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
51885Sraf * Common Development and Distribution License (the "License").
61885Sraf * 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 */
211885Sraf
220Sstevel@tonic-gate /*
23*4915Spraks * Copyright 2007 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>
35*4915Spraks #include <sys/port_impl.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
timer_lock(proc_t * p,itimer_t * it)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
timer_unlock(proc_t * p,itimer_t * it)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
timer_delete_locked(proc_t * p,timer_t tid,itimer_t * it)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) {
141*4915Spraks port_kevent_t *pev;
1420Sstevel@tonic-gate /* dissociate timer from the event port */
1430Sstevel@tonic-gate (void) port_dissociate_ksource(it->it_portfd,
1440Sstevel@tonic-gate PORT_SOURCE_TIMER, (port_source_t *)it->it_portsrc);
145*4915Spraks pev = (port_kevent_t *)it->it_portev;
1460Sstevel@tonic-gate it->it_portev = NULL;
1470Sstevel@tonic-gate it->it_flags &= ~IT_PORT;
1480Sstevel@tonic-gate it->it_pending = 0;
149*4915Spraks mutex_exit(&it->it_mutex);
150*4915Spraks (void) port_remove_done_event(pev);
151*4915Spraks port_free_event(pev);
152*4915Spraks } else {
153*4915Spraks mutex_exit(&it->it_mutex);
1540Sstevel@tonic-gate }
1550Sstevel@tonic-gate }
1560Sstevel@tonic-gate
1570Sstevel@tonic-gate mutex_enter(&p->p_lock);
1580Sstevel@tonic-gate
1590Sstevel@tonic-gate /*
1600Sstevel@tonic-gate * We need to be careful freeing the sigqueue for this timer;
1610Sstevel@tonic-gate * if a signal is pending, the sigqueue needs to be freed
1620Sstevel@tonic-gate * synchronously in siginfofree(). The need to free the sigqueue
1630Sstevel@tonic-gate * in siginfofree() is indicated by setting sq_func to NULL.
1640Sstevel@tonic-gate */
1650Sstevel@tonic-gate if (it->it_pending > 0) {
1660Sstevel@tonic-gate it->it_sigq->sq_func = NULL;
1670Sstevel@tonic-gate } else {
1680Sstevel@tonic-gate kmem_free(it->it_sigq, sizeof (sigqueue_t));
1690Sstevel@tonic-gate }
1700Sstevel@tonic-gate
1710Sstevel@tonic-gate ASSERT(it->it_blockers == 0);
1720Sstevel@tonic-gate kmem_cache_free(clock_timer_cache, it);
1730Sstevel@tonic-gate }
1740Sstevel@tonic-gate
1750Sstevel@tonic-gate /*
1760Sstevel@tonic-gate * timer_grab() and its companion routine, timer_release(), are wrappers
1770Sstevel@tonic-gate * around timer_lock()/_unlock() which allow the timer_*(3R) routines to
1780Sstevel@tonic-gate * (a) share error handling code and (b) not grab p_lock themselves. Routines
1790Sstevel@tonic-gate * which are called with p_lock held (e.g. timer_lwpbind(), timer_lwpexit())
1800Sstevel@tonic-gate * must call timer_lock()/_unlock() explictly.
1810Sstevel@tonic-gate *
1820Sstevel@tonic-gate * timer_grab() takes a proc and a timer ID, and returns a pointer to a
1830Sstevel@tonic-gate * locked interval timer. p_lock must _not_ be held on entry; timer_grab()
1840Sstevel@tonic-gate * may acquire p_lock, but will always return with p_lock dropped.
1850Sstevel@tonic-gate *
1860Sstevel@tonic-gate * If timer_grab() fails, it will return NULL. timer_grab() will fail if
1870Sstevel@tonic-gate * one or more of the following is true:
1880Sstevel@tonic-gate *
1890Sstevel@tonic-gate * (a) The specified timer ID is out of range.
1900Sstevel@tonic-gate *
1910Sstevel@tonic-gate * (b) The specified timer ID does not correspond to a timer ID returned
1920Sstevel@tonic-gate * from timer_create(3R).
1930Sstevel@tonic-gate *
1940Sstevel@tonic-gate * (c) The specified timer ID is currently being removed.
1950Sstevel@tonic-gate *
1960Sstevel@tonic-gate */
1970Sstevel@tonic-gate static itimer_t *
timer_grab(proc_t * p,timer_t tid)1980Sstevel@tonic-gate timer_grab(proc_t *p, timer_t tid)
1990Sstevel@tonic-gate {
2000Sstevel@tonic-gate itimer_t **itp, *it;
2010Sstevel@tonic-gate
2020Sstevel@tonic-gate if (tid >= timer_max || tid < 0)
2030Sstevel@tonic-gate return (NULL);
2040Sstevel@tonic-gate
2050Sstevel@tonic-gate mutex_enter(&p->p_lock);
2060Sstevel@tonic-gate
2070Sstevel@tonic-gate if ((itp = p->p_itimer) == NULL || (it = itp[tid]) == NULL) {
2080Sstevel@tonic-gate mutex_exit(&p->p_lock);
2090Sstevel@tonic-gate return (NULL);
2100Sstevel@tonic-gate }
2110Sstevel@tonic-gate
2120Sstevel@tonic-gate timer_lock(p, it);
2130Sstevel@tonic-gate
2140Sstevel@tonic-gate if (it->it_lock & ITLK_REMOVE) {
2150Sstevel@tonic-gate /*
2160Sstevel@tonic-gate * Someone is removing this timer; it will soon be invalid.
2170Sstevel@tonic-gate */
2180Sstevel@tonic-gate timer_unlock(p, it);
2190Sstevel@tonic-gate mutex_exit(&p->p_lock);
2200Sstevel@tonic-gate return (NULL);
2210Sstevel@tonic-gate }
2220Sstevel@tonic-gate
2230Sstevel@tonic-gate mutex_exit(&p->p_lock);
2240Sstevel@tonic-gate
2250Sstevel@tonic-gate return (it);
2260Sstevel@tonic-gate }
2270Sstevel@tonic-gate
2280Sstevel@tonic-gate /*
2290Sstevel@tonic-gate * timer_release() releases a timer acquired with timer_grab(). p_lock
2300Sstevel@tonic-gate * should not be held on entry; timer_release() will acquire p_lock but
2310Sstevel@tonic-gate * will drop it before returning.
2320Sstevel@tonic-gate */
2330Sstevel@tonic-gate static void
timer_release(proc_t * p,itimer_t * it)2340Sstevel@tonic-gate timer_release(proc_t *p, itimer_t *it)
2350Sstevel@tonic-gate {
2360Sstevel@tonic-gate mutex_enter(&p->p_lock);
2370Sstevel@tonic-gate timer_unlock(p, it);
2380Sstevel@tonic-gate mutex_exit(&p->p_lock);
2390Sstevel@tonic-gate }
2400Sstevel@tonic-gate
2410Sstevel@tonic-gate /*
2420Sstevel@tonic-gate * timer_delete_grabbed() deletes a timer acquired with timer_grab().
2430Sstevel@tonic-gate * p_lock should not be held on entry; timer_delete_grabbed() will acquire
2440Sstevel@tonic-gate * p_lock, but will drop it before returning.
2450Sstevel@tonic-gate */
2460Sstevel@tonic-gate static void
timer_delete_grabbed(proc_t * p,timer_t tid,itimer_t * it)2470Sstevel@tonic-gate timer_delete_grabbed(proc_t *p, timer_t tid, itimer_t *it)
2480Sstevel@tonic-gate {
2490Sstevel@tonic-gate mutex_enter(&p->p_lock);
2500Sstevel@tonic-gate timer_delete_locked(p, tid, it);
2510Sstevel@tonic-gate mutex_exit(&p->p_lock);
2520Sstevel@tonic-gate }
2530Sstevel@tonic-gate
2540Sstevel@tonic-gate void
clock_timer_init()2550Sstevel@tonic-gate clock_timer_init()
2560Sstevel@tonic-gate {
2570Sstevel@tonic-gate clock_timer_cache = kmem_cache_create("timer_cache",
2580Sstevel@tonic-gate sizeof (itimer_t), 0, NULL, NULL, NULL, NULL, NULL, 0);
2590Sstevel@tonic-gate }
2600Sstevel@tonic-gate
2610Sstevel@tonic-gate void
clock_add_backend(clockid_t clock,clock_backend_t * backend)2620Sstevel@tonic-gate clock_add_backend(clockid_t clock, clock_backend_t *backend)
2630Sstevel@tonic-gate {
2640Sstevel@tonic-gate ASSERT(clock >= 0 && clock < CLOCK_MAX);
2650Sstevel@tonic-gate ASSERT(clock_backend[clock] == NULL);
2660Sstevel@tonic-gate
2670Sstevel@tonic-gate clock_backend[clock] = backend;
2680Sstevel@tonic-gate }
2690Sstevel@tonic-gate
2700Sstevel@tonic-gate int
clock_settime(clockid_t clock,timespec_t * tp)2710Sstevel@tonic-gate clock_settime(clockid_t clock, timespec_t *tp)
2720Sstevel@tonic-gate {
2730Sstevel@tonic-gate timespec_t t;
2740Sstevel@tonic-gate clock_backend_t *backend;
2750Sstevel@tonic-gate int error;
2760Sstevel@tonic-gate
2770Sstevel@tonic-gate if ((backend = CLOCK_BACKEND(clock)) == NULL)
2780Sstevel@tonic-gate return (set_errno(EINVAL));
2790Sstevel@tonic-gate
2800Sstevel@tonic-gate if (secpolicy_settime(CRED()) != 0)
2810Sstevel@tonic-gate return (set_errno(EPERM));
2820Sstevel@tonic-gate
2830Sstevel@tonic-gate if (get_udatamodel() == DATAMODEL_NATIVE) {
2840Sstevel@tonic-gate if (copyin(tp, &t, sizeof (timespec_t)) != 0)
2850Sstevel@tonic-gate return (set_errno(EFAULT));
2860Sstevel@tonic-gate } else {
2870Sstevel@tonic-gate timespec32_t t32;
2880Sstevel@tonic-gate
2890Sstevel@tonic-gate if (copyin(tp, &t32, sizeof (timespec32_t)) != 0)
2900Sstevel@tonic-gate return (set_errno(EFAULT));
2910Sstevel@tonic-gate
2920Sstevel@tonic-gate TIMESPEC32_TO_TIMESPEC(&t, &t32);
2930Sstevel@tonic-gate }
2940Sstevel@tonic-gate
2950Sstevel@tonic-gate if (itimerspecfix(&t))
2960Sstevel@tonic-gate return (set_errno(EINVAL));
2970Sstevel@tonic-gate
2980Sstevel@tonic-gate error = backend->clk_clock_settime(&t);
2990Sstevel@tonic-gate
3000Sstevel@tonic-gate if (error)
3010Sstevel@tonic-gate return (set_errno(error));
3020Sstevel@tonic-gate
3030Sstevel@tonic-gate return (0);
3040Sstevel@tonic-gate }
3050Sstevel@tonic-gate
3060Sstevel@tonic-gate int
clock_gettime(clockid_t clock,timespec_t * tp)3070Sstevel@tonic-gate clock_gettime(clockid_t clock, timespec_t *tp)
3080Sstevel@tonic-gate {
3090Sstevel@tonic-gate timespec_t t;
3100Sstevel@tonic-gate clock_backend_t *backend;
3110Sstevel@tonic-gate int error;
3120Sstevel@tonic-gate
3130Sstevel@tonic-gate if ((backend = CLOCK_BACKEND(clock)) == NULL)
3140Sstevel@tonic-gate return (set_errno(EINVAL));
3150Sstevel@tonic-gate
3160Sstevel@tonic-gate error = backend->clk_clock_gettime(&t);
3170Sstevel@tonic-gate
3180Sstevel@tonic-gate if (error)
3190Sstevel@tonic-gate return (set_errno(error));
3200Sstevel@tonic-gate
3210Sstevel@tonic-gate if (get_udatamodel() == DATAMODEL_NATIVE) {
3220Sstevel@tonic-gate if (copyout(&t, tp, sizeof (timespec_t)) != 0)
3230Sstevel@tonic-gate return (set_errno(EFAULT));
3240Sstevel@tonic-gate } else {
3250Sstevel@tonic-gate timespec32_t t32;
3260Sstevel@tonic-gate
3270Sstevel@tonic-gate if (TIMESPEC_OVERFLOW(&t))
3280Sstevel@tonic-gate return (set_errno(EOVERFLOW));
3290Sstevel@tonic-gate TIMESPEC_TO_TIMESPEC32(&t32, &t);
3300Sstevel@tonic-gate
3310Sstevel@tonic-gate if (copyout(&t32, tp, sizeof (timespec32_t)) != 0)
3320Sstevel@tonic-gate return (set_errno(EFAULT));
3330Sstevel@tonic-gate }
3340Sstevel@tonic-gate
3350Sstevel@tonic-gate return (0);
3360Sstevel@tonic-gate }
3370Sstevel@tonic-gate
3380Sstevel@tonic-gate int
clock_getres(clockid_t clock,timespec_t * tp)3390Sstevel@tonic-gate clock_getres(clockid_t clock, timespec_t *tp)
3400Sstevel@tonic-gate {
3410Sstevel@tonic-gate timespec_t t;
3420Sstevel@tonic-gate clock_backend_t *backend;
3430Sstevel@tonic-gate int error;
3440Sstevel@tonic-gate
3450Sstevel@tonic-gate /*
3460Sstevel@tonic-gate * Strangely, the standard defines clock_getres() with a NULL tp
3470Sstevel@tonic-gate * to do nothing (regardless of the validity of the specified
3480Sstevel@tonic-gate * clock_id). Go figure.
3490Sstevel@tonic-gate */
3500Sstevel@tonic-gate if (tp == NULL)
3510Sstevel@tonic-gate return (0);
3520Sstevel@tonic-gate
3530Sstevel@tonic-gate if ((backend = CLOCK_BACKEND(clock)) == NULL)
3540Sstevel@tonic-gate return (set_errno(EINVAL));
3550Sstevel@tonic-gate
3560Sstevel@tonic-gate error = backend->clk_clock_getres(&t);
3570Sstevel@tonic-gate
3580Sstevel@tonic-gate if (error)
3590Sstevel@tonic-gate return (set_errno(error));
3600Sstevel@tonic-gate
3610Sstevel@tonic-gate if (get_udatamodel() == DATAMODEL_NATIVE) {
3620Sstevel@tonic-gate if (copyout(&t, tp, sizeof (timespec_t)) != 0)
3630Sstevel@tonic-gate return (set_errno(EFAULT));
3640Sstevel@tonic-gate } else {
3650Sstevel@tonic-gate timespec32_t t32;
3660Sstevel@tonic-gate
3670Sstevel@tonic-gate if (TIMESPEC_OVERFLOW(&t))
3680Sstevel@tonic-gate return (set_errno(EOVERFLOW));
3690Sstevel@tonic-gate TIMESPEC_TO_TIMESPEC32(&t32, &t);
3700Sstevel@tonic-gate
3710Sstevel@tonic-gate if (copyout(&t32, tp, sizeof (timespec32_t)) != 0)
3720Sstevel@tonic-gate return (set_errno(EFAULT));
3730Sstevel@tonic-gate }
3740Sstevel@tonic-gate
3750Sstevel@tonic-gate return (0);
3760Sstevel@tonic-gate }
3770Sstevel@tonic-gate
3780Sstevel@tonic-gate void
timer_signal(sigqueue_t * sigq)3790Sstevel@tonic-gate timer_signal(sigqueue_t *sigq)
3800Sstevel@tonic-gate {
3810Sstevel@tonic-gate itimer_t *it = (itimer_t *)sigq->sq_backptr;
3820Sstevel@tonic-gate
3830Sstevel@tonic-gate /*
3840Sstevel@tonic-gate * There are some conditions during a fork or an exit when we can
3850Sstevel@tonic-gate * call siginfofree() without p_lock held. To prevent a race
3860Sstevel@tonic-gate * between timer_signal() and timer_fire() with regard to it_pending,
3870Sstevel@tonic-gate * we therefore acquire it_mutex in both paths.
3880Sstevel@tonic-gate */
3890Sstevel@tonic-gate mutex_enter(&it->it_mutex);
3900Sstevel@tonic-gate ASSERT(it->it_pending > 0);
3910Sstevel@tonic-gate it->it_overrun = it->it_pending - 1;
3920Sstevel@tonic-gate it->it_pending = 0;
3930Sstevel@tonic-gate mutex_exit(&it->it_mutex);
3940Sstevel@tonic-gate }
3950Sstevel@tonic-gate
3960Sstevel@tonic-gate /*
3970Sstevel@tonic-gate * This routine is called from the clock backend.
3980Sstevel@tonic-gate */
3990Sstevel@tonic-gate void
timer_fire(itimer_t * it)4000Sstevel@tonic-gate timer_fire(itimer_t *it)
4010Sstevel@tonic-gate {
4020Sstevel@tonic-gate proc_t *p;
4030Sstevel@tonic-gate int proc_lock_held;
4040Sstevel@tonic-gate
4050Sstevel@tonic-gate if (it->it_flags & IT_SIGNAL) {
4060Sstevel@tonic-gate /*
4070Sstevel@tonic-gate * See the comment in timer_signal() for why it is not
4080Sstevel@tonic-gate * sufficient to only grab p_lock here. Because p_lock can be
4090Sstevel@tonic-gate * held on entry to timer_signal(), the lock ordering is
4100Sstevel@tonic-gate * necessarily p_lock before it_mutex.
4110Sstevel@tonic-gate */
4120Sstevel@tonic-gate
4130Sstevel@tonic-gate p = it->it_proc;
4140Sstevel@tonic-gate proc_lock_held = 1;
4150Sstevel@tonic-gate mutex_enter(&p->p_lock);
4160Sstevel@tonic-gate } else {
4170Sstevel@tonic-gate /*
4180Sstevel@tonic-gate * IT_PORT:
4190Sstevel@tonic-gate * If a timer was ever programmed to send events to a port,
4200Sstevel@tonic-gate * the IT_PORT flag will remain set until:
4210Sstevel@tonic-gate * a) the timer is deleted (see timer_delete_locked()) or
4220Sstevel@tonic-gate * b) the port is being closed (see timer_close_port()).
4230Sstevel@tonic-gate * Both cases are synchronized with the it_mutex.
4240Sstevel@tonic-gate * We don't need to use the p_lock because it is only
4250Sstevel@tonic-gate * required in the IT_SIGNAL case.
4260Sstevel@tonic-gate * If IT_PORT was set and the port is being closed then
4270Sstevel@tonic-gate * the timer notification is set to NONE. In such a case
4280Sstevel@tonic-gate * the timer itself and the it_pending counter remain active
4290Sstevel@tonic-gate * until the application deletes the counter or the process
4300Sstevel@tonic-gate * exits.
4310Sstevel@tonic-gate */
4320Sstevel@tonic-gate proc_lock_held = 0;
4330Sstevel@tonic-gate }
4340Sstevel@tonic-gate mutex_enter(&it->it_mutex);
4350Sstevel@tonic-gate
4360Sstevel@tonic-gate if (it->it_pending > 0) {
4370Sstevel@tonic-gate if (it->it_pending < INT_MAX)
4380Sstevel@tonic-gate it->it_pending++;
4390Sstevel@tonic-gate mutex_exit(&it->it_mutex);
4400Sstevel@tonic-gate } else {
4410Sstevel@tonic-gate if (it->it_flags & IT_PORT) {
4420Sstevel@tonic-gate it->it_pending = 1;
4431885Sraf port_send_event((port_kevent_t *)it->it_portev);
4440Sstevel@tonic-gate mutex_exit(&it->it_mutex);
4450Sstevel@tonic-gate } else if (it->it_flags & IT_SIGNAL) {
4460Sstevel@tonic-gate it->it_pending = 1;
4470Sstevel@tonic-gate mutex_exit(&it->it_mutex);
4480Sstevel@tonic-gate sigaddqa(p, NULL, it->it_sigq);
4490Sstevel@tonic-gate } else {
4500Sstevel@tonic-gate mutex_exit(&it->it_mutex);
4510Sstevel@tonic-gate }
4520Sstevel@tonic-gate }
4530Sstevel@tonic-gate
4540Sstevel@tonic-gate if (proc_lock_held)
4550Sstevel@tonic-gate mutex_exit(&p->p_lock);
4560Sstevel@tonic-gate }
4570Sstevel@tonic-gate
4580Sstevel@tonic-gate int
timer_create(clockid_t clock,struct sigevent * evp,timer_t * tid)4590Sstevel@tonic-gate timer_create(clockid_t clock, struct sigevent *evp, timer_t *tid)
4600Sstevel@tonic-gate {
4610Sstevel@tonic-gate struct sigevent ev;
4620Sstevel@tonic-gate proc_t *p = curproc;
4630Sstevel@tonic-gate clock_backend_t *backend;
4640Sstevel@tonic-gate itimer_t *it, **itp;
4650Sstevel@tonic-gate sigqueue_t *sigq;
4660Sstevel@tonic-gate cred_t *cr = CRED();
4670Sstevel@tonic-gate int error = 0;
4680Sstevel@tonic-gate timer_t i;
4690Sstevel@tonic-gate port_notify_t tim_pnevp;
4700Sstevel@tonic-gate port_kevent_t *pkevp = NULL;
4710Sstevel@tonic-gate
4720Sstevel@tonic-gate if ((backend = CLOCK_BACKEND(clock)) == NULL)
4730Sstevel@tonic-gate return (set_errno(EINVAL));
4740Sstevel@tonic-gate
4750Sstevel@tonic-gate if (evp != NULL) {
4760Sstevel@tonic-gate /*
4770Sstevel@tonic-gate * short copyin() for binary compatibility
4780Sstevel@tonic-gate * fetch oldsigevent to determine how much to copy in.
4790Sstevel@tonic-gate */
4800Sstevel@tonic-gate if (get_udatamodel() == DATAMODEL_NATIVE) {
4810Sstevel@tonic-gate if (copyin(evp, &ev, sizeof (struct oldsigevent)))
4820Sstevel@tonic-gate return (set_errno(EFAULT));
4830Sstevel@tonic-gate
4841885Sraf if (ev.sigev_notify == SIGEV_PORT ||
4851885Sraf ev.sigev_notify == SIGEV_THREAD) {
4860Sstevel@tonic-gate if (copyin(ev.sigev_value.sival_ptr, &tim_pnevp,
4870Sstevel@tonic-gate sizeof (port_notify_t)))
4880Sstevel@tonic-gate return (set_errno(EFAULT));
4890Sstevel@tonic-gate }
4900Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
4910Sstevel@tonic-gate } else {
4920Sstevel@tonic-gate struct sigevent32 ev32;
4930Sstevel@tonic-gate port_notify32_t tim_pnevp32;
4940Sstevel@tonic-gate
4950Sstevel@tonic-gate if (copyin(evp, &ev32, sizeof (struct oldsigevent32)))
4960Sstevel@tonic-gate return (set_errno(EFAULT));
4970Sstevel@tonic-gate ev.sigev_notify = ev32.sigev_notify;
4980Sstevel@tonic-gate ev.sigev_signo = ev32.sigev_signo;
4990Sstevel@tonic-gate /*
5000Sstevel@tonic-gate * See comment in sigqueue32() on handling of 32-bit
5010Sstevel@tonic-gate * sigvals in a 64-bit kernel.
5020Sstevel@tonic-gate */
5030Sstevel@tonic-gate ev.sigev_value.sival_int = ev32.sigev_value.sival_int;
5041885Sraf if (ev.sigev_notify == SIGEV_PORT ||
5051885Sraf ev.sigev_notify == SIGEV_THREAD) {
5060Sstevel@tonic-gate if (copyin((void *)(uintptr_t)
5070Sstevel@tonic-gate ev32.sigev_value.sival_ptr,
5080Sstevel@tonic-gate (void *)&tim_pnevp32,
5090Sstevel@tonic-gate sizeof (port_notify32_t)))
5100Sstevel@tonic-gate return (set_errno(EFAULT));
5110Sstevel@tonic-gate tim_pnevp.portnfy_port =
5120Sstevel@tonic-gate tim_pnevp32.portnfy_port;
5130Sstevel@tonic-gate tim_pnevp.portnfy_user =
5140Sstevel@tonic-gate (void *)(uintptr_t)tim_pnevp32.portnfy_user;
5150Sstevel@tonic-gate }
5160Sstevel@tonic-gate #endif
5170Sstevel@tonic-gate }
5180Sstevel@tonic-gate switch (ev.sigev_notify) {
5190Sstevel@tonic-gate case SIGEV_NONE:
5200Sstevel@tonic-gate break;
5210Sstevel@tonic-gate case SIGEV_SIGNAL:
5220Sstevel@tonic-gate if (ev.sigev_signo < 1 || ev.sigev_signo >= NSIG)
5230Sstevel@tonic-gate return (set_errno(EINVAL));
5240Sstevel@tonic-gate break;
5251885Sraf case SIGEV_THREAD:
5260Sstevel@tonic-gate case SIGEV_PORT:
5270Sstevel@tonic-gate break;
5280Sstevel@tonic-gate default:
5290Sstevel@tonic-gate return (set_errno(EINVAL));
5300Sstevel@tonic-gate }
5310Sstevel@tonic-gate } else {
5320Sstevel@tonic-gate /*
5330Sstevel@tonic-gate * Use the clock's default sigevent (this is a structure copy).
5340Sstevel@tonic-gate */
5350Sstevel@tonic-gate ev = backend->clk_default;
5360Sstevel@tonic-gate }
5370Sstevel@tonic-gate
5380Sstevel@tonic-gate /*
5390Sstevel@tonic-gate * We'll allocate our timer and sigqueue now, before we grab p_lock.
5400Sstevel@tonic-gate * If we can't find an empty slot, we'll free them before returning.
5410Sstevel@tonic-gate */
5420Sstevel@tonic-gate it = kmem_cache_alloc(clock_timer_cache, KM_SLEEP);
5430Sstevel@tonic-gate bzero(it, sizeof (itimer_t));
5440Sstevel@tonic-gate mutex_init(&it->it_mutex, NULL, MUTEX_DEFAULT, NULL);
5450Sstevel@tonic-gate sigq = kmem_zalloc(sizeof (sigqueue_t), KM_SLEEP);
5460Sstevel@tonic-gate
5470Sstevel@tonic-gate mutex_enter(&p->p_lock);
5480Sstevel@tonic-gate
5490Sstevel@tonic-gate /*
5500Sstevel@tonic-gate * If this is this process' first timer, we need to attempt to allocate
5510Sstevel@tonic-gate * an array of timerstr_t pointers. We drop p_lock to perform the
5520Sstevel@tonic-gate * allocation; if we return to discover that p_itimer is non-NULL,
5530Sstevel@tonic-gate * we will free our allocation and drive on.
5540Sstevel@tonic-gate */
5550Sstevel@tonic-gate if ((itp = p->p_itimer) == NULL) {
5560Sstevel@tonic-gate mutex_exit(&p->p_lock);
5570Sstevel@tonic-gate itp = kmem_zalloc(timer_max * sizeof (itimer_t *), KM_SLEEP);
5580Sstevel@tonic-gate mutex_enter(&p->p_lock);
5590Sstevel@tonic-gate
5600Sstevel@tonic-gate if (p->p_itimer == NULL)
5610Sstevel@tonic-gate p->p_itimer = itp;
5620Sstevel@tonic-gate else {
5630Sstevel@tonic-gate kmem_free(itp, timer_max * sizeof (itimer_t *));
5640Sstevel@tonic-gate itp = p->p_itimer;
5650Sstevel@tonic-gate }
5660Sstevel@tonic-gate }
5670Sstevel@tonic-gate
5680Sstevel@tonic-gate for (i = 0; i < timer_max && itp[i] != NULL; i++)
5690Sstevel@tonic-gate continue;
5700Sstevel@tonic-gate
5710Sstevel@tonic-gate if (i == timer_max) {
5720Sstevel@tonic-gate /*
5730Sstevel@tonic-gate * We couldn't find a slot. Drop p_lock, free the preallocated
5740Sstevel@tonic-gate * timer and sigqueue, and return an error.
5750Sstevel@tonic-gate */
5760Sstevel@tonic-gate mutex_exit(&p->p_lock);
5770Sstevel@tonic-gate kmem_cache_free(clock_timer_cache, it);
5780Sstevel@tonic-gate kmem_free(sigq, sizeof (sigqueue_t));
5790Sstevel@tonic-gate
5800Sstevel@tonic-gate return (set_errno(EAGAIN));
5810Sstevel@tonic-gate }
5820Sstevel@tonic-gate
5830Sstevel@tonic-gate ASSERT(i < timer_max && itp[i] == NULL);
5840Sstevel@tonic-gate
5850Sstevel@tonic-gate /*
5860Sstevel@tonic-gate * If we develop other notification mechanisms, this will need
5870Sstevel@tonic-gate * to call into (yet another) backend.
5880Sstevel@tonic-gate */
5890Sstevel@tonic-gate sigq->sq_info.si_signo = ev.sigev_signo;
5901885Sraf if (evp == NULL)
5911885Sraf sigq->sq_info.si_value.sival_int = i;
5921885Sraf else
5931885Sraf sigq->sq_info.si_value = ev.sigev_value;
5940Sstevel@tonic-gate sigq->sq_info.si_code = SI_TIMER;
5950Sstevel@tonic-gate sigq->sq_info.si_pid = p->p_pid;
5960Sstevel@tonic-gate sigq->sq_info.si_ctid = PRCTID(p);
5970Sstevel@tonic-gate sigq->sq_info.si_zoneid = getzoneid();
5980Sstevel@tonic-gate sigq->sq_info.si_uid = crgetruid(cr);
5990Sstevel@tonic-gate sigq->sq_func = timer_signal;
6000Sstevel@tonic-gate sigq->sq_next = NULL;
6010Sstevel@tonic-gate sigq->sq_backptr = it;
6020Sstevel@tonic-gate it->it_sigq = sigq;
6030Sstevel@tonic-gate it->it_backend = backend;
6040Sstevel@tonic-gate it->it_lock = ITLK_LOCKED;
6050Sstevel@tonic-gate itp[i] = it;
6060Sstevel@tonic-gate
6070Sstevel@tonic-gate
6081885Sraf if (ev.sigev_notify == SIGEV_THREAD ||
6091885Sraf ev.sigev_notify == SIGEV_PORT) {
6100Sstevel@tonic-gate int port;
6110Sstevel@tonic-gate
6120Sstevel@tonic-gate /*
6130Sstevel@tonic-gate * This timer is programmed to use event port notification when
6140Sstevel@tonic-gate * the timer fires:
6150Sstevel@tonic-gate * - allocate a port event structure and prepare it to be sent
6160Sstevel@tonic-gate * to the port as soon as the timer fires.
6170Sstevel@tonic-gate * - when the timer fires :
6180Sstevel@tonic-gate * - if event structure was already sent to the port then this
6190Sstevel@tonic-gate * is a timer fire overflow => increment overflow counter.
6200Sstevel@tonic-gate * - otherwise send pre-allocated event structure to the port.
6210Sstevel@tonic-gate * - the events field of the port_event_t structure counts the
6220Sstevel@tonic-gate * number of timer fired events.
6230Sstevel@tonic-gate * - The event structured is allocated using the
6240Sstevel@tonic-gate * PORT_ALLOC_CACHED flag.
6250Sstevel@tonic-gate * This flag indicates that the timer itself will manage and
6260Sstevel@tonic-gate * free the event structure when required.
6270Sstevel@tonic-gate */
6280Sstevel@tonic-gate
6290Sstevel@tonic-gate it->it_flags |= IT_PORT;
6300Sstevel@tonic-gate port = tim_pnevp.portnfy_port;
6310Sstevel@tonic-gate
6320Sstevel@tonic-gate /* associate timer as event source with the port */
6330Sstevel@tonic-gate error = port_associate_ksource(port, PORT_SOURCE_TIMER,
6340Sstevel@tonic-gate (port_source_t **)&it->it_portsrc, timer_close_port,
6350Sstevel@tonic-gate (void *)it, NULL);
6360Sstevel@tonic-gate if (error) {
6370Sstevel@tonic-gate itp[i] = NULL; /* clear slot */
6380Sstevel@tonic-gate mutex_exit(&p->p_lock);
6390Sstevel@tonic-gate kmem_cache_free(clock_timer_cache, it);
6400Sstevel@tonic-gate kmem_free(sigq, sizeof (sigqueue_t));
6410Sstevel@tonic-gate return (set_errno(error));
6420Sstevel@tonic-gate }
6430Sstevel@tonic-gate
6440Sstevel@tonic-gate /* allocate an event structure/slot */
6450Sstevel@tonic-gate error = port_alloc_event(port, PORT_ALLOC_SCACHED,
6460Sstevel@tonic-gate PORT_SOURCE_TIMER, &pkevp);
6470Sstevel@tonic-gate if (error) {
6480Sstevel@tonic-gate (void) port_dissociate_ksource(port, PORT_SOURCE_TIMER,
6490Sstevel@tonic-gate (port_source_t *)it->it_portsrc);
6500Sstevel@tonic-gate itp[i] = NULL; /* clear slot */
6510Sstevel@tonic-gate mutex_exit(&p->p_lock);
6520Sstevel@tonic-gate kmem_cache_free(clock_timer_cache, it);
6530Sstevel@tonic-gate kmem_free(sigq, sizeof (sigqueue_t));
6540Sstevel@tonic-gate return (set_errno(error));
6550Sstevel@tonic-gate }
6560Sstevel@tonic-gate
6570Sstevel@tonic-gate /* initialize event data */
6580Sstevel@tonic-gate port_init_event(pkevp, i, tim_pnevp.portnfy_user,
6590Sstevel@tonic-gate timer_port_callback, it);
6600Sstevel@tonic-gate it->it_portev = pkevp;
6610Sstevel@tonic-gate it->it_portfd = port;
6620Sstevel@tonic-gate } else {
6630Sstevel@tonic-gate if (ev.sigev_notify == SIGEV_SIGNAL)
6640Sstevel@tonic-gate it->it_flags |= IT_SIGNAL;
6650Sstevel@tonic-gate }
6660Sstevel@tonic-gate
6670Sstevel@tonic-gate mutex_exit(&p->p_lock);
6680Sstevel@tonic-gate
6690Sstevel@tonic-gate /*
6700Sstevel@tonic-gate * Call on the backend to verify the event argument (or return
6710Sstevel@tonic-gate * EINVAL if this clock type does not support timers).
6720Sstevel@tonic-gate */
6730Sstevel@tonic-gate if ((error = backend->clk_timer_create(it, &ev)) != 0)
6740Sstevel@tonic-gate goto err;
6750Sstevel@tonic-gate
6760Sstevel@tonic-gate it->it_lwp = ttolwp(curthread);
6770Sstevel@tonic-gate it->it_proc = p;
6780Sstevel@tonic-gate
6790Sstevel@tonic-gate if (copyout(&i, tid, sizeof (timer_t)) != 0) {
6800Sstevel@tonic-gate error = EFAULT;
6810Sstevel@tonic-gate goto err;
6820Sstevel@tonic-gate }
6830Sstevel@tonic-gate
6840Sstevel@tonic-gate /*
6850Sstevel@tonic-gate * If we're here, then we have successfully created the timer; we
6860Sstevel@tonic-gate * just need to release the timer and return.
6870Sstevel@tonic-gate */
6880Sstevel@tonic-gate timer_release(p, it);
6890Sstevel@tonic-gate
6900Sstevel@tonic-gate return (0);
6910Sstevel@tonic-gate
6920Sstevel@tonic-gate err:
6930Sstevel@tonic-gate /*
6940Sstevel@tonic-gate * If we're here, an error has occurred late in the timer creation
6950Sstevel@tonic-gate * process. We need to regrab p_lock, and delete the incipient timer.
6960Sstevel@tonic-gate * Since we never unlocked the timer (it was born locked), it's
6970Sstevel@tonic-gate * impossible for a removal to be pending.
6980Sstevel@tonic-gate */
6990Sstevel@tonic-gate ASSERT(!(it->it_lock & ITLK_REMOVE));
7000Sstevel@tonic-gate timer_delete_grabbed(p, i, it);
7010Sstevel@tonic-gate
7020Sstevel@tonic-gate return (set_errno(error));
7030Sstevel@tonic-gate }
7040Sstevel@tonic-gate
7050Sstevel@tonic-gate int
timer_gettime(timer_t tid,itimerspec_t * val)7060Sstevel@tonic-gate timer_gettime(timer_t tid, itimerspec_t *val)
7070Sstevel@tonic-gate {
7080Sstevel@tonic-gate proc_t *p = curproc;
7090Sstevel@tonic-gate itimer_t *it;
7100Sstevel@tonic-gate itimerspec_t when;
7110Sstevel@tonic-gate int error;
7120Sstevel@tonic-gate
7130Sstevel@tonic-gate if ((it = timer_grab(p, tid)) == NULL)
7140Sstevel@tonic-gate return (set_errno(EINVAL));
7150Sstevel@tonic-gate
7160Sstevel@tonic-gate error = it->it_backend->clk_timer_gettime(it, &when);
7170Sstevel@tonic-gate
7180Sstevel@tonic-gate timer_release(p, it);
7190Sstevel@tonic-gate
7200Sstevel@tonic-gate if (error == 0) {
7210Sstevel@tonic-gate if (get_udatamodel() == DATAMODEL_NATIVE) {
7220Sstevel@tonic-gate if (copyout(&when, val, sizeof (itimerspec_t)))
7230Sstevel@tonic-gate error = EFAULT;
7240Sstevel@tonic-gate } else {
7250Sstevel@tonic-gate if (ITIMERSPEC_OVERFLOW(&when))
7260Sstevel@tonic-gate error = EOVERFLOW;
7270Sstevel@tonic-gate else {
7280Sstevel@tonic-gate itimerspec32_t w32;
7290Sstevel@tonic-gate
7300Sstevel@tonic-gate ITIMERSPEC_TO_ITIMERSPEC32(&w32, &when)
7310Sstevel@tonic-gate if (copyout(&w32, val, sizeof (itimerspec32_t)))
7320Sstevel@tonic-gate error = EFAULT;
7330Sstevel@tonic-gate }
7340Sstevel@tonic-gate }
7350Sstevel@tonic-gate }
7360Sstevel@tonic-gate
7370Sstevel@tonic-gate return (error ? set_errno(error) : 0);
7380Sstevel@tonic-gate }
7390Sstevel@tonic-gate
7400Sstevel@tonic-gate int
timer_settime(timer_t tid,int flags,itimerspec_t * val,itimerspec_t * oval)7410Sstevel@tonic-gate timer_settime(timer_t tid, int flags, itimerspec_t *val, itimerspec_t *oval)
7420Sstevel@tonic-gate {
7430Sstevel@tonic-gate itimerspec_t when;
7440Sstevel@tonic-gate timespec_t res;
7450Sstevel@tonic-gate itimer_t *it;
7460Sstevel@tonic-gate proc_t *p = curproc;
7470Sstevel@tonic-gate int error;
7480Sstevel@tonic-gate
7490Sstevel@tonic-gate if (oval != NULL) {
7500Sstevel@tonic-gate if ((error = timer_gettime(tid, oval)) != 0)
7510Sstevel@tonic-gate return (error);
7520Sstevel@tonic-gate }
7530Sstevel@tonic-gate
7540Sstevel@tonic-gate if (get_udatamodel() == DATAMODEL_NATIVE) {
7550Sstevel@tonic-gate if (copyin(val, &when, sizeof (itimerspec_t)))
7560Sstevel@tonic-gate return (set_errno(EFAULT));
7570Sstevel@tonic-gate } else {
7580Sstevel@tonic-gate itimerspec32_t w32;
7590Sstevel@tonic-gate
7600Sstevel@tonic-gate if (copyin(val, &w32, sizeof (itimerspec32_t)))
7610Sstevel@tonic-gate return (set_errno(EFAULT));
7620Sstevel@tonic-gate
7630Sstevel@tonic-gate ITIMERSPEC32_TO_ITIMERSPEC(&when, &w32);
7640Sstevel@tonic-gate }
7650Sstevel@tonic-gate
7660Sstevel@tonic-gate if (itimerspecfix(&when.it_value) ||
7670Sstevel@tonic-gate (itimerspecfix(&when.it_interval) &&
7680Sstevel@tonic-gate timerspecisset(&when.it_value))) {
7690Sstevel@tonic-gate return (set_errno(EINVAL));
7700Sstevel@tonic-gate }
7710Sstevel@tonic-gate
7720Sstevel@tonic-gate if ((it = timer_grab(p, tid)) == NULL)
7730Sstevel@tonic-gate return (set_errno(EINVAL));
7740Sstevel@tonic-gate
7750Sstevel@tonic-gate /*
7760Sstevel@tonic-gate * From the man page:
7770Sstevel@tonic-gate * Time values that are between two consecutive non-negative
7780Sstevel@tonic-gate * integer multiples of the resolution of the specified timer
7790Sstevel@tonic-gate * shall be rounded up to the larger multiple of the resolution.
7800Sstevel@tonic-gate * We assume that the resolution of any clock is less than one second.
7810Sstevel@tonic-gate */
7820Sstevel@tonic-gate if (it->it_backend->clk_clock_getres(&res) == 0 && res.tv_nsec > 1) {
7830Sstevel@tonic-gate long rem;
7840Sstevel@tonic-gate
7850Sstevel@tonic-gate if ((rem = when.it_interval.tv_nsec % res.tv_nsec) != 0) {
7860Sstevel@tonic-gate when.it_interval.tv_nsec += res.tv_nsec - rem;
7870Sstevel@tonic-gate timespecfix(&when.it_interval);
7880Sstevel@tonic-gate }
7890Sstevel@tonic-gate if ((rem = when.it_value.tv_nsec % res.tv_nsec) != 0) {
7900Sstevel@tonic-gate when.it_value.tv_nsec += res.tv_nsec - rem;
7910Sstevel@tonic-gate timespecfix(&when.it_value);
7920Sstevel@tonic-gate }
7930Sstevel@tonic-gate }
7940Sstevel@tonic-gate error = it->it_backend->clk_timer_settime(it, flags, &when);
7950Sstevel@tonic-gate
7960Sstevel@tonic-gate timer_release(p, it);
7970Sstevel@tonic-gate
7980Sstevel@tonic-gate return (error ? set_errno(error) : 0);
7990Sstevel@tonic-gate }
8000Sstevel@tonic-gate
8010Sstevel@tonic-gate int
timer_delete(timer_t tid)8020Sstevel@tonic-gate timer_delete(timer_t tid)
8030Sstevel@tonic-gate {
8040Sstevel@tonic-gate proc_t *p = curproc;
8050Sstevel@tonic-gate itimer_t *it;
8060Sstevel@tonic-gate
8070Sstevel@tonic-gate if ((it = timer_grab(p, tid)) == NULL)
8080Sstevel@tonic-gate return (set_errno(EINVAL));
8090Sstevel@tonic-gate
8100Sstevel@tonic-gate timer_delete_grabbed(p, tid, it);
8110Sstevel@tonic-gate
8120Sstevel@tonic-gate return (0);
8130Sstevel@tonic-gate }
8140Sstevel@tonic-gate
8150Sstevel@tonic-gate int
timer_getoverrun(timer_t tid)8160Sstevel@tonic-gate timer_getoverrun(timer_t tid)
8170Sstevel@tonic-gate {
8180Sstevel@tonic-gate int overrun;
8190Sstevel@tonic-gate proc_t *p = curproc;
8200Sstevel@tonic-gate itimer_t *it;
8210Sstevel@tonic-gate
8220Sstevel@tonic-gate if ((it = timer_grab(p, tid)) == NULL)
8230Sstevel@tonic-gate return (set_errno(EINVAL));
8240Sstevel@tonic-gate
8250Sstevel@tonic-gate /*
8260Sstevel@tonic-gate * The it_overrun field is protected by p_lock; we need to acquire
8270Sstevel@tonic-gate * it before looking at the value.
8280Sstevel@tonic-gate */
8290Sstevel@tonic-gate mutex_enter(&p->p_lock);
8300Sstevel@tonic-gate overrun = it->it_overrun;
8310Sstevel@tonic-gate mutex_exit(&p->p_lock);
8320Sstevel@tonic-gate
8330Sstevel@tonic-gate timer_release(p, it);
8340Sstevel@tonic-gate
8350Sstevel@tonic-gate return (overrun);
8360Sstevel@tonic-gate }
8370Sstevel@tonic-gate
8380Sstevel@tonic-gate /*
8390Sstevel@tonic-gate * Entered/exited with p_lock held, but will repeatedly drop and regrab p_lock.
8400Sstevel@tonic-gate */
8410Sstevel@tonic-gate void
timer_lwpexit(void)8420Sstevel@tonic-gate timer_lwpexit(void)
8430Sstevel@tonic-gate {
8440Sstevel@tonic-gate timer_t i;
8450Sstevel@tonic-gate proc_t *p = curproc;
8460Sstevel@tonic-gate klwp_t *lwp = ttolwp(curthread);
8470Sstevel@tonic-gate itimer_t *it, **itp;
8480Sstevel@tonic-gate
8490Sstevel@tonic-gate ASSERT(MUTEX_HELD(&p->p_lock));
8500Sstevel@tonic-gate
8510Sstevel@tonic-gate if ((itp = p->p_itimer) == NULL)
8520Sstevel@tonic-gate return;
8530Sstevel@tonic-gate
8540Sstevel@tonic-gate for (i = 0; i < timer_max; i++) {
8550Sstevel@tonic-gate if ((it = itp[i]) == NULL)
8560Sstevel@tonic-gate continue;
8570Sstevel@tonic-gate
8580Sstevel@tonic-gate timer_lock(p, it);
8590Sstevel@tonic-gate
8600Sstevel@tonic-gate if ((it->it_lock & ITLK_REMOVE) || it->it_lwp != lwp) {
8610Sstevel@tonic-gate /*
8620Sstevel@tonic-gate * This timer is either being removed or it isn't
8630Sstevel@tonic-gate * associated with this lwp.
8640Sstevel@tonic-gate */
8650Sstevel@tonic-gate timer_unlock(p, it);
8660Sstevel@tonic-gate continue;
8670Sstevel@tonic-gate }
8680Sstevel@tonic-gate
8690Sstevel@tonic-gate /*
8700Sstevel@tonic-gate * The LWP that created this timer is going away. To the user,
8710Sstevel@tonic-gate * our behavior here is explicitly undefined. We will simply
8720Sstevel@tonic-gate * null out the it_lwp field; if the LWP was bound to a CPU,
8730Sstevel@tonic-gate * the cyclic will stay bound to that CPU until the process
8740Sstevel@tonic-gate * exits.
8750Sstevel@tonic-gate */
8760Sstevel@tonic-gate it->it_lwp = NULL;
8770Sstevel@tonic-gate timer_unlock(p, it);
8780Sstevel@tonic-gate }
8790Sstevel@tonic-gate }
8800Sstevel@tonic-gate
8810Sstevel@tonic-gate /*
8820Sstevel@tonic-gate * Called to notify of an LWP binding change. Entered/exited with p_lock
8830Sstevel@tonic-gate * held, but will repeatedly drop and regrab p_lock.
8840Sstevel@tonic-gate */
8850Sstevel@tonic-gate void
timer_lwpbind()8860Sstevel@tonic-gate timer_lwpbind()
8870Sstevel@tonic-gate {
8880Sstevel@tonic-gate timer_t i;
8890Sstevel@tonic-gate proc_t *p = curproc;
8900Sstevel@tonic-gate klwp_t *lwp = ttolwp(curthread);
8910Sstevel@tonic-gate itimer_t *it, **itp;
8920Sstevel@tonic-gate
8930Sstevel@tonic-gate ASSERT(MUTEX_HELD(&p->p_lock));
8940Sstevel@tonic-gate
8950Sstevel@tonic-gate if ((itp = p->p_itimer) == NULL)
8960Sstevel@tonic-gate return;
8970Sstevel@tonic-gate
8980Sstevel@tonic-gate for (i = 0; i < timer_max; i++) {
8990Sstevel@tonic-gate if ((it = itp[i]) == NULL)
9000Sstevel@tonic-gate continue;
9010Sstevel@tonic-gate
9020Sstevel@tonic-gate timer_lock(p, it);
9030Sstevel@tonic-gate
9040Sstevel@tonic-gate if (!(it->it_lock & ITLK_REMOVE) && it->it_lwp == lwp) {
9050Sstevel@tonic-gate /*
9060Sstevel@tonic-gate * Drop p_lock and jump into the backend.
9070Sstevel@tonic-gate */
9080Sstevel@tonic-gate mutex_exit(&p->p_lock);
9090Sstevel@tonic-gate it->it_backend->clk_timer_lwpbind(it);
9100Sstevel@tonic-gate mutex_enter(&p->p_lock);
9110Sstevel@tonic-gate }
9120Sstevel@tonic-gate
9130Sstevel@tonic-gate timer_unlock(p, it);
9140Sstevel@tonic-gate }
9150Sstevel@tonic-gate }
9160Sstevel@tonic-gate
9170Sstevel@tonic-gate /*
9180Sstevel@tonic-gate * This function should only be called if p_itimer is non-NULL.
9190Sstevel@tonic-gate */
9200Sstevel@tonic-gate void
timer_exit(void)9210Sstevel@tonic-gate timer_exit(void)
9220Sstevel@tonic-gate {
9230Sstevel@tonic-gate timer_t i;
9240Sstevel@tonic-gate proc_t *p = curproc;
9250Sstevel@tonic-gate
9260Sstevel@tonic-gate ASSERT(p->p_itimer != NULL);
9270Sstevel@tonic-gate
9280Sstevel@tonic-gate for (i = 0; i < timer_max; i++)
9290Sstevel@tonic-gate (void) timer_delete(i);
9300Sstevel@tonic-gate
9310Sstevel@tonic-gate kmem_free(p->p_itimer, timer_max * sizeof (itimer_t *));
9320Sstevel@tonic-gate p->p_itimer = NULL;
9330Sstevel@tonic-gate }
9340Sstevel@tonic-gate
9350Sstevel@tonic-gate /*
9360Sstevel@tonic-gate * timer_port_callback() is a callback function which is associated with the
9370Sstevel@tonic-gate * timer event and is activated just before the event is delivered to the user.
9380Sstevel@tonic-gate * The timer uses this function to update/set the overflow counter and
9390Sstevel@tonic-gate * to reenable the use of the event structure.
9400Sstevel@tonic-gate */
9410Sstevel@tonic-gate
9420Sstevel@tonic-gate /* ARGSUSED */
9430Sstevel@tonic-gate static int
timer_port_callback(void * arg,int * events,pid_t pid,int flag,void * evp)9440Sstevel@tonic-gate timer_port_callback(void *arg, int *events, pid_t pid, int flag, void *evp)
9450Sstevel@tonic-gate {
9460Sstevel@tonic-gate itimer_t *it = arg;
9470Sstevel@tonic-gate
9480Sstevel@tonic-gate mutex_enter(&it->it_mutex);
9490Sstevel@tonic-gate if (curproc != it->it_proc) {
9500Sstevel@tonic-gate /* can not deliver timer events to another proc */
9510Sstevel@tonic-gate mutex_exit(&it->it_mutex);
9520Sstevel@tonic-gate return (EACCES);
9530Sstevel@tonic-gate }
9540Sstevel@tonic-gate *events = it->it_pending; /* 1 = 1 event, >1 # of overflows */
9550Sstevel@tonic-gate it->it_pending = 0; /* reinit overflow counter */
9560Sstevel@tonic-gate /*
9570Sstevel@tonic-gate * This function can also be activated when the port is being closed
9580Sstevel@tonic-gate * and a timer event is already submitted to the port.
9590Sstevel@tonic-gate * In such a case the event port framework will use the
9600Sstevel@tonic-gate * close-callback function to notify the events sources.
9610Sstevel@tonic-gate * The timer close-callback function is timer_close_port() which
9620Sstevel@tonic-gate * will free all allocated resources (including the allocated
9630Sstevel@tonic-gate * port event structure).
9640Sstevel@tonic-gate * For that reason we don't need to check the value of flag here.
9650Sstevel@tonic-gate */
9660Sstevel@tonic-gate mutex_exit(&it->it_mutex);
9670Sstevel@tonic-gate return (0);
9680Sstevel@tonic-gate }
9690Sstevel@tonic-gate
9700Sstevel@tonic-gate /*
9710Sstevel@tonic-gate * port is being closed ... free all allocated port event structures
9720Sstevel@tonic-gate * The delivered arg currently correspond to the first timer associated with
9730Sstevel@tonic-gate * the port and it is not useable in this case.
9740Sstevel@tonic-gate * We have to scan the list of activated timers in the current proc and
9750Sstevel@tonic-gate * compare them with the delivered port id.
9760Sstevel@tonic-gate */
9770Sstevel@tonic-gate
9780Sstevel@tonic-gate /* ARGSUSED */
9790Sstevel@tonic-gate static void
timer_close_port(void * arg,int port,pid_t pid,int lastclose)9800Sstevel@tonic-gate timer_close_port(void *arg, int port, pid_t pid, int lastclose)
9810Sstevel@tonic-gate {
9820Sstevel@tonic-gate proc_t *p = curproc;
9830Sstevel@tonic-gate timer_t tid;
9840Sstevel@tonic-gate itimer_t *it;
9850Sstevel@tonic-gate
9860Sstevel@tonic-gate for (tid = 0; tid < timer_max; tid++) {
9870Sstevel@tonic-gate if ((it = timer_grab(p, tid)) == NULL)
9880Sstevel@tonic-gate continue;
9890Sstevel@tonic-gate if (it->it_portev) {
9900Sstevel@tonic-gate mutex_enter(&it->it_mutex);
9910Sstevel@tonic-gate if (it->it_portfd == port) {
992*4915Spraks port_kevent_t *pev;
993*4915Spraks pev = (port_kevent_t *)it->it_portev;
9940Sstevel@tonic-gate it->it_portev = NULL;
9950Sstevel@tonic-gate it->it_flags &= ~IT_PORT;
996*4915Spraks mutex_exit(&it->it_mutex);
997*4915Spraks (void) port_remove_done_event(pev);
998*4915Spraks port_free_event(pev);
999*4915Spraks } else {
1000*4915Spraks mutex_exit(&it->it_mutex);
10010Sstevel@tonic-gate }
10020Sstevel@tonic-gate }
10030Sstevel@tonic-gate timer_release(p, it);
10040Sstevel@tonic-gate }
10050Sstevel@tonic-gate }
1006