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