xref: /onnv-gate/usr/src/uts/common/os/timer.c (revision 1885:7bbaa5935f99)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*1885Sraf  * Common Development and Distribution License (the "License").
6*1885Sraf  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
21*1885Sraf 
220Sstevel@tonic-gate /*
23*1885Sraf  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
240Sstevel@tonic-gate  * Use is subject to license terms.
250Sstevel@tonic-gate  */
260Sstevel@tonic-gate 
270Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
280Sstevel@tonic-gate 
290Sstevel@tonic-gate #include <sys/timer.h>
300Sstevel@tonic-gate #include <sys/systm.h>
310Sstevel@tonic-gate #include <sys/param.h>
320Sstevel@tonic-gate #include <sys/kmem.h>
330Sstevel@tonic-gate #include <sys/debug.h>
340Sstevel@tonic-gate #include <sys/policy.h>
350Sstevel@tonic-gate #include <sys/port.h>
360Sstevel@tonic-gate #include <sys/port_kernel.h>
370Sstevel@tonic-gate #include <sys/contract/process_impl.h>
380Sstevel@tonic-gate 
390Sstevel@tonic-gate static kmem_cache_t *clock_timer_cache;
400Sstevel@tonic-gate static clock_backend_t *clock_backend[CLOCK_MAX];
410Sstevel@tonic-gate static int timer_port_callback(void *, int *, pid_t, int, void *);
420Sstevel@tonic-gate static void timer_close_port(void *, int, pid_t, int);
430Sstevel@tonic-gate 
440Sstevel@tonic-gate #define	CLOCK_BACKEND(clk) \
450Sstevel@tonic-gate 	((clk) < CLOCK_MAX && (clk) >= 0 ? clock_backend[(clk)] : NULL)
460Sstevel@tonic-gate 
470Sstevel@tonic-gate /*
480Sstevel@tonic-gate  * Tunable to increase the maximum number of POSIX timers per-process.  This
490Sstevel@tonic-gate  * may _only_ be tuned in /etc/system or by patching the kernel binary; it
500Sstevel@tonic-gate  * _cannot_ be tuned on a running system.
510Sstevel@tonic-gate  */
520Sstevel@tonic-gate int timer_max = _TIMER_MAX;
530Sstevel@tonic-gate 
540Sstevel@tonic-gate /*
550Sstevel@tonic-gate  * timer_lock() locks the specified interval timer.  It doesn't look at the
560Sstevel@tonic-gate  * ITLK_REMOVE bit; it's up to callers to look at this if they need to
570Sstevel@tonic-gate  * care.  p_lock must be held on entry; it may be dropped and reaquired,
580Sstevel@tonic-gate  * but timer_lock() will always return with p_lock held.
590Sstevel@tonic-gate  *
600Sstevel@tonic-gate  * Note that timer_create() doesn't call timer_lock(); it creates timers
610Sstevel@tonic-gate  * with the ITLK_LOCKED bit explictly set.
620Sstevel@tonic-gate  */
630Sstevel@tonic-gate static void
640Sstevel@tonic-gate timer_lock(proc_t *p, itimer_t *it)
650Sstevel@tonic-gate {
660Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&p->p_lock));
670Sstevel@tonic-gate 
680Sstevel@tonic-gate 	while (it->it_lock & ITLK_LOCKED) {
690Sstevel@tonic-gate 		it->it_blockers++;
700Sstevel@tonic-gate 		cv_wait(&it->it_cv, &p->p_lock);
710Sstevel@tonic-gate 		it->it_blockers--;
720Sstevel@tonic-gate 	}
730Sstevel@tonic-gate 
740Sstevel@tonic-gate 	it->it_lock |= ITLK_LOCKED;
750Sstevel@tonic-gate }
760Sstevel@tonic-gate 
770Sstevel@tonic-gate /*
780Sstevel@tonic-gate  * timer_unlock() unlocks the specified interval timer, waking up any
790Sstevel@tonic-gate  * waiters.  p_lock must be held on entry; it will not be dropped by
800Sstevel@tonic-gate  * timer_unlock().
810Sstevel@tonic-gate  */
820Sstevel@tonic-gate static void
830Sstevel@tonic-gate timer_unlock(proc_t *p, itimer_t *it)
840Sstevel@tonic-gate {
850Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&p->p_lock));
860Sstevel@tonic-gate 	ASSERT(it->it_lock & ITLK_LOCKED);
870Sstevel@tonic-gate 	it->it_lock &= ~ITLK_LOCKED;
880Sstevel@tonic-gate 	cv_signal(&it->it_cv);
890Sstevel@tonic-gate }
900Sstevel@tonic-gate 
910Sstevel@tonic-gate /*
920Sstevel@tonic-gate  * timer_delete_locked() takes a proc pointer, timer ID and locked interval
930Sstevel@tonic-gate  * timer, and deletes the specified timer.  It must be called with p_lock
940Sstevel@tonic-gate  * held, and cannot be called on a timer which already has ITLK_REMOVE set;
950Sstevel@tonic-gate  * the caller must check this.  timer_delete_locked() will set the ITLK_REMOVE
960Sstevel@tonic-gate  * bit and will iteratively unlock and lock the interval timer until all
970Sstevel@tonic-gate  * blockers have seen the ITLK_REMOVE and cleared out.  It will then zero
980Sstevel@tonic-gate  * out the specified entry in the p_itimer array, and call into the clock
990Sstevel@tonic-gate  * backend to complete the deletion.
1000Sstevel@tonic-gate  *
1010Sstevel@tonic-gate  * This function will always return with p_lock held.
1020Sstevel@tonic-gate  */
1030Sstevel@tonic-gate static void
1040Sstevel@tonic-gate timer_delete_locked(proc_t *p, timer_t tid, itimer_t *it)
1050Sstevel@tonic-gate {
1060Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&p->p_lock));
1070Sstevel@tonic-gate 	ASSERT(!(it->it_lock & ITLK_REMOVE));
1080Sstevel@tonic-gate 	ASSERT(it->it_lock & ITLK_LOCKED);
1090Sstevel@tonic-gate 
1100Sstevel@tonic-gate 	it->it_lock |= ITLK_REMOVE;
1110Sstevel@tonic-gate 
1120Sstevel@tonic-gate 	/*
1130Sstevel@tonic-gate 	 * If there are threads waiting to lock this timer, we'll unlock
1140Sstevel@tonic-gate 	 * the timer, and block on the cv.  Threads blocking our removal will
1150Sstevel@tonic-gate 	 * have the opportunity to run; when they see the ITLK_REMOVE flag
1160Sstevel@tonic-gate 	 * set, they will immediately unlock the timer.
1170Sstevel@tonic-gate 	 */
1180Sstevel@tonic-gate 	while (it->it_blockers) {
1190Sstevel@tonic-gate 		timer_unlock(p, it);
1200Sstevel@tonic-gate 		cv_wait(&it->it_cv, &p->p_lock);
1210Sstevel@tonic-gate 		timer_lock(p, it);
1220Sstevel@tonic-gate 	}
1230Sstevel@tonic-gate 
1240Sstevel@tonic-gate 	ASSERT(p->p_itimer[tid] == it);
1250Sstevel@tonic-gate 	p->p_itimer[tid] = NULL;
1260Sstevel@tonic-gate 
1270Sstevel@tonic-gate 	/*
1280Sstevel@tonic-gate 	 * No one is blocked on this timer, and no one will be (we've set
1290Sstevel@tonic-gate 	 * p_itimer[tid] to be NULL; no one can find it).  Now we call into
1300Sstevel@tonic-gate 	 * the clock backend to delete the timer; it is up to the backend to
1310Sstevel@tonic-gate 	 * guarantee that timer_fire() has completed (and will never again
1320Sstevel@tonic-gate 	 * be called) for this timer.
1330Sstevel@tonic-gate 	 */
1340Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
1350Sstevel@tonic-gate 
1360Sstevel@tonic-gate 	it->it_backend->clk_timer_delete(it);
1370Sstevel@tonic-gate 
1380Sstevel@tonic-gate 	if (it->it_portev) {
1390Sstevel@tonic-gate 		mutex_enter(&it->it_mutex);
1400Sstevel@tonic-gate 		if (it->it_portev) {
1410Sstevel@tonic-gate 			/* dissociate timer from the event port */
1420Sstevel@tonic-gate 			(void) port_dissociate_ksource(it->it_portfd,
1430Sstevel@tonic-gate 			    PORT_SOURCE_TIMER, (port_source_t *)it->it_portsrc);
1440Sstevel@tonic-gate 			port_free_event((port_kevent_t *)it->it_portev);
1450Sstevel@tonic-gate 			it->it_portev = NULL;
1460Sstevel@tonic-gate 			it->it_flags &= ~IT_PORT;
1470Sstevel@tonic-gate 			it->it_pending = 0;
1480Sstevel@tonic-gate 		}
1490Sstevel@tonic-gate 		mutex_exit(&it->it_mutex);
1500Sstevel@tonic-gate 	}
1510Sstevel@tonic-gate 
1520Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
1530Sstevel@tonic-gate 
1540Sstevel@tonic-gate 	/*
1550Sstevel@tonic-gate 	 * We need to be careful freeing the sigqueue for this timer;
1560Sstevel@tonic-gate 	 * if a signal is pending, the sigqueue needs to be freed
1570Sstevel@tonic-gate 	 * synchronously in siginfofree().  The need to free the sigqueue
1580Sstevel@tonic-gate 	 * in siginfofree() is indicated by setting sq_func to NULL.
1590Sstevel@tonic-gate 	 */
1600Sstevel@tonic-gate 	if (it->it_pending > 0) {
1610Sstevel@tonic-gate 		it->it_sigq->sq_func = NULL;
1620Sstevel@tonic-gate 	} else {
1630Sstevel@tonic-gate 		kmem_free(it->it_sigq, sizeof (sigqueue_t));
1640Sstevel@tonic-gate 	}
1650Sstevel@tonic-gate 
1660Sstevel@tonic-gate 	ASSERT(it->it_blockers == 0);
1670Sstevel@tonic-gate 	kmem_cache_free(clock_timer_cache, it);
1680Sstevel@tonic-gate }
1690Sstevel@tonic-gate 
1700Sstevel@tonic-gate /*
1710Sstevel@tonic-gate  * timer_grab() and its companion routine, timer_release(), are wrappers
1720Sstevel@tonic-gate  * around timer_lock()/_unlock() which allow the timer_*(3R) routines to
1730Sstevel@tonic-gate  * (a) share error handling code and (b) not grab p_lock themselves.  Routines
1740Sstevel@tonic-gate  * which are called with p_lock held (e.g. timer_lwpbind(), timer_lwpexit())
1750Sstevel@tonic-gate  * must call timer_lock()/_unlock() explictly.
1760Sstevel@tonic-gate  *
1770Sstevel@tonic-gate  * timer_grab() takes a proc and a timer ID, and returns a pointer to a
1780Sstevel@tonic-gate  * locked interval timer.  p_lock must _not_ be held on entry; timer_grab()
1790Sstevel@tonic-gate  * may acquire p_lock, but will always return with p_lock dropped.
1800Sstevel@tonic-gate  *
1810Sstevel@tonic-gate  * If timer_grab() fails, it will return NULL.  timer_grab() will fail if
1820Sstevel@tonic-gate  * one or more of the following is true:
1830Sstevel@tonic-gate  *
1840Sstevel@tonic-gate  *  (a)	The specified timer ID is out of range.
1850Sstevel@tonic-gate  *
1860Sstevel@tonic-gate  *  (b)	The specified timer ID does not correspond to a timer ID returned
1870Sstevel@tonic-gate  *	from timer_create(3R).
1880Sstevel@tonic-gate  *
1890Sstevel@tonic-gate  *  (c)	The specified timer ID is currently being removed.
1900Sstevel@tonic-gate  *
1910Sstevel@tonic-gate  */
1920Sstevel@tonic-gate static itimer_t *
1930Sstevel@tonic-gate timer_grab(proc_t *p, timer_t tid)
1940Sstevel@tonic-gate {
1950Sstevel@tonic-gate 	itimer_t **itp, *it;
1960Sstevel@tonic-gate 
1970Sstevel@tonic-gate 	if (tid >= timer_max || tid < 0)
1980Sstevel@tonic-gate 		return (NULL);
1990Sstevel@tonic-gate 
2000Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
2010Sstevel@tonic-gate 
2020Sstevel@tonic-gate 	if ((itp = p->p_itimer) == NULL || (it = itp[tid]) == NULL) {
2030Sstevel@tonic-gate 		mutex_exit(&p->p_lock);
2040Sstevel@tonic-gate 		return (NULL);
2050Sstevel@tonic-gate 	}
2060Sstevel@tonic-gate 
2070Sstevel@tonic-gate 	timer_lock(p, it);
2080Sstevel@tonic-gate 
2090Sstevel@tonic-gate 	if (it->it_lock & ITLK_REMOVE) {
2100Sstevel@tonic-gate 		/*
2110Sstevel@tonic-gate 		 * Someone is removing this timer; it will soon be invalid.
2120Sstevel@tonic-gate 		 */
2130Sstevel@tonic-gate 		timer_unlock(p, it);
2140Sstevel@tonic-gate 		mutex_exit(&p->p_lock);
2150Sstevel@tonic-gate 		return (NULL);
2160Sstevel@tonic-gate 	}
2170Sstevel@tonic-gate 
2180Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
2190Sstevel@tonic-gate 
2200Sstevel@tonic-gate 	return (it);
2210Sstevel@tonic-gate }
2220Sstevel@tonic-gate 
2230Sstevel@tonic-gate /*
2240Sstevel@tonic-gate  * timer_release() releases a timer acquired with timer_grab().  p_lock
2250Sstevel@tonic-gate  * should not be held on entry; timer_release() will acquire p_lock but
2260Sstevel@tonic-gate  * will drop it before returning.
2270Sstevel@tonic-gate  */
2280Sstevel@tonic-gate static void
2290Sstevel@tonic-gate timer_release(proc_t *p, itimer_t *it)
2300Sstevel@tonic-gate {
2310Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
2320Sstevel@tonic-gate 	timer_unlock(p, it);
2330Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
2340Sstevel@tonic-gate }
2350Sstevel@tonic-gate 
2360Sstevel@tonic-gate /*
2370Sstevel@tonic-gate  * timer_delete_grabbed() deletes a timer acquired with timer_grab().
2380Sstevel@tonic-gate  * p_lock should not be held on entry; timer_delete_grabbed() will acquire
2390Sstevel@tonic-gate  * p_lock, but will drop it before returning.
2400Sstevel@tonic-gate  */
2410Sstevel@tonic-gate static void
2420Sstevel@tonic-gate timer_delete_grabbed(proc_t *p, timer_t tid, itimer_t *it)
2430Sstevel@tonic-gate {
2440Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
2450Sstevel@tonic-gate 	timer_delete_locked(p, tid, it);
2460Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
2470Sstevel@tonic-gate }
2480Sstevel@tonic-gate 
2490Sstevel@tonic-gate void
2500Sstevel@tonic-gate clock_timer_init()
2510Sstevel@tonic-gate {
2520Sstevel@tonic-gate 	clock_timer_cache = kmem_cache_create("timer_cache",
2530Sstevel@tonic-gate 	    sizeof (itimer_t), 0, NULL, NULL, NULL, NULL, NULL, 0);
2540Sstevel@tonic-gate }
2550Sstevel@tonic-gate 
2560Sstevel@tonic-gate void
2570Sstevel@tonic-gate clock_add_backend(clockid_t clock, clock_backend_t *backend)
2580Sstevel@tonic-gate {
2590Sstevel@tonic-gate 	ASSERT(clock >= 0 && clock < CLOCK_MAX);
2600Sstevel@tonic-gate 	ASSERT(clock_backend[clock] == NULL);
2610Sstevel@tonic-gate 
2620Sstevel@tonic-gate 	clock_backend[clock] = backend;
2630Sstevel@tonic-gate }
2640Sstevel@tonic-gate 
2650Sstevel@tonic-gate int
2660Sstevel@tonic-gate clock_settime(clockid_t clock, timespec_t *tp)
2670Sstevel@tonic-gate {
2680Sstevel@tonic-gate 	timespec_t t;
2690Sstevel@tonic-gate 	clock_backend_t *backend;
2700Sstevel@tonic-gate 	int error;
2710Sstevel@tonic-gate 
2720Sstevel@tonic-gate 	if ((backend = CLOCK_BACKEND(clock)) == NULL)
2730Sstevel@tonic-gate 		return (set_errno(EINVAL));
2740Sstevel@tonic-gate 
2750Sstevel@tonic-gate 	if (secpolicy_settime(CRED()) != 0)
2760Sstevel@tonic-gate 		return (set_errno(EPERM));
2770Sstevel@tonic-gate 
2780Sstevel@tonic-gate 	if (get_udatamodel() == DATAMODEL_NATIVE) {
2790Sstevel@tonic-gate 		if (copyin(tp, &t, sizeof (timespec_t)) != 0)
2800Sstevel@tonic-gate 			return (set_errno(EFAULT));
2810Sstevel@tonic-gate 	} else {
2820Sstevel@tonic-gate 		timespec32_t t32;
2830Sstevel@tonic-gate 
2840Sstevel@tonic-gate 		if (copyin(tp, &t32, sizeof (timespec32_t)) != 0)
2850Sstevel@tonic-gate 			return (set_errno(EFAULT));
2860Sstevel@tonic-gate 
2870Sstevel@tonic-gate 		TIMESPEC32_TO_TIMESPEC(&t, &t32);
2880Sstevel@tonic-gate 	}
2890Sstevel@tonic-gate 
2900Sstevel@tonic-gate 	if (itimerspecfix(&t))
2910Sstevel@tonic-gate 		return (set_errno(EINVAL));
2920Sstevel@tonic-gate 
2930Sstevel@tonic-gate 	error = backend->clk_clock_settime(&t);
2940Sstevel@tonic-gate 
2950Sstevel@tonic-gate 	if (error)
2960Sstevel@tonic-gate 		return (set_errno(error));
2970Sstevel@tonic-gate 
2980Sstevel@tonic-gate 	return (0);
2990Sstevel@tonic-gate }
3000Sstevel@tonic-gate 
3010Sstevel@tonic-gate int
3020Sstevel@tonic-gate clock_gettime(clockid_t clock, timespec_t *tp)
3030Sstevel@tonic-gate {
3040Sstevel@tonic-gate 	timespec_t t;
3050Sstevel@tonic-gate 	clock_backend_t *backend;
3060Sstevel@tonic-gate 	int error;
3070Sstevel@tonic-gate 
3080Sstevel@tonic-gate 	if ((backend = CLOCK_BACKEND(clock)) == NULL)
3090Sstevel@tonic-gate 		return (set_errno(EINVAL));
3100Sstevel@tonic-gate 
3110Sstevel@tonic-gate 	error = backend->clk_clock_gettime(&t);
3120Sstevel@tonic-gate 
3130Sstevel@tonic-gate 	if (error)
3140Sstevel@tonic-gate 		return (set_errno(error));
3150Sstevel@tonic-gate 
3160Sstevel@tonic-gate 	if (get_udatamodel() == DATAMODEL_NATIVE) {
3170Sstevel@tonic-gate 		if (copyout(&t, tp, sizeof (timespec_t)) != 0)
3180Sstevel@tonic-gate 			return (set_errno(EFAULT));
3190Sstevel@tonic-gate 	} else {
3200Sstevel@tonic-gate 		timespec32_t t32;
3210Sstevel@tonic-gate 
3220Sstevel@tonic-gate 		if (TIMESPEC_OVERFLOW(&t))
3230Sstevel@tonic-gate 			return (set_errno(EOVERFLOW));
3240Sstevel@tonic-gate 		TIMESPEC_TO_TIMESPEC32(&t32, &t);
3250Sstevel@tonic-gate 
3260Sstevel@tonic-gate 		if (copyout(&t32, tp, sizeof (timespec32_t)) != 0)
3270Sstevel@tonic-gate 			return (set_errno(EFAULT));
3280Sstevel@tonic-gate 	}
3290Sstevel@tonic-gate 
3300Sstevel@tonic-gate 	return (0);
3310Sstevel@tonic-gate }
3320Sstevel@tonic-gate 
3330Sstevel@tonic-gate int
3340Sstevel@tonic-gate clock_getres(clockid_t clock, timespec_t *tp)
3350Sstevel@tonic-gate {
3360Sstevel@tonic-gate 	timespec_t t;
3370Sstevel@tonic-gate 	clock_backend_t *backend;
3380Sstevel@tonic-gate 	int error;
3390Sstevel@tonic-gate 
3400Sstevel@tonic-gate 	/*
3410Sstevel@tonic-gate 	 * Strangely, the standard defines clock_getres() with a NULL tp
3420Sstevel@tonic-gate 	 * to do nothing (regardless of the validity of the specified
3430Sstevel@tonic-gate 	 * clock_id).  Go figure.
3440Sstevel@tonic-gate 	 */
3450Sstevel@tonic-gate 	if (tp == NULL)
3460Sstevel@tonic-gate 		return (0);
3470Sstevel@tonic-gate 
3480Sstevel@tonic-gate 	if ((backend = CLOCK_BACKEND(clock)) == NULL)
3490Sstevel@tonic-gate 		return (set_errno(EINVAL));
3500Sstevel@tonic-gate 
3510Sstevel@tonic-gate 	error = backend->clk_clock_getres(&t);
3520Sstevel@tonic-gate 
3530Sstevel@tonic-gate 	if (error)
3540Sstevel@tonic-gate 		return (set_errno(error));
3550Sstevel@tonic-gate 
3560Sstevel@tonic-gate 	if (get_udatamodel() == DATAMODEL_NATIVE) {
3570Sstevel@tonic-gate 		if (copyout(&t, tp, sizeof (timespec_t)) != 0)
3580Sstevel@tonic-gate 			return (set_errno(EFAULT));
3590Sstevel@tonic-gate 	} else {
3600Sstevel@tonic-gate 		timespec32_t t32;
3610Sstevel@tonic-gate 
3620Sstevel@tonic-gate 		if (TIMESPEC_OVERFLOW(&t))
3630Sstevel@tonic-gate 			return (set_errno(EOVERFLOW));
3640Sstevel@tonic-gate 		TIMESPEC_TO_TIMESPEC32(&t32, &t);
3650Sstevel@tonic-gate 
3660Sstevel@tonic-gate 		if (copyout(&t32, tp, sizeof (timespec32_t)) != 0)
3670Sstevel@tonic-gate 			return (set_errno(EFAULT));
3680Sstevel@tonic-gate 	}
3690Sstevel@tonic-gate 
3700Sstevel@tonic-gate 	return (0);
3710Sstevel@tonic-gate }
3720Sstevel@tonic-gate 
3730Sstevel@tonic-gate void
3740Sstevel@tonic-gate timer_signal(sigqueue_t *sigq)
3750Sstevel@tonic-gate {
3760Sstevel@tonic-gate 	itimer_t *it = (itimer_t *)sigq->sq_backptr;
3770Sstevel@tonic-gate 
3780Sstevel@tonic-gate 	/*
3790Sstevel@tonic-gate 	 * There are some conditions during a fork or an exit when we can
3800Sstevel@tonic-gate 	 * call siginfofree() without p_lock held.  To prevent a race
3810Sstevel@tonic-gate 	 * between timer_signal() and timer_fire() with regard to it_pending,
3820Sstevel@tonic-gate 	 * we therefore acquire it_mutex in both paths.
3830Sstevel@tonic-gate 	 */
3840Sstevel@tonic-gate 	mutex_enter(&it->it_mutex);
3850Sstevel@tonic-gate 	ASSERT(it->it_pending > 0);
3860Sstevel@tonic-gate 	it->it_overrun = it->it_pending - 1;
3870Sstevel@tonic-gate 	it->it_pending = 0;
3880Sstevel@tonic-gate 	mutex_exit(&it->it_mutex);
3890Sstevel@tonic-gate }
3900Sstevel@tonic-gate 
3910Sstevel@tonic-gate /*
3920Sstevel@tonic-gate  * This routine is called from the clock backend.
3930Sstevel@tonic-gate  */
3940Sstevel@tonic-gate void
3950Sstevel@tonic-gate timer_fire(itimer_t *it)
3960Sstevel@tonic-gate {
3970Sstevel@tonic-gate 	proc_t *p;
3980Sstevel@tonic-gate 	int proc_lock_held;
3990Sstevel@tonic-gate 
4000Sstevel@tonic-gate 	if (it->it_flags & IT_SIGNAL) {
4010Sstevel@tonic-gate 		/*
4020Sstevel@tonic-gate 		 * See the comment in timer_signal() for why it is not
4030Sstevel@tonic-gate 		 * sufficient to only grab p_lock here. Because p_lock can be
4040Sstevel@tonic-gate 		 * held on entry to timer_signal(), the lock ordering is
4050Sstevel@tonic-gate 		 * necessarily p_lock before it_mutex.
4060Sstevel@tonic-gate 		 */
4070Sstevel@tonic-gate 
4080Sstevel@tonic-gate 		p = it->it_proc;
4090Sstevel@tonic-gate 		proc_lock_held = 1;
4100Sstevel@tonic-gate 		mutex_enter(&p->p_lock);
4110Sstevel@tonic-gate 	} else {
4120Sstevel@tonic-gate 		/*
4130Sstevel@tonic-gate 		 * IT_PORT:
4140Sstevel@tonic-gate 		 * If a timer was ever programmed to send events to a port,
4150Sstevel@tonic-gate 		 * the IT_PORT flag will remain set until:
4160Sstevel@tonic-gate 		 * a) the timer is deleted (see timer_delete_locked()) or
4170Sstevel@tonic-gate 		 * b) the port is being closed (see timer_close_port()).
4180Sstevel@tonic-gate 		 * Both cases are synchronized with the it_mutex.
4190Sstevel@tonic-gate 		 * We don't need to use the p_lock because it is only
4200Sstevel@tonic-gate 		 * required in the IT_SIGNAL case.
4210Sstevel@tonic-gate 		 * If IT_PORT was set and the port is being closed then
4220Sstevel@tonic-gate 		 * the timer notification is set to NONE. In such a case
4230Sstevel@tonic-gate 		 * the timer itself and the it_pending counter remain active
4240Sstevel@tonic-gate 		 * until the application deletes the counter or the process
4250Sstevel@tonic-gate 		 * exits.
4260Sstevel@tonic-gate 		 */
4270Sstevel@tonic-gate 		proc_lock_held = 0;
4280Sstevel@tonic-gate 	}
4290Sstevel@tonic-gate 	mutex_enter(&it->it_mutex);
4300Sstevel@tonic-gate 
4310Sstevel@tonic-gate 	if (it->it_pending > 0) {
4320Sstevel@tonic-gate 		if (it->it_pending < INT_MAX)
4330Sstevel@tonic-gate 			it->it_pending++;
4340Sstevel@tonic-gate 		mutex_exit(&it->it_mutex);
4350Sstevel@tonic-gate 	} else {
4360Sstevel@tonic-gate 		if (it->it_flags & IT_PORT) {
4370Sstevel@tonic-gate 			it->it_pending = 1;
438*1885Sraf 			port_send_event((port_kevent_t *)it->it_portev);
4390Sstevel@tonic-gate 			mutex_exit(&it->it_mutex);
4400Sstevel@tonic-gate 		} else if (it->it_flags & IT_SIGNAL) {
4410Sstevel@tonic-gate 			it->it_pending = 1;
4420Sstevel@tonic-gate 			mutex_exit(&it->it_mutex);
4430Sstevel@tonic-gate 			sigaddqa(p, NULL, it->it_sigq);
4440Sstevel@tonic-gate 		} else {
4450Sstevel@tonic-gate 			mutex_exit(&it->it_mutex);
4460Sstevel@tonic-gate 		}
4470Sstevel@tonic-gate 	}
4480Sstevel@tonic-gate 
4490Sstevel@tonic-gate 	if (proc_lock_held)
4500Sstevel@tonic-gate 		mutex_exit(&p->p_lock);
4510Sstevel@tonic-gate }
4520Sstevel@tonic-gate 
4530Sstevel@tonic-gate int
4540Sstevel@tonic-gate timer_create(clockid_t clock, struct sigevent *evp, timer_t *tid)
4550Sstevel@tonic-gate {
4560Sstevel@tonic-gate 	struct sigevent ev;
4570Sstevel@tonic-gate 	proc_t *p = curproc;
4580Sstevel@tonic-gate 	clock_backend_t *backend;
4590Sstevel@tonic-gate 	itimer_t *it, **itp;
4600Sstevel@tonic-gate 	sigqueue_t *sigq;
4610Sstevel@tonic-gate 	cred_t *cr = CRED();
4620Sstevel@tonic-gate 	int error = 0;
4630Sstevel@tonic-gate 	timer_t i;
4640Sstevel@tonic-gate 	port_notify_t tim_pnevp;
4650Sstevel@tonic-gate 	port_kevent_t *pkevp = NULL;
4660Sstevel@tonic-gate 
4670Sstevel@tonic-gate 	if ((backend = CLOCK_BACKEND(clock)) == NULL)
4680Sstevel@tonic-gate 		return (set_errno(EINVAL));
4690Sstevel@tonic-gate 
4700Sstevel@tonic-gate 	if (evp != NULL) {
4710Sstevel@tonic-gate 		/*
4720Sstevel@tonic-gate 		 * short copyin() for binary compatibility
4730Sstevel@tonic-gate 		 * fetch oldsigevent to determine how much to copy in.
4740Sstevel@tonic-gate 		 */
4750Sstevel@tonic-gate 		if (get_udatamodel() == DATAMODEL_NATIVE) {
4760Sstevel@tonic-gate 			if (copyin(evp, &ev, sizeof (struct oldsigevent)))
4770Sstevel@tonic-gate 				return (set_errno(EFAULT));
4780Sstevel@tonic-gate 
479*1885Sraf 			if (ev.sigev_notify == SIGEV_PORT ||
480*1885Sraf 			    ev.sigev_notify == SIGEV_THREAD) {
4810Sstevel@tonic-gate 				if (copyin(ev.sigev_value.sival_ptr, &tim_pnevp,
4820Sstevel@tonic-gate 				    sizeof (port_notify_t)))
4830Sstevel@tonic-gate 					return (set_errno(EFAULT));
4840Sstevel@tonic-gate 			}
4850Sstevel@tonic-gate #ifdef	_SYSCALL32_IMPL
4860Sstevel@tonic-gate 		} else {
4870Sstevel@tonic-gate 			struct sigevent32 ev32;
4880Sstevel@tonic-gate 			port_notify32_t tim_pnevp32;
4890Sstevel@tonic-gate 
4900Sstevel@tonic-gate 			if (copyin(evp, &ev32, sizeof (struct oldsigevent32)))
4910Sstevel@tonic-gate 				return (set_errno(EFAULT));
4920Sstevel@tonic-gate 			ev.sigev_notify = ev32.sigev_notify;
4930Sstevel@tonic-gate 			ev.sigev_signo = ev32.sigev_signo;
4940Sstevel@tonic-gate 			/*
4950Sstevel@tonic-gate 			 * See comment in sigqueue32() on handling of 32-bit
4960Sstevel@tonic-gate 			 * sigvals in a 64-bit kernel.
4970Sstevel@tonic-gate 			 */
4980Sstevel@tonic-gate 			ev.sigev_value.sival_int = ev32.sigev_value.sival_int;
499*1885Sraf 			if (ev.sigev_notify == SIGEV_PORT ||
500*1885Sraf 			    ev.sigev_notify == SIGEV_THREAD) {
5010Sstevel@tonic-gate 				if (copyin((void *)(uintptr_t)
5020Sstevel@tonic-gate 				    ev32.sigev_value.sival_ptr,
5030Sstevel@tonic-gate 				    (void *)&tim_pnevp32,
5040Sstevel@tonic-gate 				    sizeof (port_notify32_t)))
5050Sstevel@tonic-gate 					return (set_errno(EFAULT));
5060Sstevel@tonic-gate 				tim_pnevp.portnfy_port =
5070Sstevel@tonic-gate 				    tim_pnevp32.portnfy_port;
5080Sstevel@tonic-gate 				tim_pnevp.portnfy_user =
5090Sstevel@tonic-gate 				    (void *)(uintptr_t)tim_pnevp32.portnfy_user;
5100Sstevel@tonic-gate 			}
5110Sstevel@tonic-gate #endif
5120Sstevel@tonic-gate 		}
5130Sstevel@tonic-gate 		switch (ev.sigev_notify) {
5140Sstevel@tonic-gate 		case SIGEV_NONE:
5150Sstevel@tonic-gate 			break;
5160Sstevel@tonic-gate 		case SIGEV_SIGNAL:
5170Sstevel@tonic-gate 			if (ev.sigev_signo < 1 || ev.sigev_signo >= NSIG)
5180Sstevel@tonic-gate 				return (set_errno(EINVAL));
5190Sstevel@tonic-gate 			break;
520*1885Sraf 		case SIGEV_THREAD:
5210Sstevel@tonic-gate 		case SIGEV_PORT:
5220Sstevel@tonic-gate 			break;
5230Sstevel@tonic-gate 		default:
5240Sstevel@tonic-gate 			return (set_errno(EINVAL));
5250Sstevel@tonic-gate 		}
5260Sstevel@tonic-gate 	} else {
5270Sstevel@tonic-gate 		/*
5280Sstevel@tonic-gate 		 * Use the clock's default sigevent (this is a structure copy).
5290Sstevel@tonic-gate 		 */
5300Sstevel@tonic-gate 		ev = backend->clk_default;
5310Sstevel@tonic-gate 	}
5320Sstevel@tonic-gate 
5330Sstevel@tonic-gate 	/*
5340Sstevel@tonic-gate 	 * We'll allocate our timer and sigqueue now, before we grab p_lock.
5350Sstevel@tonic-gate 	 * If we can't find an empty slot, we'll free them before returning.
5360Sstevel@tonic-gate 	 */
5370Sstevel@tonic-gate 	it = kmem_cache_alloc(clock_timer_cache, KM_SLEEP);
5380Sstevel@tonic-gate 	bzero(it, sizeof (itimer_t));
5390Sstevel@tonic-gate 	mutex_init(&it->it_mutex, NULL, MUTEX_DEFAULT, NULL);
5400Sstevel@tonic-gate 	sigq = kmem_zalloc(sizeof (sigqueue_t), KM_SLEEP);
5410Sstevel@tonic-gate 
5420Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
5430Sstevel@tonic-gate 
5440Sstevel@tonic-gate 	/*
5450Sstevel@tonic-gate 	 * If this is this process' first timer, we need to attempt to allocate
5460Sstevel@tonic-gate 	 * an array of timerstr_t pointers.  We drop p_lock to perform the
5470Sstevel@tonic-gate 	 * allocation; if we return to discover that p_itimer is non-NULL,
5480Sstevel@tonic-gate 	 * we will free our allocation and drive on.
5490Sstevel@tonic-gate 	 */
5500Sstevel@tonic-gate 	if ((itp = p->p_itimer) == NULL) {
5510Sstevel@tonic-gate 		mutex_exit(&p->p_lock);
5520Sstevel@tonic-gate 		itp = kmem_zalloc(timer_max * sizeof (itimer_t *), KM_SLEEP);
5530Sstevel@tonic-gate 		mutex_enter(&p->p_lock);
5540Sstevel@tonic-gate 
5550Sstevel@tonic-gate 		if (p->p_itimer == NULL)
5560Sstevel@tonic-gate 			p->p_itimer = itp;
5570Sstevel@tonic-gate 		else {
5580Sstevel@tonic-gate 			kmem_free(itp, timer_max * sizeof (itimer_t *));
5590Sstevel@tonic-gate 			itp = p->p_itimer;
5600Sstevel@tonic-gate 		}
5610Sstevel@tonic-gate 	}
5620Sstevel@tonic-gate 
5630Sstevel@tonic-gate 	for (i = 0; i < timer_max && itp[i] != NULL; i++)
5640Sstevel@tonic-gate 		continue;
5650Sstevel@tonic-gate 
5660Sstevel@tonic-gate 	if (i == timer_max) {
5670Sstevel@tonic-gate 		/*
5680Sstevel@tonic-gate 		 * We couldn't find a slot.  Drop p_lock, free the preallocated
5690Sstevel@tonic-gate 		 * timer and sigqueue, and return an error.
5700Sstevel@tonic-gate 		 */
5710Sstevel@tonic-gate 		mutex_exit(&p->p_lock);
5720Sstevel@tonic-gate 		kmem_cache_free(clock_timer_cache, it);
5730Sstevel@tonic-gate 		kmem_free(sigq, sizeof (sigqueue_t));
5740Sstevel@tonic-gate 
5750Sstevel@tonic-gate 		return (set_errno(EAGAIN));
5760Sstevel@tonic-gate 	}
5770Sstevel@tonic-gate 
5780Sstevel@tonic-gate 	ASSERT(i < timer_max && itp[i] == NULL);
5790Sstevel@tonic-gate 
5800Sstevel@tonic-gate 	/*
5810Sstevel@tonic-gate 	 * If we develop other notification mechanisms, this will need
5820Sstevel@tonic-gate 	 * to call into (yet another) backend.
5830Sstevel@tonic-gate 	 */
5840Sstevel@tonic-gate 	sigq->sq_info.si_signo = ev.sigev_signo;
585*1885Sraf 	if (evp == NULL)
586*1885Sraf 		sigq->sq_info.si_value.sival_int = i;
587*1885Sraf 	else
588*1885Sraf 		sigq->sq_info.si_value = ev.sigev_value;
5890Sstevel@tonic-gate 	sigq->sq_info.si_code = SI_TIMER;
5900Sstevel@tonic-gate 	sigq->sq_info.si_pid = p->p_pid;
5910Sstevel@tonic-gate 	sigq->sq_info.si_ctid = PRCTID(p);
5920Sstevel@tonic-gate 	sigq->sq_info.si_zoneid = getzoneid();
5930Sstevel@tonic-gate 	sigq->sq_info.si_uid = crgetruid(cr);
5940Sstevel@tonic-gate 	sigq->sq_func = timer_signal;
5950Sstevel@tonic-gate 	sigq->sq_next = NULL;
5960Sstevel@tonic-gate 	sigq->sq_backptr = it;
5970Sstevel@tonic-gate 	it->it_sigq = sigq;
5980Sstevel@tonic-gate 	it->it_backend = backend;
5990Sstevel@tonic-gate 	it->it_lock = ITLK_LOCKED;
6000Sstevel@tonic-gate 	itp[i] = it;
6010Sstevel@tonic-gate 
6020Sstevel@tonic-gate 
603*1885Sraf 	if (ev.sigev_notify == SIGEV_THREAD ||
604*1885Sraf 	    ev.sigev_notify == SIGEV_PORT) {
6050Sstevel@tonic-gate 		int port;
6060Sstevel@tonic-gate 
6070Sstevel@tonic-gate 		/*
6080Sstevel@tonic-gate 		 * This timer is programmed to use event port notification when
6090Sstevel@tonic-gate 		 * the timer fires:
6100Sstevel@tonic-gate 		 * - allocate a port event structure and prepare it to be sent
6110Sstevel@tonic-gate 		 *   to the port as soon as the timer fires.
6120Sstevel@tonic-gate 		 * - when the timer fires :
6130Sstevel@tonic-gate 		 *   - if event structure was already sent to the port then this
6140Sstevel@tonic-gate 		 *	is a timer fire overflow => increment overflow counter.
6150Sstevel@tonic-gate 		 *   - otherwise send pre-allocated event structure to the port.
6160Sstevel@tonic-gate 		 * - the events field of the port_event_t structure counts the
6170Sstevel@tonic-gate 		 *   number of timer fired events.
6180Sstevel@tonic-gate 		 * - The event structured is allocated using the
6190Sstevel@tonic-gate 		 *   PORT_ALLOC_CACHED flag.
6200Sstevel@tonic-gate 		 *   This flag indicates that the timer itself will manage and
6210Sstevel@tonic-gate 		 *   free the event structure when required.
6220Sstevel@tonic-gate 		 */
6230Sstevel@tonic-gate 
6240Sstevel@tonic-gate 		it->it_flags |= IT_PORT;
6250Sstevel@tonic-gate 		port = tim_pnevp.portnfy_port;
6260Sstevel@tonic-gate 
6270Sstevel@tonic-gate 		/* associate timer as event source with the port */
6280Sstevel@tonic-gate 		error = port_associate_ksource(port, PORT_SOURCE_TIMER,
6290Sstevel@tonic-gate 		    (port_source_t **)&it->it_portsrc, timer_close_port,
6300Sstevel@tonic-gate 		    (void *)it, NULL);
6310Sstevel@tonic-gate 		if (error) {
6320Sstevel@tonic-gate 			itp[i] = NULL;		/* clear slot */
6330Sstevel@tonic-gate 			mutex_exit(&p->p_lock);
6340Sstevel@tonic-gate 			kmem_cache_free(clock_timer_cache, it);
6350Sstevel@tonic-gate 			kmem_free(sigq, sizeof (sigqueue_t));
6360Sstevel@tonic-gate 			return (set_errno(error));
6370Sstevel@tonic-gate 		}
6380Sstevel@tonic-gate 
6390Sstevel@tonic-gate 		/* allocate an event structure/slot */
6400Sstevel@tonic-gate 		error = port_alloc_event(port, PORT_ALLOC_SCACHED,
6410Sstevel@tonic-gate 		    PORT_SOURCE_TIMER, &pkevp);
6420Sstevel@tonic-gate 		if (error) {
6430Sstevel@tonic-gate 			(void) port_dissociate_ksource(port, PORT_SOURCE_TIMER,
6440Sstevel@tonic-gate 			    (port_source_t *)it->it_portsrc);
6450Sstevel@tonic-gate 			itp[i] = NULL;		/* clear slot */
6460Sstevel@tonic-gate 			mutex_exit(&p->p_lock);
6470Sstevel@tonic-gate 			kmem_cache_free(clock_timer_cache, it);
6480Sstevel@tonic-gate 			kmem_free(sigq, sizeof (sigqueue_t));
6490Sstevel@tonic-gate 			return (set_errno(error));
6500Sstevel@tonic-gate 		}
6510Sstevel@tonic-gate 
6520Sstevel@tonic-gate 		/* initialize event data */
6530Sstevel@tonic-gate 		port_init_event(pkevp, i, tim_pnevp.portnfy_user,
6540Sstevel@tonic-gate 		    timer_port_callback, it);
6550Sstevel@tonic-gate 		it->it_portev = pkevp;
6560Sstevel@tonic-gate 		it->it_portfd = port;
6570Sstevel@tonic-gate 	} else {
6580Sstevel@tonic-gate 		if (ev.sigev_notify == SIGEV_SIGNAL)
6590Sstevel@tonic-gate 			it->it_flags |= IT_SIGNAL;
6600Sstevel@tonic-gate 	}
6610Sstevel@tonic-gate 
6620Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
6630Sstevel@tonic-gate 
6640Sstevel@tonic-gate 	/*
6650Sstevel@tonic-gate 	 * Call on the backend to verify the event argument (or return
6660Sstevel@tonic-gate 	 * EINVAL if this clock type does not support timers).
6670Sstevel@tonic-gate 	 */
6680Sstevel@tonic-gate 	if ((error = backend->clk_timer_create(it, &ev)) != 0)
6690Sstevel@tonic-gate 		goto err;
6700Sstevel@tonic-gate 
6710Sstevel@tonic-gate 	it->it_lwp = ttolwp(curthread);
6720Sstevel@tonic-gate 	it->it_proc = p;
6730Sstevel@tonic-gate 
6740Sstevel@tonic-gate 	if (copyout(&i, tid, sizeof (timer_t)) != 0) {
6750Sstevel@tonic-gate 		error = EFAULT;
6760Sstevel@tonic-gate 		goto err;
6770Sstevel@tonic-gate 	}
6780Sstevel@tonic-gate 
6790Sstevel@tonic-gate 	/*
6800Sstevel@tonic-gate 	 * If we're here, then we have successfully created the timer; we
6810Sstevel@tonic-gate 	 * just need to release the timer and return.
6820Sstevel@tonic-gate 	 */
6830Sstevel@tonic-gate 	timer_release(p, it);
6840Sstevel@tonic-gate 
6850Sstevel@tonic-gate 	return (0);
6860Sstevel@tonic-gate 
6870Sstevel@tonic-gate err:
6880Sstevel@tonic-gate 	/*
6890Sstevel@tonic-gate 	 * If we're here, an error has occurred late in the timer creation
6900Sstevel@tonic-gate 	 * process.  We need to regrab p_lock, and delete the incipient timer.
6910Sstevel@tonic-gate 	 * Since we never unlocked the timer (it was born locked), it's
6920Sstevel@tonic-gate 	 * impossible for a removal to be pending.
6930Sstevel@tonic-gate 	 */
6940Sstevel@tonic-gate 	ASSERT(!(it->it_lock & ITLK_REMOVE));
6950Sstevel@tonic-gate 	timer_delete_grabbed(p, i, it);
6960Sstevel@tonic-gate 
6970Sstevel@tonic-gate 	return (set_errno(error));
6980Sstevel@tonic-gate }
6990Sstevel@tonic-gate 
7000Sstevel@tonic-gate int
7010Sstevel@tonic-gate timer_gettime(timer_t tid, itimerspec_t *val)
7020Sstevel@tonic-gate {
7030Sstevel@tonic-gate 	proc_t *p = curproc;
7040Sstevel@tonic-gate 	itimer_t *it;
7050Sstevel@tonic-gate 	itimerspec_t when;
7060Sstevel@tonic-gate 	int error;
7070Sstevel@tonic-gate 
7080Sstevel@tonic-gate 	if ((it = timer_grab(p, tid)) == NULL)
7090Sstevel@tonic-gate 		return (set_errno(EINVAL));
7100Sstevel@tonic-gate 
7110Sstevel@tonic-gate 	error = it->it_backend->clk_timer_gettime(it, &when);
7120Sstevel@tonic-gate 
7130Sstevel@tonic-gate 	timer_release(p, it);
7140Sstevel@tonic-gate 
7150Sstevel@tonic-gate 	if (error == 0) {
7160Sstevel@tonic-gate 		if (get_udatamodel() == DATAMODEL_NATIVE) {
7170Sstevel@tonic-gate 			if (copyout(&when, val, sizeof (itimerspec_t)))
7180Sstevel@tonic-gate 				error = EFAULT;
7190Sstevel@tonic-gate 		} else {
7200Sstevel@tonic-gate 			if (ITIMERSPEC_OVERFLOW(&when))
7210Sstevel@tonic-gate 				error = EOVERFLOW;
7220Sstevel@tonic-gate 			else {
7230Sstevel@tonic-gate 				itimerspec32_t w32;
7240Sstevel@tonic-gate 
7250Sstevel@tonic-gate 				ITIMERSPEC_TO_ITIMERSPEC32(&w32, &when)
7260Sstevel@tonic-gate 				if (copyout(&w32, val, sizeof (itimerspec32_t)))
7270Sstevel@tonic-gate 					error = EFAULT;
7280Sstevel@tonic-gate 			}
7290Sstevel@tonic-gate 		}
7300Sstevel@tonic-gate 	}
7310Sstevel@tonic-gate 
7320Sstevel@tonic-gate 	return (error ? set_errno(error) : 0);
7330Sstevel@tonic-gate }
7340Sstevel@tonic-gate 
7350Sstevel@tonic-gate int
7360Sstevel@tonic-gate timer_settime(timer_t tid, int flags, itimerspec_t *val, itimerspec_t *oval)
7370Sstevel@tonic-gate {
7380Sstevel@tonic-gate 	itimerspec_t when;
7390Sstevel@tonic-gate 	timespec_t res;
7400Sstevel@tonic-gate 	itimer_t *it;
7410Sstevel@tonic-gate 	proc_t *p = curproc;
7420Sstevel@tonic-gate 	int error;
7430Sstevel@tonic-gate 
7440Sstevel@tonic-gate 	if (oval != NULL) {
7450Sstevel@tonic-gate 		if ((error = timer_gettime(tid, oval)) != 0)
7460Sstevel@tonic-gate 			return (error);
7470Sstevel@tonic-gate 	}
7480Sstevel@tonic-gate 
7490Sstevel@tonic-gate 	if (get_udatamodel() == DATAMODEL_NATIVE) {
7500Sstevel@tonic-gate 		if (copyin(val, &when, sizeof (itimerspec_t)))
7510Sstevel@tonic-gate 			return (set_errno(EFAULT));
7520Sstevel@tonic-gate 	} else {
7530Sstevel@tonic-gate 		itimerspec32_t w32;
7540Sstevel@tonic-gate 
7550Sstevel@tonic-gate 		if (copyin(val, &w32, sizeof (itimerspec32_t)))
7560Sstevel@tonic-gate 			return (set_errno(EFAULT));
7570Sstevel@tonic-gate 
7580Sstevel@tonic-gate 		ITIMERSPEC32_TO_ITIMERSPEC(&when, &w32);
7590Sstevel@tonic-gate 	}
7600Sstevel@tonic-gate 
7610Sstevel@tonic-gate 	if (itimerspecfix(&when.it_value) ||
7620Sstevel@tonic-gate 	    (itimerspecfix(&when.it_interval) &&
7630Sstevel@tonic-gate 	    timerspecisset(&when.it_value))) {
7640Sstevel@tonic-gate 		return (set_errno(EINVAL));
7650Sstevel@tonic-gate 	}
7660Sstevel@tonic-gate 
7670Sstevel@tonic-gate 	if ((it = timer_grab(p, tid)) == NULL)
7680Sstevel@tonic-gate 		return (set_errno(EINVAL));
7690Sstevel@tonic-gate 
7700Sstevel@tonic-gate 	/*
7710Sstevel@tonic-gate 	 * From the man page:
7720Sstevel@tonic-gate 	 *	Time values that are between two consecutive non-negative
7730Sstevel@tonic-gate 	 *	integer multiples of the resolution of the specified timer
7740Sstevel@tonic-gate 	 *	shall be rounded up to the larger multiple of the resolution.
7750Sstevel@tonic-gate 	 * We assume that the resolution of any clock is less than one second.
7760Sstevel@tonic-gate 	 */
7770Sstevel@tonic-gate 	if (it->it_backend->clk_clock_getres(&res) == 0 && res.tv_nsec > 1) {
7780Sstevel@tonic-gate 		long rem;
7790Sstevel@tonic-gate 
7800Sstevel@tonic-gate 		if ((rem = when.it_interval.tv_nsec % res.tv_nsec) != 0) {
7810Sstevel@tonic-gate 			when.it_interval.tv_nsec += res.tv_nsec - rem;
7820Sstevel@tonic-gate 			timespecfix(&when.it_interval);
7830Sstevel@tonic-gate 		}
7840Sstevel@tonic-gate 		if ((rem = when.it_value.tv_nsec % res.tv_nsec) != 0) {
7850Sstevel@tonic-gate 			when.it_value.tv_nsec += res.tv_nsec - rem;
7860Sstevel@tonic-gate 			timespecfix(&when.it_value);
7870Sstevel@tonic-gate 		}
7880Sstevel@tonic-gate 	}
7890Sstevel@tonic-gate 	error = it->it_backend->clk_timer_settime(it, flags, &when);
7900Sstevel@tonic-gate 
7910Sstevel@tonic-gate 	timer_release(p, it);
7920Sstevel@tonic-gate 
7930Sstevel@tonic-gate 	return (error ? set_errno(error) : 0);
7940Sstevel@tonic-gate }
7950Sstevel@tonic-gate 
7960Sstevel@tonic-gate int
7970Sstevel@tonic-gate timer_delete(timer_t tid)
7980Sstevel@tonic-gate {
7990Sstevel@tonic-gate 	proc_t *p = curproc;
8000Sstevel@tonic-gate 	itimer_t *it;
8010Sstevel@tonic-gate 
8020Sstevel@tonic-gate 	if ((it = timer_grab(p, tid)) == NULL)
8030Sstevel@tonic-gate 		return (set_errno(EINVAL));
8040Sstevel@tonic-gate 
8050Sstevel@tonic-gate 	timer_delete_grabbed(p, tid, it);
8060Sstevel@tonic-gate 
8070Sstevel@tonic-gate 	return (0);
8080Sstevel@tonic-gate }
8090Sstevel@tonic-gate 
8100Sstevel@tonic-gate int
8110Sstevel@tonic-gate timer_getoverrun(timer_t tid)
8120Sstevel@tonic-gate {
8130Sstevel@tonic-gate 	int overrun;
8140Sstevel@tonic-gate 	proc_t *p = curproc;
8150Sstevel@tonic-gate 	itimer_t *it;
8160Sstevel@tonic-gate 
8170Sstevel@tonic-gate 	if ((it = timer_grab(p, tid)) == NULL)
8180Sstevel@tonic-gate 		return (set_errno(EINVAL));
8190Sstevel@tonic-gate 
8200Sstevel@tonic-gate 	/*
8210Sstevel@tonic-gate 	 * The it_overrun field is protected by p_lock; we need to acquire
8220Sstevel@tonic-gate 	 * it before looking at the value.
8230Sstevel@tonic-gate 	 */
8240Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
8250Sstevel@tonic-gate 	overrun = it->it_overrun;
8260Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
8270Sstevel@tonic-gate 
8280Sstevel@tonic-gate 	timer_release(p, it);
8290Sstevel@tonic-gate 
8300Sstevel@tonic-gate 	return (overrun);
8310Sstevel@tonic-gate }
8320Sstevel@tonic-gate 
8330Sstevel@tonic-gate /*
8340Sstevel@tonic-gate  * Entered/exited with p_lock held, but will repeatedly drop and regrab p_lock.
8350Sstevel@tonic-gate  */
8360Sstevel@tonic-gate void
8370Sstevel@tonic-gate timer_lwpexit(void)
8380Sstevel@tonic-gate {
8390Sstevel@tonic-gate 	timer_t i;
8400Sstevel@tonic-gate 	proc_t *p = curproc;
8410Sstevel@tonic-gate 	klwp_t *lwp = ttolwp(curthread);
8420Sstevel@tonic-gate 	itimer_t *it, **itp;
8430Sstevel@tonic-gate 
8440Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&p->p_lock));
8450Sstevel@tonic-gate 
8460Sstevel@tonic-gate 	if ((itp = p->p_itimer) == NULL)
8470Sstevel@tonic-gate 		return;
8480Sstevel@tonic-gate 
8490Sstevel@tonic-gate 	for (i = 0; i < timer_max; i++) {
8500Sstevel@tonic-gate 		if ((it = itp[i]) == NULL)
8510Sstevel@tonic-gate 			continue;
8520Sstevel@tonic-gate 
8530Sstevel@tonic-gate 		timer_lock(p, it);
8540Sstevel@tonic-gate 
8550Sstevel@tonic-gate 		if ((it->it_lock & ITLK_REMOVE) || it->it_lwp != lwp) {
8560Sstevel@tonic-gate 			/*
8570Sstevel@tonic-gate 			 * This timer is either being removed or it isn't
8580Sstevel@tonic-gate 			 * associated with this lwp.
8590Sstevel@tonic-gate 			 */
8600Sstevel@tonic-gate 			timer_unlock(p, it);
8610Sstevel@tonic-gate 			continue;
8620Sstevel@tonic-gate 		}
8630Sstevel@tonic-gate 
8640Sstevel@tonic-gate 		/*
8650Sstevel@tonic-gate 		 * The LWP that created this timer is going away.  To the user,
8660Sstevel@tonic-gate 		 * our behavior here is explicitly undefined.  We will simply
8670Sstevel@tonic-gate 		 * null out the it_lwp field; if the LWP was bound to a CPU,
8680Sstevel@tonic-gate 		 * the cyclic will stay bound to that CPU until the process
8690Sstevel@tonic-gate 		 * exits.
8700Sstevel@tonic-gate 		 */
8710Sstevel@tonic-gate 		it->it_lwp = NULL;
8720Sstevel@tonic-gate 		timer_unlock(p, it);
8730Sstevel@tonic-gate 	}
8740Sstevel@tonic-gate }
8750Sstevel@tonic-gate 
8760Sstevel@tonic-gate /*
8770Sstevel@tonic-gate  * Called to notify of an LWP binding change.  Entered/exited with p_lock
8780Sstevel@tonic-gate  * held, but will repeatedly drop and regrab p_lock.
8790Sstevel@tonic-gate  */
8800Sstevel@tonic-gate void
8810Sstevel@tonic-gate timer_lwpbind()
8820Sstevel@tonic-gate {
8830Sstevel@tonic-gate 	timer_t i;
8840Sstevel@tonic-gate 	proc_t *p = curproc;
8850Sstevel@tonic-gate 	klwp_t *lwp = ttolwp(curthread);
8860Sstevel@tonic-gate 	itimer_t *it, **itp;
8870Sstevel@tonic-gate 
8880Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&p->p_lock));
8890Sstevel@tonic-gate 
8900Sstevel@tonic-gate 	if ((itp = p->p_itimer) == NULL)
8910Sstevel@tonic-gate 		return;
8920Sstevel@tonic-gate 
8930Sstevel@tonic-gate 	for (i = 0; i < timer_max; i++) {
8940Sstevel@tonic-gate 		if ((it = itp[i]) == NULL)
8950Sstevel@tonic-gate 			continue;
8960Sstevel@tonic-gate 
8970Sstevel@tonic-gate 		timer_lock(p, it);
8980Sstevel@tonic-gate 
8990Sstevel@tonic-gate 		if (!(it->it_lock & ITLK_REMOVE) && it->it_lwp == lwp) {
9000Sstevel@tonic-gate 			/*
9010Sstevel@tonic-gate 			 * Drop p_lock and jump into the backend.
9020Sstevel@tonic-gate 			 */
9030Sstevel@tonic-gate 			mutex_exit(&p->p_lock);
9040Sstevel@tonic-gate 			it->it_backend->clk_timer_lwpbind(it);
9050Sstevel@tonic-gate 			mutex_enter(&p->p_lock);
9060Sstevel@tonic-gate 		}
9070Sstevel@tonic-gate 
9080Sstevel@tonic-gate 		timer_unlock(p, it);
9090Sstevel@tonic-gate 	}
9100Sstevel@tonic-gate }
9110Sstevel@tonic-gate 
9120Sstevel@tonic-gate /*
9130Sstevel@tonic-gate  * This function should only be called if p_itimer is non-NULL.
9140Sstevel@tonic-gate  */
9150Sstevel@tonic-gate void
9160Sstevel@tonic-gate timer_exit(void)
9170Sstevel@tonic-gate {
9180Sstevel@tonic-gate 	timer_t i;
9190Sstevel@tonic-gate 	proc_t *p = curproc;
9200Sstevel@tonic-gate 
9210Sstevel@tonic-gate 	ASSERT(p->p_itimer != NULL);
9220Sstevel@tonic-gate 
9230Sstevel@tonic-gate 	for (i = 0; i < timer_max; i++)
9240Sstevel@tonic-gate 		(void) timer_delete(i);
9250Sstevel@tonic-gate 
9260Sstevel@tonic-gate 	kmem_free(p->p_itimer, timer_max * sizeof (itimer_t *));
9270Sstevel@tonic-gate 	p->p_itimer = NULL;
9280Sstevel@tonic-gate }
9290Sstevel@tonic-gate 
9300Sstevel@tonic-gate /*
9310Sstevel@tonic-gate  * timer_port_callback() is a callback function which is associated with the
9320Sstevel@tonic-gate  * timer event and is activated just before the event is delivered to the user.
9330Sstevel@tonic-gate  * The timer uses this function to update/set the overflow counter and
9340Sstevel@tonic-gate  * to reenable the use of the event structure.
9350Sstevel@tonic-gate  */
9360Sstevel@tonic-gate 
9370Sstevel@tonic-gate /* ARGSUSED */
9380Sstevel@tonic-gate static int
9390Sstevel@tonic-gate timer_port_callback(void *arg, int *events, pid_t pid, int flag, void *evp)
9400Sstevel@tonic-gate {
9410Sstevel@tonic-gate 	itimer_t	*it = arg;
9420Sstevel@tonic-gate 
9430Sstevel@tonic-gate 	mutex_enter(&it->it_mutex);
9440Sstevel@tonic-gate 	if (curproc != it->it_proc) {
9450Sstevel@tonic-gate 		/* can not deliver timer events to another proc */
9460Sstevel@tonic-gate 		mutex_exit(&it->it_mutex);
9470Sstevel@tonic-gate 		return (EACCES);
9480Sstevel@tonic-gate 	}
9490Sstevel@tonic-gate 	*events = it->it_pending;	/* 1 = 1 event, >1 # of overflows */
9500Sstevel@tonic-gate 	it->it_pending = 0;		/* reinit overflow counter	*/
9510Sstevel@tonic-gate 	/*
9520Sstevel@tonic-gate 	 * This function can also be activated when the port is being closed
9530Sstevel@tonic-gate 	 * and a timer event is already submitted to the port.
9540Sstevel@tonic-gate 	 * In such a case the event port framework will use the
9550Sstevel@tonic-gate 	 * close-callback function to notify the events sources.
9560Sstevel@tonic-gate 	 * The timer close-callback function is timer_close_port() which
9570Sstevel@tonic-gate 	 * will free all allocated resources (including the allocated
9580Sstevel@tonic-gate 	 * port event structure).
9590Sstevel@tonic-gate 	 * For that reason we don't need to check the value of flag here.
9600Sstevel@tonic-gate 	 */
9610Sstevel@tonic-gate 	mutex_exit(&it->it_mutex);
9620Sstevel@tonic-gate 	return (0);
9630Sstevel@tonic-gate }
9640Sstevel@tonic-gate 
9650Sstevel@tonic-gate /*
9660Sstevel@tonic-gate  * port is being closed ... free all allocated port event structures
9670Sstevel@tonic-gate  * The delivered arg currently correspond to the first timer associated with
9680Sstevel@tonic-gate  * the port and it is not useable in this case.
9690Sstevel@tonic-gate  * We have to scan the list of activated timers in the current proc and
9700Sstevel@tonic-gate  * compare them with the delivered port id.
9710Sstevel@tonic-gate  */
9720Sstevel@tonic-gate 
9730Sstevel@tonic-gate /* ARGSUSED */
9740Sstevel@tonic-gate static void
9750Sstevel@tonic-gate timer_close_port(void *arg, int port, pid_t pid, int lastclose)
9760Sstevel@tonic-gate {
9770Sstevel@tonic-gate 	proc_t		*p = curproc;
9780Sstevel@tonic-gate 	timer_t		tid;
9790Sstevel@tonic-gate 	itimer_t	*it;
9800Sstevel@tonic-gate 
9810Sstevel@tonic-gate 	for (tid = 0; tid < timer_max; tid++) {
9820Sstevel@tonic-gate 		if ((it = timer_grab(p, tid)) == NULL)
9830Sstevel@tonic-gate 			continue;
9840Sstevel@tonic-gate 		if (it->it_portev) {
9850Sstevel@tonic-gate 			mutex_enter(&it->it_mutex);
9860Sstevel@tonic-gate 			if (it->it_portfd == port) {
9870Sstevel@tonic-gate 				port_free_event((port_kevent_t *)it->it_portev);
9880Sstevel@tonic-gate 				it->it_portev = NULL;
9890Sstevel@tonic-gate 				it->it_flags &= ~IT_PORT;
9900Sstevel@tonic-gate 			}
9910Sstevel@tonic-gate 			mutex_exit(&it->it_mutex);
9920Sstevel@tonic-gate 		}
9930Sstevel@tonic-gate 		timer_release(p, it);
9940Sstevel@tonic-gate 	}
9950Sstevel@tonic-gate }
996