1170159Sariff/*- 2170159Sariff * Copyright (c) 2007 Ariff Abdullah <ariff@FreeBSD.org> 3170159Sariff * All rights reserved. 4170159Sariff * 5170159Sariff * Redistribution and use in source and binary forms, with or without 6170159Sariff * modification, are permitted provided that the following conditions 7170159Sariff * are met: 8170159Sariff * 1. Redistributions of source code must retain the above copyright 9170159Sariff * notice, this list of conditions and the following disclaimer. 10170159Sariff * 2. Redistributions in binary form must reproduce the above copyright 11170159Sariff * notice, this list of conditions and the following disclaimer in the 12170159Sariff * documentation and/or other materials provided with the distribution. 13170159Sariff * 14170159Sariff * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15170159Sariff * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16170159Sariff * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17170159Sariff * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18170159Sariff * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19170159Sariff * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20170159Sariff * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21170159Sariff * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22170159Sariff * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23170159Sariff * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24170159Sariff * SUCH DAMAGE. 25170159Sariff * 26170159Sariff * $FreeBSD$ 27170159Sariff */ 28170159Sariff 29170159Sariff#include <sys/param.h> 30170159Sariff#include <sys/systm.h> 31170159Sariff#include <sys/conf.h> 32170159Sariff#include <sys/kernel.h> 33170159Sariff#include <sys/malloc.h> 34170159Sariff#include <sys/proc.h> 35170159Sariff 36193640Sariff#ifdef HAVE_KERNEL_OPTION_HEADERS 37193640Sariff#include "opt_snd.h" 38193640Sariff#endif 39193640Sariff 40170159Sariff#if defined(SND_DIAGNOSTIC) || defined(SND_DEBUG) 41170159Sariff#include <dev/sound/pcm/sound.h> 42170159Sariff#endif 43170159Sariff 44170159Sariff#include <dev/sound/clone.h> 45170159Sariff 46170159Sariff/* 47170159Sariff * So here we go again, another clonedevs manager. Unlike default clonedevs, 48170159Sariff * this clone manager is designed to withstand various abusive behavior 49170159Sariff * (such as 'while : ; do ls /dev/whatever ; done', etc.), reusable object 50170159Sariff * after reaching certain expiration threshold, aggressive garbage collector, 51170159Sariff * transparent device allocator and concurrency handling across multiple 52170159Sariff * thread/proc. Due to limited information given by dev_clone EVENTHANDLER, 53170159Sariff * we don't have much clues whether the caller wants a real open() or simply 54170159Sariff * making fun of us with things like stat(), mtime() etc. Assuming that: 55170159Sariff * 1) Time window between dev_clone EH <-> real open() should be small 56170159Sariff * enough and 2) mtime()/stat() etc. always looks like a half way / stalled 57170159Sariff * operation, we can decide whether a new cdev must be created, old 58170159Sariff * (expired) cdev can be reused or an existing cdev can be shared. 59170159Sariff * 60170159Sariff * Most of the operations and logics are generic enough and can be applied 61170159Sariff * on other places (such as if_tap, snp, etc). Perhaps this can be 62170159Sariff * rearranged to complement clone_*(). However, due to this still being 63170159Sariff * specific to the sound driver (and as a proof of concept on how it can be 64170159Sariff * done), si_drv2 is used to keep the pointer of the clone list entry to 65170159Sariff * avoid expensive lookup. 66170159Sariff */ 67170159Sariff 68170159Sariff/* clone entry */ 69170159Sariffstruct snd_clone_entry { 70170159Sariff TAILQ_ENTRY(snd_clone_entry) link; 71170159Sariff struct snd_clone *parent; 72170159Sariff struct cdev *devt; 73170159Sariff struct timespec tsp; 74170159Sariff uint32_t flags; 75170159Sariff pid_t pid; 76170159Sariff int unit; 77170159Sariff}; 78170159Sariff 79170159Sariff/* clone manager */ 80170159Sariffstruct snd_clone { 81170159Sariff TAILQ_HEAD(link_head, snd_clone_entry) head; 82170159Sariff struct timespec tsp; 83170159Sariff int refcount; 84170159Sariff int size; 85170159Sariff int typemask; 86170159Sariff int maxunit; 87170159Sariff int deadline; 88170159Sariff uint32_t flags; 89170159Sariff}; 90170159Sariff 91170159Sariff#ifdef SND_DIAGNOSTIC 92170159Sariff#define SND_CLONE_ASSERT(x, y) do { \ 93170159Sariff if (!(x)) \ 94170159Sariff panic y; \ 95193640Sariff} while (0) 96170159Sariff#else 97193640Sariff#define SND_CLONE_ASSERT(...) KASSERT(__VA_ARGS__) 98170159Sariff#endif 99170159Sariff 100170159Sariff/* 101170159Sariff * Shamelessly ripped off from vfs_subr.c 102170159Sariff * We need at least 1/HZ precision as default timestamping. 103170159Sariff */ 104170159Sariffenum { SND_TSP_SEC, SND_TSP_HZ, SND_TSP_USEC, SND_TSP_NSEC }; 105170159Sariff 106170159Sariffstatic int snd_timestamp_precision = SND_TSP_HZ; 107170159SariffTUNABLE_INT("hw.snd.timestamp_precision", &snd_timestamp_precision); 108170159Sariff 109170159Sariffvoid 110170159Sariffsnd_timestamp(struct timespec *tsp) 111170159Sariff{ 112170159Sariff struct timeval tv; 113170159Sariff 114170159Sariff switch (snd_timestamp_precision) { 115170159Sariff case SND_TSP_SEC: 116170159Sariff tsp->tv_sec = time_second; 117170159Sariff tsp->tv_nsec = 0; 118170159Sariff break; 119170159Sariff case SND_TSP_HZ: 120170159Sariff getnanouptime(tsp); 121170159Sariff break; 122170159Sariff case SND_TSP_USEC: 123170159Sariff microuptime(&tv); 124170159Sariff TIMEVAL_TO_TIMESPEC(&tv, tsp); 125170159Sariff break; 126170159Sariff case SND_TSP_NSEC: 127170159Sariff nanouptime(tsp); 128170159Sariff break; 129170159Sariff default: 130170159Sariff snd_timestamp_precision = SND_TSP_HZ; 131170159Sariff getnanouptime(tsp); 132170159Sariff break; 133170159Sariff } 134170159Sariff} 135170159Sariff 136170159Sariff#if defined(SND_DIAGNOSTIC) || defined(SND_DEBUG) 137170159Sariffstatic int 138170159Sariffsysctl_hw_snd_timestamp_precision(SYSCTL_HANDLER_ARGS) 139170159Sariff{ 140170159Sariff int err, val; 141170159Sariff 142170159Sariff val = snd_timestamp_precision; 143170289Sdwmalone err = sysctl_handle_int(oidp, &val, 0, req); 144170159Sariff if (err == 0 && req->newptr != NULL) { 145170159Sariff switch (val) { 146170159Sariff case SND_TSP_SEC: 147170159Sariff case SND_TSP_HZ: 148170159Sariff case SND_TSP_USEC: 149170159Sariff case SND_TSP_NSEC: 150170159Sariff snd_timestamp_precision = val; 151170159Sariff break; 152170159Sariff default: 153170159Sariff break; 154170159Sariff } 155170159Sariff } 156170159Sariff 157170159Sariff return (err); 158170159Sariff} 159170159SariffSYSCTL_PROC(_hw_snd, OID_AUTO, timestamp_precision, CTLTYPE_INT | CTLFLAG_RW, 160170159Sariff 0, sizeof(int), sysctl_hw_snd_timestamp_precision, "I", 161170159Sariff "timestamp precision (0=s 1=hz 2=us 3=ns)"); 162170159Sariff#endif 163170159Sariff 164170159Sariff/* 165170719Sariff * snd_clone_create() : Return opaque allocated clone manager. 166170159Sariff */ 167170159Sariffstruct snd_clone * 168170719Sariffsnd_clone_create(int typemask, int maxunit, int deadline, uint32_t flags) 169170159Sariff{ 170170159Sariff struct snd_clone *c; 171170159Sariff 172170159Sariff SND_CLONE_ASSERT(!(typemask & ~SND_CLONE_MAXUNIT), 173170159Sariff ("invalid typemask: 0x%08x", typemask)); 174170159Sariff SND_CLONE_ASSERT(maxunit == -1 || 175170159Sariff !(maxunit & ~(~typemask & SND_CLONE_MAXUNIT)), 176170159Sariff ("maxunit overflow: typemask=0x%08x maxunit=%d", 177170159Sariff typemask, maxunit)); 178170159Sariff SND_CLONE_ASSERT(!(flags & ~SND_CLONE_MASK), 179170159Sariff ("invalid clone flags=0x%08x", flags)); 180170159Sariff 181170159Sariff c = malloc(sizeof(*c), M_DEVBUF, M_WAITOK | M_ZERO); 182170159Sariff c->refcount = 0; 183170159Sariff c->size = 0; 184170159Sariff c->typemask = typemask; 185170159Sariff c->maxunit = (maxunit == -1) ? (~typemask & SND_CLONE_MAXUNIT) : 186170159Sariff maxunit; 187170159Sariff c->deadline = deadline; 188170159Sariff c->flags = flags; 189170159Sariff snd_timestamp(&c->tsp); 190170159Sariff TAILQ_INIT(&c->head); 191170159Sariff 192170159Sariff return (c); 193170159Sariff} 194170159Sariff 195170159Sariffint 196170159Sariffsnd_clone_busy(struct snd_clone *c) 197170159Sariff{ 198170159Sariff struct snd_clone_entry *ce; 199170159Sariff 200170159Sariff SND_CLONE_ASSERT(c != NULL, ("NULL snd_clone")); 201170159Sariff 202170159Sariff if (c->size == 0) 203170159Sariff return (0); 204170159Sariff 205170159Sariff TAILQ_FOREACH(ce, &c->head, link) { 206170159Sariff if ((ce->flags & SND_CLONE_BUSY) || 207170159Sariff (ce->devt != NULL && ce->devt->si_threadcount != 0)) 208170159Sariff return (EBUSY); 209170159Sariff } 210170159Sariff 211170159Sariff return (0); 212170159Sariff} 213170159Sariff 214170159Sariff/* 215170159Sariff * snd_clone_enable()/disable() : Suspend/resume clone allocation through 216170159Sariff * snd_clone_alloc(). Everything else will not be affected by this. 217170159Sariff */ 218170159Sariffint 219170159Sariffsnd_clone_enable(struct snd_clone *c) 220170159Sariff{ 221170159Sariff SND_CLONE_ASSERT(c != NULL, ("NULL snd_clone")); 222170159Sariff 223170159Sariff if (c->flags & SND_CLONE_ENABLE) 224170159Sariff return (EINVAL); 225170159Sariff 226170159Sariff c->flags |= SND_CLONE_ENABLE; 227170159Sariff 228170159Sariff return (0); 229170159Sariff} 230170159Sariff 231170159Sariffint 232170159Sariffsnd_clone_disable(struct snd_clone *c) 233170159Sariff{ 234170159Sariff SND_CLONE_ASSERT(c != NULL, ("NULL snd_clone")); 235170159Sariff 236170159Sariff if (!(c->flags & SND_CLONE_ENABLE)) 237170159Sariff return (EINVAL); 238170159Sariff 239170159Sariff c->flags &= ~SND_CLONE_ENABLE; 240170159Sariff 241170159Sariff return (0); 242170159Sariff} 243170159Sariff 244170159Sariff/* 245170159Sariff * Getters / Setters. Not worth explaining :) 246170159Sariff */ 247170159Sariffint 248170159Sariffsnd_clone_getsize(struct snd_clone *c) 249170159Sariff{ 250170159Sariff SND_CLONE_ASSERT(c != NULL, ("NULL snd_clone")); 251170159Sariff 252170159Sariff return (c->size); 253170159Sariff} 254170159Sariff 255170159Sariffint 256170159Sariffsnd_clone_getmaxunit(struct snd_clone *c) 257170159Sariff{ 258170159Sariff SND_CLONE_ASSERT(c != NULL, ("NULL snd_clone")); 259170159Sariff 260170159Sariff return (c->maxunit); 261170159Sariff} 262170159Sariff 263170159Sariffint 264170159Sariffsnd_clone_setmaxunit(struct snd_clone *c, int maxunit) 265170159Sariff{ 266170159Sariff SND_CLONE_ASSERT(c != NULL, ("NULL snd_clone")); 267170159Sariff SND_CLONE_ASSERT(maxunit == -1 || 268170159Sariff !(maxunit & ~(~c->typemask & SND_CLONE_MAXUNIT)), 269170159Sariff ("maxunit overflow: typemask=0x%08x maxunit=%d", 270170159Sariff c->typemask, maxunit)); 271170159Sariff 272170159Sariff c->maxunit = (maxunit == -1) ? (~c->typemask & SND_CLONE_MAXUNIT) : 273170159Sariff maxunit; 274170159Sariff 275170159Sariff return (c->maxunit); 276170159Sariff} 277170159Sariff 278170159Sariffint 279170159Sariffsnd_clone_getdeadline(struct snd_clone *c) 280170159Sariff{ 281170159Sariff SND_CLONE_ASSERT(c != NULL, ("NULL snd_clone")); 282170159Sariff 283170159Sariff return (c->deadline); 284170159Sariff} 285170159Sariff 286170159Sariffint 287170159Sariffsnd_clone_setdeadline(struct snd_clone *c, int deadline) 288170159Sariff{ 289170159Sariff SND_CLONE_ASSERT(c != NULL, ("NULL snd_clone")); 290170159Sariff 291170159Sariff c->deadline = deadline; 292170159Sariff 293170159Sariff return (c->deadline); 294170159Sariff} 295170159Sariff 296170159Sariffint 297170159Sariffsnd_clone_gettime(struct snd_clone *c, struct timespec *tsp) 298170159Sariff{ 299170159Sariff SND_CLONE_ASSERT(c != NULL, ("NULL snd_clone")); 300170159Sariff SND_CLONE_ASSERT(tsp != NULL, ("NULL timespec")); 301170159Sariff 302170159Sariff *tsp = c->tsp; 303170159Sariff 304170159Sariff return (0); 305170159Sariff} 306170159Sariff 307170159Sariffuint32_t 308170159Sariffsnd_clone_getflags(struct snd_clone *c) 309170159Sariff{ 310170159Sariff SND_CLONE_ASSERT(c != NULL, ("NULL snd_clone")); 311170159Sariff 312170159Sariff return (c->flags); 313170159Sariff} 314170159Sariff 315170159Sariffuint32_t 316170159Sariffsnd_clone_setflags(struct snd_clone *c, uint32_t flags) 317170159Sariff{ 318170159Sariff SND_CLONE_ASSERT(c != NULL, ("NULL snd_clone")); 319170159Sariff SND_CLONE_ASSERT(!(flags & ~SND_CLONE_MASK), 320170159Sariff ("invalid clone flags=0x%08x", flags)); 321170159Sariff 322170159Sariff c->flags = flags; 323170159Sariff 324170159Sariff return (c->flags); 325170159Sariff} 326170159Sariff 327170159Sariffint 328170159Sariffsnd_clone_getdevtime(struct cdev *dev, struct timespec *tsp) 329170159Sariff{ 330170159Sariff struct snd_clone_entry *ce; 331170159Sariff 332170159Sariff SND_CLONE_ASSERT(dev != NULL, ("NULL dev")); 333170159Sariff SND_CLONE_ASSERT(tsp != NULL, ("NULL timespec")); 334170159Sariff 335170159Sariff ce = dev->si_drv2; 336170159Sariff if (ce == NULL) 337170159Sariff return (ENODEV); 338170159Sariff 339170159Sariff SND_CLONE_ASSERT(ce->parent != NULL, ("NULL parent")); 340170159Sariff 341170159Sariff *tsp = ce->tsp; 342170159Sariff 343170159Sariff return (0); 344170159Sariff} 345170159Sariff 346170159Sariffuint32_t 347170159Sariffsnd_clone_getdevflags(struct cdev *dev) 348170159Sariff{ 349170159Sariff struct snd_clone_entry *ce; 350170159Sariff 351170159Sariff SND_CLONE_ASSERT(dev != NULL, ("NULL dev")); 352170159Sariff 353170159Sariff ce = dev->si_drv2; 354170159Sariff if (ce == NULL) 355170159Sariff return (0xffffffff); 356170159Sariff 357170159Sariff SND_CLONE_ASSERT(ce->parent != NULL, ("NULL parent")); 358170159Sariff 359170159Sariff return (ce->flags); 360170159Sariff} 361170159Sariff 362170159Sariffuint32_t 363170159Sariffsnd_clone_setdevflags(struct cdev *dev, uint32_t flags) 364170159Sariff{ 365170159Sariff struct snd_clone_entry *ce; 366170159Sariff 367170159Sariff SND_CLONE_ASSERT(dev != NULL, ("NULL dev")); 368170159Sariff SND_CLONE_ASSERT(!(flags & ~SND_CLONE_DEVMASK), 369170159Sariff ("invalid clone dev flags=0x%08x", flags)); 370170159Sariff 371170159Sariff ce = dev->si_drv2; 372170159Sariff if (ce == NULL) 373170159Sariff return (0xffffffff); 374170159Sariff 375170159Sariff SND_CLONE_ASSERT(ce->parent != NULL, ("NULL parent")); 376170159Sariff 377170159Sariff ce->flags = flags; 378170159Sariff 379170159Sariff return (ce->flags); 380170159Sariff} 381170159Sariff 382170159Sariff/* Elapsed time conversion to ms */ 383170159Sariff#define SND_CLONE_ELAPSED(x, y) \ 384170159Sariff ((((x)->tv_sec - (y)->tv_sec) * 1000) + \ 385170159Sariff (((y)->tv_nsec > (x)->tv_nsec) ? \ 386170159Sariff (((1000000000L + (x)->tv_nsec - \ 387170159Sariff (y)->tv_nsec) / 1000000) - 1000) : \ 388170159Sariff (((x)->tv_nsec - (y)->tv_nsec) / 1000000))) 389170159Sariff 390170159Sariff#define SND_CLONE_EXPIRED(x, y, z) \ 391170159Sariff ((x)->deadline < 1 || \ 392170159Sariff ((y)->tv_sec - (z)->tv_sec) > ((x)->deadline / 1000) || \ 393170159Sariff SND_CLONE_ELAPSED(y, z) > (x)->deadline) 394170159Sariff 395170159Sariff/* 396170159Sariff * snd_clone_gc() : Garbage collector for stalled, expired objects. Refer to 397170159Sariff * clone.h for explanations on GC settings. 398170159Sariff */ 399170159Sariffint 400170159Sariffsnd_clone_gc(struct snd_clone *c) 401170159Sariff{ 402170159Sariff struct snd_clone_entry *ce, *tce; 403170159Sariff struct timespec now; 404170159Sariff int pruned; 405170159Sariff 406170159Sariff SND_CLONE_ASSERT(c != NULL, ("NULL snd_clone")); 407170159Sariff 408170159Sariff if (!(c->flags & SND_CLONE_GC_ENABLE) || c->size == 0) 409170159Sariff return (0); 410170159Sariff 411170159Sariff snd_timestamp(&now); 412170159Sariff 413170159Sariff /* 414170159Sariff * Bail out if the last clone handler was invoked below the deadline 415170159Sariff * threshold. 416170159Sariff */ 417170159Sariff if ((c->flags & SND_CLONE_GC_EXPIRED) && 418170159Sariff !SND_CLONE_EXPIRED(c, &now, &c->tsp)) 419170159Sariff return (0); 420170159Sariff 421170159Sariff pruned = 0; 422170159Sariff 423170159Sariff /* 424170159Sariff * Visit each object in reverse order. If the object is still being 425170159Sariff * referenced by a valid open(), skip it. Look for expired objects 426170159Sariff * and either revoke its clone invocation status or mercilessly 427170159Sariff * throw it away. 428170159Sariff */ 429170159Sariff TAILQ_FOREACH_REVERSE_SAFE(ce, &c->head, link_head, link, tce) { 430170159Sariff if (!(ce->flags & SND_CLONE_BUSY) && 431170159Sariff (!(ce->flags & SND_CLONE_INVOKE) || 432170159Sariff SND_CLONE_EXPIRED(c, &now, &ce->tsp))) { 433170159Sariff if ((c->flags & SND_CLONE_GC_REVOKE) || 434170159Sariff ce->devt->si_threadcount != 0) { 435170159Sariff ce->flags &= ~SND_CLONE_INVOKE; 436170159Sariff ce->pid = -1; 437170159Sariff } else { 438170159Sariff TAILQ_REMOVE(&c->head, ce, link); 439170159Sariff destroy_dev(ce->devt); 440170159Sariff free(ce, M_DEVBUF); 441170159Sariff c->size--; 442170159Sariff } 443170159Sariff pruned++; 444170159Sariff } 445170159Sariff } 446170159Sariff 447170159Sariff /* return total pruned objects */ 448170159Sariff return (pruned); 449170159Sariff} 450170159Sariff 451170159Sariffvoid 452170159Sariffsnd_clone_destroy(struct snd_clone *c) 453170159Sariff{ 454170719Sariff struct snd_clone_entry *ce, *tmp; 455170159Sariff 456170159Sariff SND_CLONE_ASSERT(c != NULL, ("NULL snd_clone")); 457170159Sariff 458170719Sariff ce = TAILQ_FIRST(&c->head); 459170719Sariff while (ce != NULL) { 460170719Sariff tmp = TAILQ_NEXT(ce, link); 461170159Sariff if (ce->devt != NULL) 462170159Sariff destroy_dev(ce->devt); 463170159Sariff free(ce, M_DEVBUF); 464170719Sariff ce = tmp; 465170159Sariff } 466170159Sariff 467170159Sariff free(c, M_DEVBUF); 468170159Sariff} 469170159Sariff 470170159Sariff/* 471170159Sariff * snd_clone_acquire() : The vital part of concurrency management. Must be 472170159Sariff * called somewhere at the beginning of open() handler. ENODEV is not really 473170159Sariff * fatal since it just tell the caller that this is not cloned stuff. 474170159Sariff * EBUSY is *real*, don't forget that! 475170159Sariff */ 476170159Sariffint 477170159Sariffsnd_clone_acquire(struct cdev *dev) 478170159Sariff{ 479170159Sariff struct snd_clone_entry *ce; 480170159Sariff 481170159Sariff SND_CLONE_ASSERT(dev != NULL, ("NULL dev")); 482170159Sariff 483170159Sariff ce = dev->si_drv2; 484170159Sariff if (ce == NULL) 485170159Sariff return (ENODEV); 486170159Sariff 487170159Sariff SND_CLONE_ASSERT(ce->parent != NULL, ("NULL parent")); 488170159Sariff 489170159Sariff ce->flags &= ~SND_CLONE_INVOKE; 490170159Sariff 491170159Sariff if (ce->flags & SND_CLONE_BUSY) 492170159Sariff return (EBUSY); 493170159Sariff 494170159Sariff ce->flags |= SND_CLONE_BUSY; 495170159Sariff 496170159Sariff return (0); 497170159Sariff} 498170159Sariff 499170159Sariff/* 500170159Sariff * snd_clone_release() : Release busy status. Must be called somewhere at 501170159Sariff * the end of close() handler, or somewhere after fail open(). 502170159Sariff */ 503170159Sariffint 504170159Sariffsnd_clone_release(struct cdev *dev) 505170159Sariff{ 506170159Sariff struct snd_clone_entry *ce; 507170159Sariff 508170159Sariff SND_CLONE_ASSERT(dev != NULL, ("NULL dev")); 509170159Sariff 510170159Sariff ce = dev->si_drv2; 511170159Sariff if (ce == NULL) 512170159Sariff return (ENODEV); 513170159Sariff 514170159Sariff SND_CLONE_ASSERT(ce->parent != NULL, ("NULL parent")); 515170159Sariff 516170159Sariff ce->flags &= ~SND_CLONE_INVOKE; 517170159Sariff 518170159Sariff if (!(ce->flags & SND_CLONE_BUSY)) 519170159Sariff return (EBADF); 520170159Sariff 521170159Sariff ce->flags &= ~SND_CLONE_BUSY; 522170159Sariff ce->pid = -1; 523170159Sariff 524170159Sariff return (0); 525170159Sariff} 526170159Sariff 527170159Sariff/* 528170159Sariff * snd_clone_ref/unref() : Garbage collector reference counter. To make 529170159Sariff * garbage collector run automatically, the sequence must be something like 530170159Sariff * this (both in open() and close() handlers): 531170159Sariff * 532170159Sariff * open() - 1) snd_clone_acquire() 533170159Sariff * 2) .... check check ... if failed, snd_clone_release() 534170159Sariff * 3) Success. Call snd_clone_ref() 535170159Sariff * 536170159Sariff * close() - 1) .... check check check .... 537170159Sariff * 2) Success. snd_clone_release() 538170159Sariff * 3) snd_clone_unref() . Garbage collector will run at this point 539170159Sariff * if this is the last referenced object. 540170159Sariff */ 541170159Sariffint 542170159Sariffsnd_clone_ref(struct cdev *dev) 543170159Sariff{ 544170159Sariff struct snd_clone_entry *ce; 545170159Sariff struct snd_clone *c; 546170159Sariff 547170159Sariff SND_CLONE_ASSERT(dev != NULL, ("NULL dev")); 548170159Sariff 549170159Sariff ce = dev->si_drv2; 550170159Sariff if (ce == NULL) 551170159Sariff return (0); 552170159Sariff 553170159Sariff c = ce->parent; 554170159Sariff SND_CLONE_ASSERT(c != NULL, ("NULL parent")); 555170159Sariff SND_CLONE_ASSERT(c->refcount >= 0, ("refcount < 0")); 556170159Sariff 557170159Sariff return (++c->refcount); 558170159Sariff} 559170159Sariff 560170159Sariffint 561170159Sariffsnd_clone_unref(struct cdev *dev) 562170159Sariff{ 563170159Sariff struct snd_clone_entry *ce; 564170159Sariff struct snd_clone *c; 565170159Sariff 566170159Sariff SND_CLONE_ASSERT(dev != NULL, ("NULL dev")); 567170159Sariff 568170159Sariff ce = dev->si_drv2; 569170159Sariff if (ce == NULL) 570170159Sariff return (0); 571170159Sariff 572170159Sariff c = ce->parent; 573170159Sariff SND_CLONE_ASSERT(c != NULL, ("NULL parent")); 574170159Sariff SND_CLONE_ASSERT(c->refcount > 0, ("refcount <= 0")); 575170159Sariff 576170159Sariff c->refcount--; 577170159Sariff 578170159Sariff /* 579170159Sariff * Run automatic garbage collector, if needed. 580170159Sariff */ 581170159Sariff if ((c->flags & SND_CLONE_GC_UNREF) && 582170159Sariff (!(c->flags & SND_CLONE_GC_LASTREF) || 583170159Sariff (c->refcount == 0 && (c->flags & SND_CLONE_GC_LASTREF)))) 584170159Sariff (void)snd_clone_gc(c); 585170159Sariff 586170159Sariff return (c->refcount); 587170159Sariff} 588170159Sariff 589170159Sariffvoid 590170159Sariffsnd_clone_register(struct snd_clone_entry *ce, struct cdev *dev) 591170159Sariff{ 592170159Sariff SND_CLONE_ASSERT(ce != NULL, ("NULL snd_clone_entry")); 593170159Sariff SND_CLONE_ASSERT(dev != NULL, ("NULL dev")); 594170159Sariff SND_CLONE_ASSERT(dev->si_drv2 == NULL, ("dev->si_drv2 not NULL")); 595170159Sariff SND_CLONE_ASSERT((ce->flags & SND_CLONE_ALLOC) == SND_CLONE_ALLOC, 596170159Sariff ("invalid clone alloc flags=0x%08x", ce->flags)); 597170159Sariff SND_CLONE_ASSERT(ce->devt == NULL, ("ce->devt not NULL")); 598170159Sariff SND_CLONE_ASSERT(ce->unit == dev2unit(dev), 599170159Sariff ("invalid unit ce->unit=0x%08x dev2unit=0x%08x", 600170159Sariff ce->unit, dev2unit(dev))); 601170159Sariff 602170159Sariff SND_CLONE_ASSERT(ce->parent != NULL, ("NULL parent")); 603170159Sariff 604170159Sariff dev->si_drv2 = ce; 605170159Sariff ce->devt = dev; 606170159Sariff ce->flags &= ~SND_CLONE_ALLOC; 607170159Sariff ce->flags |= SND_CLONE_INVOKE; 608170159Sariff} 609170159Sariff 610170159Sariffstruct snd_clone_entry * 611170159Sariffsnd_clone_alloc(struct snd_clone *c, struct cdev **dev, int *unit, int tmask) 612170159Sariff{ 613170159Sariff struct snd_clone_entry *ce, *after, *bce, *cce, *nce, *tce; 614170159Sariff struct timespec now; 615170159Sariff int cunit, allocunit; 616170159Sariff pid_t curpid; 617170159Sariff 618170159Sariff SND_CLONE_ASSERT(c != NULL, ("NULL snd_clone")); 619170159Sariff SND_CLONE_ASSERT(dev != NULL, ("NULL dev pointer")); 620170159Sariff SND_CLONE_ASSERT((c->typemask & tmask) == tmask, 621170159Sariff ("invalid tmask: typemask=0x%08x tmask=0x%08x", 622170159Sariff c->typemask, tmask)); 623170159Sariff SND_CLONE_ASSERT(unit != NULL, ("NULL unit pointer")); 624170159Sariff SND_CLONE_ASSERT(*unit == -1 || !(*unit & (c->typemask | tmask)), 625170159Sariff ("typemask collision: typemask=0x%08x tmask=0x%08x *unit=%d", 626170159Sariff c->typemask, tmask, *unit)); 627170159Sariff 628170159Sariff if (!(c->flags & SND_CLONE_ENABLE) || 629170159Sariff (*unit != -1 && *unit > c->maxunit)) 630170159Sariff return (NULL); 631170159Sariff 632170159Sariff ce = NULL; 633170159Sariff after = NULL; 634170159Sariff bce = NULL; /* "b"usy candidate */ 635170159Sariff cce = NULL; /* "c"urthread/proc candidate */ 636170159Sariff nce = NULL; /* "n"ull, totally unbusy candidate */ 637170159Sariff tce = NULL; /* Last "t"ry candidate */ 638170159Sariff cunit = 0; 639170159Sariff allocunit = (*unit == -1) ? 0 : *unit; 640170159Sariff curpid = curthread->td_proc->p_pid; 641170159Sariff 642170159Sariff snd_timestamp(&now); 643170159Sariff 644170159Sariff TAILQ_FOREACH(ce, &c->head, link) { 645170159Sariff /* 646170159Sariff * Sort incrementally according to device type. 647170159Sariff */ 648170159Sariff if (tmask > (ce->unit & c->typemask)) { 649170159Sariff if (cunit == 0) 650170159Sariff after = ce; 651170159Sariff continue; 652170159Sariff } else if (tmask < (ce->unit & c->typemask)) 653170159Sariff break; 654170159Sariff 655170159Sariff /* 656170159Sariff * Shoot.. this is where the grumpiness begin. Just 657170159Sariff * return immediately. 658170159Sariff */ 659170159Sariff if (*unit != -1 && *unit == (ce->unit & ~tmask)) 660170159Sariff goto snd_clone_alloc_out; 661170159Sariff 662170159Sariff cunit++; 663170159Sariff /* 664170159Sariff * Simmilar device type. Sort incrementally according 665170159Sariff * to allocation unit. While here, look for free slot 666170159Sariff * and possible collision for new / future allocation. 667170159Sariff */ 668170159Sariff if (*unit == -1 && (ce->unit & ~tmask) == allocunit) 669170159Sariff allocunit++; 670170159Sariff if ((ce->unit & ~tmask) < allocunit) 671170159Sariff after = ce; 672170159Sariff /* 673170159Sariff * Clone logic: 674170159Sariff * 1. Look for non busy, but keep track of the best 675170159Sariff * possible busy cdev. 676170159Sariff * 2. Look for the best (oldest referenced) entry that is 677170159Sariff * in a same process / thread. 678170159Sariff * 3. Look for the best (oldest referenced), absolute free 679170159Sariff * entry. 680170159Sariff * 4. Lastly, look for the best (oldest referenced) 681170159Sariff * any entries that doesn't fit with anything above. 682170159Sariff */ 683170159Sariff if (ce->flags & SND_CLONE_BUSY) { 684170159Sariff if (ce->devt != NULL && (bce == NULL || 685170159Sariff timespeccmp(&ce->tsp, &bce->tsp, <))) 686170159Sariff bce = ce; 687170159Sariff continue; 688170159Sariff } 689170159Sariff if (ce->pid == curpid && 690170159Sariff (cce == NULL || timespeccmp(&ce->tsp, &cce->tsp, <))) 691170159Sariff cce = ce; 692170159Sariff else if (!(ce->flags & SND_CLONE_INVOKE) && 693170159Sariff (nce == NULL || timespeccmp(&ce->tsp, &nce->tsp, <))) 694170159Sariff nce = ce; 695170159Sariff else if (tce == NULL || timespeccmp(&ce->tsp, &tce->tsp, <)) 696170159Sariff tce = ce; 697170159Sariff } 698170159Sariff if (*unit != -1) 699170159Sariff goto snd_clone_alloc_new; 700170159Sariff else if (cce != NULL) { 701170159Sariff /* Same proc entry found, go for it */ 702170159Sariff ce = cce; 703170159Sariff goto snd_clone_alloc_out; 704170159Sariff } else if (nce != NULL) { 705170159Sariff /* 706170159Sariff * Next, try absolute free entry. If the calculated 707170159Sariff * allocunit is smaller, create new entry instead. 708170159Sariff */ 709170159Sariff if (allocunit < (nce->unit & ~tmask)) 710170159Sariff goto snd_clone_alloc_new; 711170159Sariff ce = nce; 712170159Sariff goto snd_clone_alloc_out; 713170159Sariff } else if (allocunit > c->maxunit) { 714170159Sariff /* 715170159Sariff * Maximum allowable unit reached. Try returning any 716170159Sariff * available cdev and hope for the best. If the lookup is 717170159Sariff * done for things like stat(), mtime() etc. , things should 718170159Sariff * be ok. Otherwise, open() handler should do further checks 719170159Sariff * and decide whether to return correct error code or not. 720170159Sariff */ 721170159Sariff if (tce != NULL) { 722170159Sariff ce = tce; 723170159Sariff goto snd_clone_alloc_out; 724170159Sariff } else if (bce != NULL) { 725170159Sariff ce = bce; 726170159Sariff goto snd_clone_alloc_out; 727170159Sariff } 728170159Sariff return (NULL); 729170159Sariff } 730170159Sariff 731170159Sariffsnd_clone_alloc_new: 732170159Sariff /* 733170159Sariff * No free entries found, and we still haven't reached maximum 734170159Sariff * allowable units. Allocate, setup a minimal unique entry with busy 735170719Sariff * status so nobody will monkey on this new entry. Unit magic is set 736170719Sariff * right here to avoid collision with other contesting handler. 737170719Sariff * The caller must be carefull here to maintain its own 738170719Sariff * synchronization, as long as it will not conflict with malloc(9) 739170719Sariff * operations. 740170719Sariff * 741170719Sariff * That said, go figure. 742170159Sariff */ 743170719Sariff ce = malloc(sizeof(*ce), M_DEVBUF, 744170719Sariff ((c->flags & SND_CLONE_WAITOK) ? M_WAITOK : M_NOWAIT) | M_ZERO); 745170159Sariff if (ce == NULL) { 746170159Sariff if (*unit != -1) 747170159Sariff return (NULL); 748170159Sariff /* 749170159Sariff * We're being dense, ignorance is bliss, 750170159Sariff * Super Regulatory Measure (TM).. TRY AGAIN! 751170159Sariff */ 752170159Sariff if (nce != NULL) { 753170159Sariff ce = nce; 754170159Sariff goto snd_clone_alloc_out; 755170159Sariff } else if (tce != NULL) { 756170159Sariff ce = tce; 757170159Sariff goto snd_clone_alloc_out; 758170159Sariff } else if (bce != NULL) { 759170159Sariff ce = bce; 760170159Sariff goto snd_clone_alloc_out; 761170159Sariff } 762170159Sariff return (NULL); 763170159Sariff } 764170159Sariff /* Setup new entry */ 765170159Sariff ce->parent = c; 766170159Sariff ce->unit = tmask | allocunit; 767170159Sariff ce->pid = curpid; 768170159Sariff ce->tsp = now; 769170159Sariff ce->flags |= SND_CLONE_ALLOC; 770170159Sariff if (after != NULL) { 771170159Sariff TAILQ_INSERT_AFTER(&c->head, after, ce, link); 772170159Sariff } else { 773170159Sariff TAILQ_INSERT_HEAD(&c->head, ce, link); 774170159Sariff } 775170159Sariff c->size++; 776170159Sariff c->tsp = now; 777170159Sariff /* 778170159Sariff * Save new allocation unit for caller which will be used 779170159Sariff * by make_dev(). 780170159Sariff */ 781170159Sariff *unit = allocunit; 782170159Sariff 783170159Sariff return (ce); 784170159Sariff 785170159Sariffsnd_clone_alloc_out: 786170159Sariff /* 787170159Sariff * Set, mark, timestamp the entry if this is a truly free entry. 788170159Sariff * Leave busy entry alone. 789170159Sariff */ 790170159Sariff if (!(ce->flags & SND_CLONE_BUSY)) { 791170159Sariff ce->pid = curpid; 792170159Sariff ce->tsp = now; 793170159Sariff ce->flags |= SND_CLONE_INVOKE; 794170159Sariff } 795170159Sariff c->tsp = now; 796170159Sariff *dev = ce->devt; 797170159Sariff 798170159Sariff return (NULL); 799170159Sariff} 800