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