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