2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
4 * Copyright (c) 2007 Ariff Abdullah <ariff@FreeBSD.org>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 #include <sys/param.h>
32 #include <sys/systm.h>
34 #include <sys/kernel.h>
35 #include <sys/malloc.h>
38 #ifdef HAVE_KERNEL_OPTION_HEADERS
42 #if defined(SND_DIAGNOSTIC) || defined(SND_DEBUG)
43 #include <dev/sound/pcm/sound.h>
46 #include <dev/sound/clone.h>
49 * So here we go again, another clonedevs manager. Unlike default clonedevs,
50 * this clone manager is designed to withstand various abusive behavior
51 * (such as 'while : ; do ls /dev/whatever ; done', etc.), reusable object
52 * after reaching certain expiration threshold, aggressive garbage collector,
53 * transparent device allocator and concurrency handling across multiple
54 * thread/proc. Due to limited information given by dev_clone EVENTHANDLER,
55 * we don't have much clues whether the caller wants a real open() or simply
56 * making fun of us with things like stat(), mtime() etc. Assuming that:
57 * 1) Time window between dev_clone EH <-> real open() should be small
58 * enough and 2) mtime()/stat() etc. always looks like a half way / stalled
59 * operation, we can decide whether a new cdev must be created, old
60 * (expired) cdev can be reused or an existing cdev can be shared.
62 * Most of the operations and logics are generic enough and can be applied
63 * on other places (such as if_tap, snp, etc). Perhaps this can be
64 * rearranged to complement clone_*(). However, due to this still being
65 * specific to the sound driver (and as a proof of concept on how it can be
66 * done), si_drv2 is used to keep the pointer of the clone list entry to
67 * avoid expensive lookup.
71 struct snd_clone_entry {
72 TAILQ_ENTRY(snd_clone_entry) link;
73 struct snd_clone *parent;
83 TAILQ_HEAD(link_head, snd_clone_entry) head;
94 #define SND_CLONE_ASSERT(x, y) do { \
99 #define SND_CLONE_ASSERT(...) KASSERT(__VA_ARGS__)
103 * Shamelessly ripped off from vfs_subr.c
104 * We need at least 1/HZ precision as default timestamping.
106 enum { SND_TSP_SEC, SND_TSP_HZ, SND_TSP_USEC, SND_TSP_NSEC };
108 static int snd_timestamp_precision = SND_TSP_HZ;
109 TUNABLE_INT("hw.snd.timestamp_precision", &snd_timestamp_precision);
112 snd_timestamp(struct timespec *tsp)
116 switch (snd_timestamp_precision) {
118 tsp->tv_sec = time_second;
126 TIMEVAL_TO_TIMESPEC(&tv, tsp);
132 snd_timestamp_precision = SND_TSP_HZ;
138 #if defined(SND_DIAGNOSTIC) || defined(SND_DEBUG)
140 sysctl_hw_snd_timestamp_precision(SYSCTL_HANDLER_ARGS)
144 val = snd_timestamp_precision;
145 err = sysctl_handle_int(oidp, &val, 0, req);
146 if (err == 0 && req->newptr != NULL) {
152 snd_timestamp_precision = val;
161 SYSCTL_PROC(_hw_snd, OID_AUTO, timestamp_precision,
162 CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT, 0, sizeof(int),
163 sysctl_hw_snd_timestamp_precision, "I",
164 "timestamp precision (0=s 1=hz 2=us 3=ns)");
168 * snd_clone_create() : Return opaque allocated clone manager.
171 snd_clone_create(int typemask, int maxunit, int deadline, uint32_t flags)
175 SND_CLONE_ASSERT(!(typemask & ~SND_CLONE_MAXUNIT),
176 ("invalid typemask: 0x%08x", typemask));
177 SND_CLONE_ASSERT(maxunit == -1 ||
178 !(maxunit & ~(~typemask & SND_CLONE_MAXUNIT)),
179 ("maxunit overflow: typemask=0x%08x maxunit=%d",
181 SND_CLONE_ASSERT(!(flags & ~SND_CLONE_MASK),
182 ("invalid clone flags=0x%08x", flags));
184 c = malloc(sizeof(*c), M_DEVBUF, M_WAITOK | M_ZERO);
187 c->typemask = typemask;
188 c->maxunit = (maxunit == -1) ? (~typemask & SND_CLONE_MAXUNIT) :
190 c->deadline = deadline;
192 snd_timestamp(&c->tsp);
193 TAILQ_INIT(&c->head);
199 snd_clone_busy(struct snd_clone *c)
201 struct snd_clone_entry *ce;
203 SND_CLONE_ASSERT(c != NULL, ("NULL snd_clone"));
208 TAILQ_FOREACH(ce, &c->head, link) {
209 if ((ce->flags & SND_CLONE_BUSY) ||
210 (ce->devt != NULL && ce->devt->si_threadcount != 0))
218 * snd_clone_enable()/disable() : Suspend/resume clone allocation through
219 * snd_clone_alloc(). Everything else will not be affected by this.
222 snd_clone_enable(struct snd_clone *c)
224 SND_CLONE_ASSERT(c != NULL, ("NULL snd_clone"));
226 if (c->flags & SND_CLONE_ENABLE)
229 c->flags |= SND_CLONE_ENABLE;
235 snd_clone_disable(struct snd_clone *c)
237 SND_CLONE_ASSERT(c != NULL, ("NULL snd_clone"));
239 if (!(c->flags & SND_CLONE_ENABLE))
242 c->flags &= ~SND_CLONE_ENABLE;
248 * Getters / Setters. Not worth explaining :)
251 snd_clone_getsize(struct snd_clone *c)
253 SND_CLONE_ASSERT(c != NULL, ("NULL snd_clone"));
259 snd_clone_getmaxunit(struct snd_clone *c)
261 SND_CLONE_ASSERT(c != NULL, ("NULL snd_clone"));
267 snd_clone_setmaxunit(struct snd_clone *c, int maxunit)
269 SND_CLONE_ASSERT(c != NULL, ("NULL snd_clone"));
270 SND_CLONE_ASSERT(maxunit == -1 ||
271 !(maxunit & ~(~c->typemask & SND_CLONE_MAXUNIT)),
272 ("maxunit overflow: typemask=0x%08x maxunit=%d",
273 c->typemask, maxunit));
275 c->maxunit = (maxunit == -1) ? (~c->typemask & SND_CLONE_MAXUNIT) :
282 snd_clone_getdeadline(struct snd_clone *c)
284 SND_CLONE_ASSERT(c != NULL, ("NULL snd_clone"));
286 return (c->deadline);
290 snd_clone_setdeadline(struct snd_clone *c, int deadline)
292 SND_CLONE_ASSERT(c != NULL, ("NULL snd_clone"));
294 c->deadline = deadline;
296 return (c->deadline);
300 snd_clone_gettime(struct snd_clone *c, struct timespec *tsp)
302 SND_CLONE_ASSERT(c != NULL, ("NULL snd_clone"));
303 SND_CLONE_ASSERT(tsp != NULL, ("NULL timespec"));
311 snd_clone_getflags(struct snd_clone *c)
313 SND_CLONE_ASSERT(c != NULL, ("NULL snd_clone"));
319 snd_clone_setflags(struct snd_clone *c, uint32_t flags)
321 SND_CLONE_ASSERT(c != NULL, ("NULL snd_clone"));
322 SND_CLONE_ASSERT(!(flags & ~SND_CLONE_MASK),
323 ("invalid clone flags=0x%08x", flags));
331 snd_clone_getdevtime(struct cdev *dev, struct timespec *tsp)
333 struct snd_clone_entry *ce;
335 SND_CLONE_ASSERT(dev != NULL, ("NULL dev"));
336 SND_CLONE_ASSERT(tsp != NULL, ("NULL timespec"));
342 SND_CLONE_ASSERT(ce->parent != NULL, ("NULL parent"));
350 snd_clone_getdevflags(struct cdev *dev)
352 struct snd_clone_entry *ce;
354 SND_CLONE_ASSERT(dev != NULL, ("NULL dev"));
360 SND_CLONE_ASSERT(ce->parent != NULL, ("NULL parent"));
366 snd_clone_setdevflags(struct cdev *dev, uint32_t flags)
368 struct snd_clone_entry *ce;
370 SND_CLONE_ASSERT(dev != NULL, ("NULL dev"));
371 SND_CLONE_ASSERT(!(flags & ~SND_CLONE_DEVMASK),
372 ("invalid clone dev flags=0x%08x", flags));
378 SND_CLONE_ASSERT(ce->parent != NULL, ("NULL parent"));
385 /* Elapsed time conversion to ms */
386 #define SND_CLONE_ELAPSED(x, y) \
387 ((((x)->tv_sec - (y)->tv_sec) * 1000) + \
388 (((y)->tv_nsec > (x)->tv_nsec) ? \
389 (((1000000000L + (x)->tv_nsec - \
390 (y)->tv_nsec) / 1000000) - 1000) : \
391 (((x)->tv_nsec - (y)->tv_nsec) / 1000000)))
393 #define SND_CLONE_EXPIRED(x, y, z) \
394 ((x)->deadline < 1 || \
395 ((y)->tv_sec - (z)->tv_sec) > ((x)->deadline / 1000) || \
396 SND_CLONE_ELAPSED(y, z) > (x)->deadline)
399 * snd_clone_gc() : Garbage collector for stalled, expired objects. Refer to
400 * clone.h for explanations on GC settings.
403 snd_clone_gc(struct snd_clone *c)
405 struct snd_clone_entry *ce, *tce;
409 SND_CLONE_ASSERT(c != NULL, ("NULL snd_clone"));
411 if (!(c->flags & SND_CLONE_GC_ENABLE) || c->size == 0)
417 * Bail out if the last clone handler was invoked below the deadline
420 if ((c->flags & SND_CLONE_GC_EXPIRED) &&
421 !SND_CLONE_EXPIRED(c, &now, &c->tsp))
427 * Visit each object in reverse order. If the object is still being
428 * referenced by a valid open(), skip it. Look for expired objects
429 * and either revoke its clone invocation status or mercilessly
432 TAILQ_FOREACH_REVERSE_SAFE(ce, &c->head, link_head, link, tce) {
433 if (!(ce->flags & SND_CLONE_BUSY) &&
434 (!(ce->flags & SND_CLONE_INVOKE) ||
435 SND_CLONE_EXPIRED(c, &now, &ce->tsp))) {
436 if ((c->flags & SND_CLONE_GC_REVOKE) ||
437 ce->devt->si_threadcount != 0) {
438 ce->flags &= ~SND_CLONE_INVOKE;
441 TAILQ_REMOVE(&c->head, ce, link);
442 destroy_dev(ce->devt);
450 /* return total pruned objects */
455 snd_clone_destroy(struct snd_clone *c)
457 struct snd_clone_entry *ce, *tmp;
459 SND_CLONE_ASSERT(c != NULL, ("NULL snd_clone"));
461 ce = TAILQ_FIRST(&c->head);
463 tmp = TAILQ_NEXT(ce, link);
464 if (ce->devt != NULL)
465 destroy_dev(ce->devt);
474 * snd_clone_acquire() : The vital part of concurrency management. Must be
475 * called somewhere at the beginning of open() handler. ENODEV is not really
476 * fatal since it just tell the caller that this is not cloned stuff.
477 * EBUSY is *real*, don't forget that!
480 snd_clone_acquire(struct cdev *dev)
482 struct snd_clone_entry *ce;
484 SND_CLONE_ASSERT(dev != NULL, ("NULL dev"));
490 SND_CLONE_ASSERT(ce->parent != NULL, ("NULL parent"));
492 ce->flags &= ~SND_CLONE_INVOKE;
494 if (ce->flags & SND_CLONE_BUSY)
497 ce->flags |= SND_CLONE_BUSY;
503 * snd_clone_release() : Release busy status. Must be called somewhere at
504 * the end of close() handler, or somewhere after fail open().
507 snd_clone_release(struct cdev *dev)
509 struct snd_clone_entry *ce;
511 SND_CLONE_ASSERT(dev != NULL, ("NULL dev"));
517 SND_CLONE_ASSERT(ce->parent != NULL, ("NULL parent"));
519 ce->flags &= ~SND_CLONE_INVOKE;
521 if (!(ce->flags & SND_CLONE_BUSY))
524 ce->flags &= ~SND_CLONE_BUSY;
531 * snd_clone_ref/unref() : Garbage collector reference counter. To make
532 * garbage collector run automatically, the sequence must be something like
533 * this (both in open() and close() handlers):
535 * open() - 1) snd_clone_acquire()
536 * 2) .... check check ... if failed, snd_clone_release()
537 * 3) Success. Call snd_clone_ref()
539 * close() - 1) .... check check check ....
540 * 2) Success. snd_clone_release()
541 * 3) snd_clone_unref() . Garbage collector will run at this point
542 * if this is the last referenced object.
545 snd_clone_ref(struct cdev *dev)
547 struct snd_clone_entry *ce;
550 SND_CLONE_ASSERT(dev != NULL, ("NULL dev"));
557 SND_CLONE_ASSERT(c != NULL, ("NULL parent"));
558 SND_CLONE_ASSERT(c->refcount >= 0, ("refcount < 0"));
560 return (++c->refcount);
564 snd_clone_unref(struct cdev *dev)
566 struct snd_clone_entry *ce;
569 SND_CLONE_ASSERT(dev != NULL, ("NULL dev"));
576 SND_CLONE_ASSERT(c != NULL, ("NULL parent"));
577 SND_CLONE_ASSERT(c->refcount > 0, ("refcount <= 0"));
582 * Run automatic garbage collector, if needed.
584 if ((c->flags & SND_CLONE_GC_UNREF) &&
585 (!(c->flags & SND_CLONE_GC_LASTREF) ||
586 (c->refcount == 0 && (c->flags & SND_CLONE_GC_LASTREF))))
587 (void)snd_clone_gc(c);
589 return (c->refcount);
593 snd_clone_register(struct snd_clone_entry *ce, struct cdev *dev)
595 SND_CLONE_ASSERT(ce != NULL, ("NULL snd_clone_entry"));
596 SND_CLONE_ASSERT(dev != NULL, ("NULL dev"));
597 SND_CLONE_ASSERT(dev->si_drv2 == NULL, ("dev->si_drv2 not NULL"));
598 SND_CLONE_ASSERT((ce->flags & SND_CLONE_ALLOC) == SND_CLONE_ALLOC,
599 ("invalid clone alloc flags=0x%08x", ce->flags));
600 SND_CLONE_ASSERT(ce->devt == NULL, ("ce->devt not NULL"));
601 SND_CLONE_ASSERT(ce->unit == dev2unit(dev),
602 ("invalid unit ce->unit=0x%08x dev2unit=0x%08x",
603 ce->unit, dev2unit(dev)));
605 SND_CLONE_ASSERT(ce->parent != NULL, ("NULL parent"));
609 ce->flags &= ~SND_CLONE_ALLOC;
610 ce->flags |= SND_CLONE_INVOKE;
613 struct snd_clone_entry *
614 snd_clone_alloc(struct snd_clone *c, struct cdev **dev, int *unit, int tmask)
616 struct snd_clone_entry *ce, *after, *bce, *cce, *nce, *tce;
618 int cunit, allocunit;
621 SND_CLONE_ASSERT(c != NULL, ("NULL snd_clone"));
622 SND_CLONE_ASSERT(dev != NULL, ("NULL dev pointer"));
623 SND_CLONE_ASSERT((c->typemask & tmask) == tmask,
624 ("invalid tmask: typemask=0x%08x tmask=0x%08x",
625 c->typemask, tmask));
626 SND_CLONE_ASSERT(unit != NULL, ("NULL unit pointer"));
627 SND_CLONE_ASSERT(*unit == -1 || !(*unit & (c->typemask | tmask)),
628 ("typemask collision: typemask=0x%08x tmask=0x%08x *unit=%d",
629 c->typemask, tmask, *unit));
631 if (!(c->flags & SND_CLONE_ENABLE) ||
632 (*unit != -1 && *unit > c->maxunit))
637 bce = NULL; /* "b"usy candidate */
638 cce = NULL; /* "c"urthread/proc candidate */
639 nce = NULL; /* "n"ull, totally unbusy candidate */
640 tce = NULL; /* Last "t"ry candidate */
642 allocunit = (*unit == -1) ? 0 : *unit;
643 curpid = curthread->td_proc->p_pid;
647 TAILQ_FOREACH(ce, &c->head, link) {
649 * Sort incrementally according to device type.
651 if (tmask > (ce->unit & c->typemask)) {
655 } else if (tmask < (ce->unit & c->typemask))
659 * Shoot.. this is where the grumpiness begin. Just
660 * return immediately.
662 if (*unit != -1 && *unit == (ce->unit & ~tmask))
663 goto snd_clone_alloc_out;
667 * Simmilar device type. Sort incrementally according
668 * to allocation unit. While here, look for free slot
669 * and possible collision for new / future allocation.
671 if (*unit == -1 && (ce->unit & ~tmask) == allocunit)
673 if ((ce->unit & ~tmask) < allocunit)
677 * 1. Look for non busy, but keep track of the best
678 * possible busy cdev.
679 * 2. Look for the best (oldest referenced) entry that is
680 * in a same process / thread.
681 * 3. Look for the best (oldest referenced), absolute free
683 * 4. Lastly, look for the best (oldest referenced)
684 * any entries that doesn't fit with anything above.
686 if (ce->flags & SND_CLONE_BUSY) {
687 if (ce->devt != NULL && (bce == NULL ||
688 timespeccmp(&ce->tsp, &bce->tsp, <)))
692 if (ce->pid == curpid &&
693 (cce == NULL || timespeccmp(&ce->tsp, &cce->tsp, <)))
695 else if (!(ce->flags & SND_CLONE_INVOKE) &&
696 (nce == NULL || timespeccmp(&ce->tsp, &nce->tsp, <)))
698 else if (tce == NULL || timespeccmp(&ce->tsp, &tce->tsp, <))
702 goto snd_clone_alloc_new;
703 else if (cce != NULL) {
704 /* Same proc entry found, go for it */
706 goto snd_clone_alloc_out;
707 } else if (nce != NULL) {
709 * Next, try absolute free entry. If the calculated
710 * allocunit is smaller, create new entry instead.
712 if (allocunit < (nce->unit & ~tmask))
713 goto snd_clone_alloc_new;
715 goto snd_clone_alloc_out;
716 } else if (allocunit > c->maxunit) {
718 * Maximum allowable unit reached. Try returning any
719 * available cdev and hope for the best. If the lookup is
720 * done for things like stat(), mtime() etc. , things should
721 * be ok. Otherwise, open() handler should do further checks
722 * and decide whether to return correct error code or not.
726 goto snd_clone_alloc_out;
727 } else if (bce != NULL) {
729 goto snd_clone_alloc_out;
736 * No free entries found, and we still haven't reached maximum
737 * allowable units. Allocate, setup a minimal unique entry with busy
738 * status so nobody will monkey on this new entry. Unit magic is set
739 * right here to avoid collision with other contesting handler.
740 * The caller must be carefull here to maintain its own
741 * synchronization, as long as it will not conflict with malloc(9)
744 * That said, go figure.
746 ce = malloc(sizeof(*ce), M_DEVBUF,
747 ((c->flags & SND_CLONE_WAITOK) ? M_WAITOK : M_NOWAIT) | M_ZERO);
752 * We're being dense, ignorance is bliss,
753 * Super Regulatory Measure (TM).. TRY AGAIN!
757 goto snd_clone_alloc_out;
758 } else if (tce != NULL) {
760 goto snd_clone_alloc_out;
761 } else if (bce != NULL) {
763 goto snd_clone_alloc_out;
767 /* Setup new entry */
769 ce->unit = tmask | allocunit;
772 ce->flags |= SND_CLONE_ALLOC;
774 TAILQ_INSERT_AFTER(&c->head, after, ce, link);
776 TAILQ_INSERT_HEAD(&c->head, ce, link);
781 * Save new allocation unit for caller which will be used
790 * Set, mark, timestamp the entry if this is a truly free entry.
791 * Leave busy entry alone.
793 if (!(ce->flags & SND_CLONE_BUSY)) {
796 ce->flags |= SND_CLONE_INVOKE;