1 /*-
2 * Copyright (c) 2007 Ariff Abdullah <ariff@FreeBSD.org>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 * $FreeBSD: head/sys/dev/sound/clone.c 193640 2009-06-07 19:12:08Z ariff $
27 */
28
29 #include <sys/param.h>
30 #include <sys/systm.h>
31 #include <sys/conf.h>
32 #include <sys/kernel.h>
33 #include <sys/malloc.h>
34 #include <sys/proc.h>
35 #include <sys/devfs.h>
36
37 #ifdef HAVE_KERNEL_OPTION_HEADERS
38 #include "opt_snd.h"
39 #endif
40
41 #include <dev/sound/pcm/sound.h>
42 #include <dev/sound/clone.h>
43
44 DEVFS_DECLARE_CLONE_BITMAP(dsp);
45
46 /*
47 * So here we go again, another clonedevs manager. Unlike default clonedevs,
48 * this clone manager is designed to withstand various abusive behavior
49 * (such as 'while : ; do ls /dev/whatever ; done', etc.), reusable object
50 * after reaching certain expiration threshold, aggressive garbage collector,
51 * transparent device allocator and concurrency handling across multiple
52 * thread/proc. Due to limited information given by dev_clone EVENTHANDLER,
53 * we don't have much clues whether the caller wants a real open() or simply
54 * making fun of us with things like stat(), mtime() etc. Assuming that:
55 * 1) Time window between dev_clone EH <-> real open() should be small
56 * enough and 2) mtime()/stat() etc. always looks like a half way / stalled
57 * operation, we can decide whether a new cdev must be created, old
58 * (expired) cdev can be reused or an existing cdev can be shared.
59 *
60 * Most of the operations and logics are generic enough and can be applied
61 * on other places (such as if_tap, snp, etc). Perhaps this can be
62 * rearranged to complement clone_*(). However, due to this still being
63 * specific to the sound driver (and as a proof of concept on how it can be
64 * done), si_drv2 is used to keep the pointer of the clone list entry to
65 * avoid expensive lookup.
66 */
67
68 /* clone entry */
69 struct snd_clone_entry {
70 TAILQ_ENTRY(snd_clone_entry) link;
71 struct snd_clone *parent;
72 struct cdev *devt;
73 struct timespec tsp;
74 uint32_t flags;
75 pid_t pid;
76 int unit;
77 };
78
79 /* clone manager */
80 struct snd_clone {
81 TAILQ_HEAD(link_head, snd_clone_entry) head;
82 struct timespec tsp;
83 int refcount;
84 int size;
85 int typemask;
86 int maxunit;
87 int deadline;
88 uint32_t flags;
89 };
90
91 #ifdef SND_DIAGNOSTIC
92 #define SND_CLONE_ASSERT(x, y) do { \
93 if (!(x)) \
94 panic y; \
95 } while (0)
96 #else
97 #define SND_CLONE_ASSERT(...) KASSERT(__VA_ARGS__)
98 #endif
99
100 /*
101 * Shamelessly ripped off from vfs_subr.c
102 * We need at least 1/HZ precision as default timestamping.
103 */
104 enum { SND_TSP_SEC, SND_TSP_HZ, SND_TSP_USEC, SND_TSP_NSEC };
105
106 static int snd_timestamp_precision = SND_TSP_HZ;
107 TUNABLE_INT("hw.snd.timestamp_precision", &snd_timestamp_precision);
108
109 void
snd_timestamp(struct timespec * tsp)110 snd_timestamp(struct timespec *tsp)
111 {
112 struct timeval tv;
113
114 switch (snd_timestamp_precision) {
115 case SND_TSP_SEC:
116 tsp->tv_sec = time_second;
117 tsp->tv_nsec = 0;
118 break;
119 case SND_TSP_HZ:
120 getnanouptime(tsp);
121 break;
122 case SND_TSP_USEC:
123 microuptime(&tv);
124 TIMEVAL_TO_TIMESPEC(&tv, tsp);
125 break;
126 case SND_TSP_NSEC:
127 nanouptime(tsp);
128 break;
129 default:
130 snd_timestamp_precision = SND_TSP_HZ;
131 getnanouptime(tsp);
132 break;
133 }
134 }
135
136 #if defined(SND_DIAGNOSTIC) || defined(SND_DEBUG)
137 static int
sysctl_hw_snd_timestamp_precision(SYSCTL_HANDLER_ARGS)138 sysctl_hw_snd_timestamp_precision(SYSCTL_HANDLER_ARGS)
139 {
140 int err, val;
141
142 val = snd_timestamp_precision;
143 err = sysctl_handle_int(oidp, &val, 0, req);
144 if (err == 0 && req->newptr != NULL) {
145 switch (val) {
146 case SND_TSP_SEC:
147 case SND_TSP_HZ:
148 case SND_TSP_USEC:
149 case SND_TSP_NSEC:
150 snd_timestamp_precision = val;
151 break;
152 default:
153 break;
154 }
155 }
156
157 return (err);
158 }
159 SYSCTL_PROC(_hw_snd, OID_AUTO, timestamp_precision, CTLTYPE_INT | CTLFLAG_RW,
160 0, sizeof(int), sysctl_hw_snd_timestamp_precision, "I",
161 "timestamp precision (0=s 1=hz 2=us 3=ns)");
162 #endif
163
164 /*
165 * snd_clone_create() : Return opaque allocated clone manager.
166 */
167 struct snd_clone *
snd_clone_create(int typemask,int maxunit,int deadline,uint32_t flags)168 snd_clone_create(int typemask, int maxunit, int deadline, uint32_t flags)
169 {
170 struct snd_clone *c;
171
172 SND_CLONE_ASSERT(!(typemask & ~SND_CLONE_MAXUNIT),
173 ("invalid typemask: 0x%08x", typemask));
174 SND_CLONE_ASSERT(!(flags & ~SND_CLONE_MASK),
175 ("invalid clone flags=0x%08x", flags));
176
177 c = kmalloc(sizeof(*c), M_DEVBUF, M_WAITOK | M_ZERO);
178 c->refcount = 0;
179 c->size = 0;
180 c->typemask = typemask;
181 c->maxunit = (maxunit == -1) ? (~typemask & SND_CLONE_MAXUNIT) :
182 maxunit;
183 c->deadline = deadline;
184 c->flags = flags;
185 snd_timestamp(&c->tsp);
186 TAILQ_INIT(&c->head);
187
188 return (c);
189 }
190
191 int
snd_clone_busy(struct snd_clone * c)192 snd_clone_busy(struct snd_clone *c)
193 {
194 struct snd_clone_entry *ce;
195
196 SND_CLONE_ASSERT(c != NULL, ("NULL snd_clone"));
197
198 if (c->size == 0)
199 return (0);
200
201 TAILQ_FOREACH(ce, &c->head, link) {
202 if (ce->flags & SND_CLONE_BUSY)
203 return (EBUSY);
204 }
205
206 return (0);
207 }
208
209 /*
210 * snd_clone_enable()/disable() : Suspend/resume clone allocation through
211 * snd_clone_alloc(). Everything else will not be affected by this.
212 */
213 int
snd_clone_enable(struct snd_clone * c)214 snd_clone_enable(struct snd_clone *c)
215 {
216 SND_CLONE_ASSERT(c != NULL, ("NULL snd_clone"));
217
218 if (c->flags & SND_CLONE_ENABLE)
219 return (EINVAL);
220
221 c->flags |= SND_CLONE_ENABLE;
222
223 return (0);
224 }
225
226 int
snd_clone_disable(struct snd_clone * c)227 snd_clone_disable(struct snd_clone *c)
228 {
229 SND_CLONE_ASSERT(c != NULL, ("NULL snd_clone"));
230
231 if (!(c->flags & SND_CLONE_ENABLE))
232 return (EINVAL);
233
234 c->flags &= ~SND_CLONE_ENABLE;
235
236 return (0);
237 }
238
239 /*
240 * Getters / Setters. Not worth explaining :)
241 */
242 int
snd_clone_getsize(struct snd_clone * c)243 snd_clone_getsize(struct snd_clone *c)
244 {
245 SND_CLONE_ASSERT(c != NULL, ("NULL snd_clone"));
246
247 return (c->size);
248 }
249
250 int
snd_clone_getmaxunit(struct snd_clone * c)251 snd_clone_getmaxunit(struct snd_clone *c)
252 {
253 SND_CLONE_ASSERT(c != NULL, ("NULL snd_clone"));
254
255 return (c->maxunit);
256 }
257
258 int
snd_clone_setmaxunit(struct snd_clone * c,int maxunit)259 snd_clone_setmaxunit(struct snd_clone *c, int maxunit)
260 {
261 SND_CLONE_ASSERT(c != NULL, ("NULL snd_clone"));
262
263 c->maxunit = (maxunit == -1) ? (~c->typemask & SND_CLONE_MAXUNIT) :
264 maxunit;
265
266 return (c->maxunit);
267 }
268
269 int
snd_clone_getdeadline(struct snd_clone * c)270 snd_clone_getdeadline(struct snd_clone *c)
271 {
272 SND_CLONE_ASSERT(c != NULL, ("NULL snd_clone"));
273
274 return (c->deadline);
275 }
276
277 int
snd_clone_setdeadline(struct snd_clone * c,int deadline)278 snd_clone_setdeadline(struct snd_clone *c, int deadline)
279 {
280 SND_CLONE_ASSERT(c != NULL, ("NULL snd_clone"));
281
282 c->deadline = deadline;
283
284 return (c->deadline);
285 }
286
287 int
snd_clone_gettime(struct snd_clone * c,struct timespec * tsp)288 snd_clone_gettime(struct snd_clone *c, struct timespec *tsp)
289 {
290 SND_CLONE_ASSERT(c != NULL, ("NULL snd_clone"));
291 SND_CLONE_ASSERT(tsp != NULL, ("NULL timespec"));
292
293 *tsp = c->tsp;
294
295 return (0);
296 }
297
298 uint32_t
snd_clone_getflags(struct snd_clone * c)299 snd_clone_getflags(struct snd_clone *c)
300 {
301 SND_CLONE_ASSERT(c != NULL, ("NULL snd_clone"));
302
303 return (c->flags);
304 }
305
306 uint32_t
snd_clone_setflags(struct snd_clone * c,uint32_t flags)307 snd_clone_setflags(struct snd_clone *c, uint32_t flags)
308 {
309 SND_CLONE_ASSERT(c != NULL, ("NULL snd_clone"));
310 SND_CLONE_ASSERT(!(flags & ~SND_CLONE_MASK),
311 ("invalid clone flags=0x%08x", flags));
312
313 c->flags = flags;
314
315 return (c->flags);
316 }
317
318 int
snd_clone_getdevtime(struct cdev * dev,struct timespec * tsp)319 snd_clone_getdevtime(struct cdev *dev, struct timespec *tsp)
320 {
321 struct snd_clone_entry *ce;
322
323 SND_CLONE_ASSERT(dev != NULL, ("NULL dev"));
324 SND_CLONE_ASSERT(tsp != NULL, ("NULL timespec"));
325
326 ce = dev->si_drv2;
327 if (ce == NULL)
328 return (ENODEV);
329
330 SND_CLONE_ASSERT(ce->parent != NULL, ("NULL parent"));
331
332 *tsp = ce->tsp;
333
334 return (0);
335 }
336
337 uint32_t
snd_clone_getdevflags(struct cdev * dev)338 snd_clone_getdevflags(struct cdev *dev)
339 {
340 struct snd_clone_entry *ce;
341
342 SND_CLONE_ASSERT(dev != NULL, ("NULL dev"));
343
344 ce = dev->si_drv2;
345 if (ce == NULL)
346 return (0xffffffff);
347
348 SND_CLONE_ASSERT(ce->parent != NULL, ("NULL parent"));
349
350 return (ce->flags);
351 }
352
353 uint32_t
snd_clone_setdevflags(struct cdev * dev,uint32_t flags)354 snd_clone_setdevflags(struct cdev *dev, uint32_t flags)
355 {
356 struct snd_clone_entry *ce;
357
358 SND_CLONE_ASSERT(dev != NULL, ("NULL dev"));
359 SND_CLONE_ASSERT(!(flags & ~SND_CLONE_DEVMASK),
360 ("invalid clone dev flags=0x%08x", flags));
361
362 ce = dev->si_drv2;
363 if (ce == NULL)
364 return (0xffffffff);
365
366 SND_CLONE_ASSERT(ce->parent != NULL, ("NULL parent"));
367
368 ce->flags = flags;
369
370 return (ce->flags);
371 }
372
373 /* Elapsed time conversion to ms */
374 #define SND_CLONE_ELAPSED(x, y) \
375 ((((x)->tv_sec - (y)->tv_sec) * 1000) + \
376 (((y)->tv_nsec > (x)->tv_nsec) ? \
377 (((1000000000L + (x)->tv_nsec - \
378 (y)->tv_nsec) / 1000000) - 1000) : \
379 (((x)->tv_nsec - (y)->tv_nsec) / 1000000)))
380
381 #define SND_CLONE_EXPIRED(x, y, z) \
382 ((x)->deadline < 1 || \
383 ((y)->tv_sec - (z)->tv_sec) > ((x)->deadline / 1000) || \
384 SND_CLONE_ELAPSED(y, z) > (x)->deadline)
385
386 /*
387 * snd_clone_gc() : Garbage collector for stalled, expired objects. Refer to
388 * clone.h for explanations on GC settings.
389 */
390 int
snd_clone_gc(struct snd_clone * c)391 snd_clone_gc(struct snd_clone *c)
392 {
393 struct snd_clone_entry *ce, *tce;
394 struct timespec now;
395 int pruned;
396 int subunit;
397
398 SND_CLONE_ASSERT(c != NULL, ("NULL snd_clone"));
399
400 if (!(c->flags & SND_CLONE_GC_ENABLE) || c->size == 0)
401 return (0);
402
403 snd_timestamp(&now);
404
405 /*
406 * Bail out if the last clone handler was invoked below the deadline
407 * threshold.
408 */
409 if ((c->flags & SND_CLONE_GC_EXPIRED) &&
410 !SND_CLONE_EXPIRED(c, &now, &c->tsp))
411 return (0);
412
413 pruned = 0;
414
415 /*
416 * Visit each object in reverse order. If the object is still being
417 * referenced by a valid open(), skip it. Look for expired objects
418 * and either revoke its clone invocation status or mercilessly
419 * throw it away.
420 */
421 TAILQ_FOREACH_REVERSE_MUTABLE(ce, &c->head, link_head, link, tce) {
422 if (!(ce->flags & SND_CLONE_BUSY) &&
423 (!(ce->flags & SND_CLONE_INVOKE) ||
424 SND_CLONE_EXPIRED(c, &now, &ce->tsp))) {
425 if (c->flags & SND_CLONE_GC_REVOKE) {
426 ce->flags &= ~SND_CLONE_INVOKE;
427 ce->pid = -1;
428 } else {
429 TAILQ_REMOVE(&c->head, ce, link);
430 subunit = PCMSUBUNIT(ce->devt);
431 destroy_dev(ce->devt);
432 devfs_clone_bitmap_put(&DEVFS_CLONE_BITMAP(dsp), subunit);
433 kfree(ce, M_DEVBUF);
434 c->size--;
435 }
436 pruned++;
437 }
438 }
439
440 /* return total pruned objects */
441 return (pruned);
442 }
443
444 void
snd_clone_destroy(struct snd_clone * c)445 snd_clone_destroy(struct snd_clone *c)
446 {
447 struct snd_clone_entry *ce, *tmp;
448 int subunit;
449
450 SND_CLONE_ASSERT(c != NULL, ("NULL snd_clone"));
451
452 ce = TAILQ_FIRST(&c->head);
453 while (ce != NULL) {
454 tmp = TAILQ_NEXT(ce, link);
455 if (ce->devt != NULL) {
456 subunit = PCMSUBUNIT(ce->devt);
457 destroy_dev(ce->devt);
458 devfs_clone_bitmap_put(&DEVFS_CLONE_BITMAP(dsp), subunit);
459 }
460 kfree(ce, M_DEVBUF);
461 ce = tmp;
462 }
463
464 kfree(c, M_DEVBUF);
465 }
466
467 /*
468 * snd_clone_acquire() : The vital part of concurrency management. Must be
469 * called somewhere at the beginning of open() handler. ENODEV is not really
470 * fatal since it just tell the caller that this is not cloned stuff.
471 * EBUSY is *real*, don't forget that!
472 */
473 int
snd_clone_acquire(struct cdev * dev)474 snd_clone_acquire(struct cdev *dev)
475 {
476 struct snd_clone_entry *ce;
477
478 SND_CLONE_ASSERT(dev != NULL, ("NULL dev"));
479
480 ce = dev->si_drv2;
481 if (ce == NULL)
482 return (ENODEV);
483
484 SND_CLONE_ASSERT(ce->parent != NULL, ("NULL parent"));
485
486 ce->flags &= ~SND_CLONE_INVOKE;
487
488 if (ce->flags & SND_CLONE_BUSY)
489 return (EBUSY);
490
491 ce->flags |= SND_CLONE_BUSY;
492
493 return (0);
494 }
495
496 /*
497 * snd_clone_release() : Release busy status. Must be called somewhere at
498 * the end of close() handler, or somewhere after fail open().
499 */
500 int
snd_clone_release(struct cdev * dev)501 snd_clone_release(struct cdev *dev)
502 {
503 struct snd_clone_entry *ce;
504
505 SND_CLONE_ASSERT(dev != NULL, ("NULL dev"));
506
507 ce = dev->si_drv2;
508 if (ce == NULL)
509 return (ENODEV);
510
511 SND_CLONE_ASSERT(ce->parent != NULL, ("NULL parent"));
512
513 ce->flags &= ~SND_CLONE_INVOKE;
514
515 if (!(ce->flags & SND_CLONE_BUSY))
516 return (EBADF);
517
518 ce->flags &= ~SND_CLONE_BUSY;
519 ce->pid = -1;
520
521 return (0);
522 }
523
524 /*
525 * snd_clone_ref/unref() : Garbage collector reference counter. To make
526 * garbage collector run automatically, the sequence must be something like
527 * this (both in open() and close() handlers):
528 *
529 * open() - 1) snd_clone_acquire()
530 * 2) .... check check ... if failed, snd_clone_release()
531 * 3) Success. Call snd_clone_ref()
532 *
533 * close() - 1) .... check check check ....
534 * 2) Success. snd_clone_release()
535 * 3) snd_clone_unref() . Garbage collector will run at this point
536 * if this is the last referenced object.
537 */
538 int
snd_clone_ref(struct cdev * dev)539 snd_clone_ref(struct cdev *dev)
540 {
541 struct snd_clone_entry *ce;
542 struct snd_clone *c;
543
544 SND_CLONE_ASSERT(dev != NULL, ("NULL dev"));
545
546 ce = dev->si_drv2;
547 if (ce == NULL)
548 return (0);
549
550 c = ce->parent;
551 SND_CLONE_ASSERT(c != NULL, ("NULL parent"));
552 SND_CLONE_ASSERT(c->refcount >= 0, ("refcount < 0"));
553
554 return (++c->refcount);
555 }
556
557 int
snd_clone_unref(struct cdev * dev)558 snd_clone_unref(struct cdev *dev)
559 {
560 struct snd_clone_entry *ce;
561 struct snd_clone *c;
562
563 SND_CLONE_ASSERT(dev != NULL, ("NULL dev"));
564
565 ce = dev->si_drv2;
566 if (ce == NULL)
567 return (0);
568
569 c = ce->parent;
570 SND_CLONE_ASSERT(c != NULL, ("NULL parent"));
571 SND_CLONE_ASSERT(c->refcount > 0, ("refcount <= 0"));
572
573 c->refcount--;
574
575 /*
576 * Run automatic garbage collector, if needed.
577 */
578 if ((c->flags & SND_CLONE_GC_UNREF) &&
579 (!(c->flags & SND_CLONE_GC_LASTREF) ||
580 (c->refcount == 0 && (c->flags & SND_CLONE_GC_LASTREF))))
581 (void)snd_clone_gc(c);
582
583 return (c->refcount);
584 }
585
586 void
snd_clone_register(struct snd_clone_entry * ce,struct cdev * dev)587 snd_clone_register(struct snd_clone_entry *ce, struct cdev *dev)
588 {
589 SND_CLONE_ASSERT(ce != NULL, ("NULL snd_clone_entry"));
590 SND_CLONE_ASSERT(dev != NULL, ("NULL dev"));
591 SND_CLONE_ASSERT(dev->si_drv2 == NULL, ("dev->si_drv2 not NULL"));
592 SND_CLONE_ASSERT((ce->flags & SND_CLONE_ALLOC) == SND_CLONE_ALLOC,
593 ("invalid clone alloc flags=0x%08x", ce->flags));
594 SND_CLONE_ASSERT(ce->devt == NULL, ("ce->devt not NULL"));
595 #if 0 /* dev2unit doesn't make any sense on DragonFly */
596 SND_CLONE_ASSERT(ce->unit == dev2unit(dev),
597 ("invalid unit ce->unit=0x%08x dev2unit=0x%08x",
598 ce->unit, dev2unit(dev)));
599 #endif
600
601 SND_CLONE_ASSERT(ce->parent != NULL, ("NULL parent"));
602
603 dev->si_drv2 = ce;
604 ce->devt = dev;
605 ce->flags &= ~SND_CLONE_ALLOC;
606 ce->flags |= SND_CLONE_INVOKE;
607 }
608
609 struct snd_clone_entry *
snd_clone_alloc(struct snd_clone * c,struct cdev ** dev,int * unit,int tmask)610 snd_clone_alloc(struct snd_clone *c, struct cdev **dev, int *unit, int tmask)
611 {
612 struct snd_clone_entry *ce, *after, *bce, *cce, *nce, *tce;
613 struct timespec now;
614 int cunit, allocunit;
615 pid_t curpid;
616
617 SND_CLONE_ASSERT(c != NULL, ("NULL snd_clone"));
618 SND_CLONE_ASSERT(dev != NULL, ("NULL dev pointer"));
619 SND_CLONE_ASSERT((c->typemask & tmask) == tmask,
620 ("invalid tmask: typemask=0x%08x tmask=0x%08x",
621 c->typemask, tmask));
622 SND_CLONE_ASSERT(unit != NULL, ("NULL unit pointer"));
623 SND_CLONE_ASSERT(*unit == -1 || !(*unit & (c->typemask | tmask)),
624 ("typemask collision: typemask=0x%08x tmask=0x%08x *unit=%d",
625 c->typemask, tmask, *unit));
626
627 if (!(c->flags & SND_CLONE_ENABLE) ||
628 (*unit != -1 && *unit > c->maxunit))
629 return (NULL);
630
631 ce = NULL;
632 after = NULL;
633 bce = NULL; /* "b"usy candidate */
634 cce = NULL; /* "c"urthread/proc candidate */
635 nce = NULL; /* "n"ull, totally unbusy candidate */
636 tce = NULL; /* Last "t"ry candidate */
637 cunit = 0;
638 allocunit = (*unit == -1) ? 0 : *unit;
639 curpid = curthread->td_proc->p_pid;
640
641 snd_timestamp(&now);
642
643 TAILQ_FOREACH(ce, &c->head, link) {
644 /*
645 * Sort incrementally according to device type.
646 */
647 if (tmask > (ce->unit & c->typemask)) {
648 if (cunit == 0)
649 after = ce;
650 continue;
651 } else if (tmask < (ce->unit & c->typemask))
652 break;
653
654 /*
655 * Shoot.. this is where the grumpiness begin. Just
656 * return immediately.
657 */
658 if (*unit != -1 && *unit == (ce->unit & ~tmask))
659 goto snd_clone_alloc_out;
660
661 cunit++;
662 /*
663 * Simmilar device type. Sort incrementally according
664 * to allocation unit. While here, look for free slot
665 * and possible collision for new / future allocation.
666 */
667 if (*unit == -1 && (ce->unit & ~tmask) == allocunit)
668 allocunit++;
669 if ((ce->unit & ~tmask) < allocunit)
670 after = ce;
671 /*
672 * Clone logic:
673 * 1. Look for non busy, but keep track of the best
674 * possible busy cdev.
675 * 2. Look for the best (oldest referenced) entry that is
676 * in a same process / thread.
677 * 3. Look for the best (oldest referenced), absolute free
678 * entry.
679 * 4. Lastly, look for the best (oldest referenced)
680 * any entries that doesn't fit with anything above.
681 */
682 if (ce->flags & SND_CLONE_BUSY) {
683 if (ce->devt != NULL && (bce == NULL ||
684 timespeccmp(&ce->tsp, &bce->tsp, <)))
685 bce = ce;
686 continue;
687 }
688 if (ce->pid == curpid &&
689 (cce == NULL || timespeccmp(&ce->tsp, &cce->tsp, <)))
690 cce = ce;
691 else if (!(ce->flags & SND_CLONE_INVOKE) &&
692 (nce == NULL || timespeccmp(&ce->tsp, &nce->tsp, <)))
693 nce = ce;
694 else if (tce == NULL || timespeccmp(&ce->tsp, &tce->tsp, <))
695 tce = ce;
696 }
697 if (*unit != -1)
698 goto snd_clone_alloc_new;
699 else if (cce != NULL) {
700 /* Same proc entry found, go for it */
701 ce = cce;
702 goto snd_clone_alloc_out;
703 } else if (nce != NULL) {
704 /*
705 * Next, try absolute free entry. If the calculated
706 * allocunit is smaller, create new entry instead.
707 */
708 if (allocunit < (nce->unit & ~tmask))
709 goto snd_clone_alloc_new;
710 ce = nce;
711 goto snd_clone_alloc_out;
712 } else if (allocunit > c->maxunit) {
713 /*
714 * Maximum allowable unit reached. Try returning any
715 * available cdev and hope for the best. If the lookup is
716 * done for things like stat(), mtime() etc. , things should
717 * be ok. Otherwise, open() handler should do further checks
718 * and decide whether to return correct error code or not.
719 */
720 if (tce != NULL) {
721 ce = tce;
722 goto snd_clone_alloc_out;
723 } else if (bce != NULL) {
724 ce = bce;
725 goto snd_clone_alloc_out;
726 }
727 return (NULL);
728 }
729
730 snd_clone_alloc_new:
731 /*
732 * No free entries found, and we still haven't reached maximum
733 * allowable units. Allocate, setup a minimal unique entry with busy
734 * status so nobody will monkey on this new entry. Unit magic is set
735 * right here to avoid collision with other contesting handler.
736 * The caller must be carefull here to maintain its own
737 * synchronization, as long as it will not conflict with malloc(9)
738 * operations.
739 *
740 * That said, go figure.
741 */
742 ce = kmalloc(sizeof(*ce), M_DEVBUF, M_WAITOK | M_ZERO);
743 if (ce == NULL) {
744 if (*unit != -1)
745 return (NULL);
746 /*
747 * We're being dense, ignorance is bliss,
748 * Super Regulatory Measure (TM).. TRY AGAIN!
749 */
750 if (nce != NULL) {
751 ce = nce;
752 goto snd_clone_alloc_out;
753 } else if (tce != NULL) {
754 ce = tce;
755 goto snd_clone_alloc_out;
756 } else if (bce != NULL) {
757 ce = bce;
758 goto snd_clone_alloc_out;
759 }
760 return (NULL);
761 }
762 /* Setup new entry */
763 ce->parent = c;
764 ce->unit = tmask | allocunit;
765 ce->pid = curpid;
766 ce->tsp = now;
767 ce->flags |= SND_CLONE_ALLOC;
768 if (after != NULL) {
769 TAILQ_INSERT_AFTER(&c->head, after, ce, link);
770 } else {
771 TAILQ_INSERT_HEAD(&c->head, ce, link);
772 }
773 c->size++;
774 c->tsp = now;
775 /*
776 * Save new allocation unit for caller which will be used
777 * by make_dev().
778 */
779 *unit = allocunit;
780
781 return (ce);
782
783 snd_clone_alloc_out:
784 /*
785 * Set, mark, timestamp the entry if this is a truly free entry.
786 * Leave busy entry alone.
787 */
788 if (!(ce->flags & SND_CLONE_BUSY)) {
789 ce->pid = curpid;
790 ce->tsp = now;
791 ce->flags |= SND_CLONE_INVOKE;
792 }
793 c->tsp = now;
794 *dev = ce->devt;
795
796 return (NULL);
797 }
798