1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START 3*7c478bd9Sstevel@tonic-gate * 4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*7c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*7c478bd9Sstevel@tonic-gate * with the License. 8*7c478bd9Sstevel@tonic-gate * 9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 12*7c478bd9Sstevel@tonic-gate * and limitations under the License. 13*7c478bd9Sstevel@tonic-gate * 14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*7c478bd9Sstevel@tonic-gate * 20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END 21*7c478bd9Sstevel@tonic-gate */ 22*7c478bd9Sstevel@tonic-gate /* 23*7c478bd9Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 25*7c478bd9Sstevel@tonic-gate */ 26*7c478bd9Sstevel@tonic-gate 27*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*7c478bd9Sstevel@tonic-gate 29*7c478bd9Sstevel@tonic-gate #include <sys/timer.h> 30*7c478bd9Sstevel@tonic-gate #include <sys/systm.h> 31*7c478bd9Sstevel@tonic-gate #include <sys/param.h> 32*7c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 33*7c478bd9Sstevel@tonic-gate #include <sys/debug.h> 34*7c478bd9Sstevel@tonic-gate #include <sys/policy.h> 35*7c478bd9Sstevel@tonic-gate #include <sys/port.h> 36*7c478bd9Sstevel@tonic-gate #include <sys/port_kernel.h> 37*7c478bd9Sstevel@tonic-gate #include <sys/contract/process_impl.h> 38*7c478bd9Sstevel@tonic-gate 39*7c478bd9Sstevel@tonic-gate static kmem_cache_t *clock_timer_cache; 40*7c478bd9Sstevel@tonic-gate static clock_backend_t *clock_backend[CLOCK_MAX]; 41*7c478bd9Sstevel@tonic-gate static int timer_port_callback(void *, int *, pid_t, int, void *); 42*7c478bd9Sstevel@tonic-gate static void timer_close_port(void *, int, pid_t, int); 43*7c478bd9Sstevel@tonic-gate 44*7c478bd9Sstevel@tonic-gate #define CLOCK_BACKEND(clk) \ 45*7c478bd9Sstevel@tonic-gate ((clk) < CLOCK_MAX && (clk) >= 0 ? clock_backend[(clk)] : NULL) 46*7c478bd9Sstevel@tonic-gate 47*7c478bd9Sstevel@tonic-gate /* 48*7c478bd9Sstevel@tonic-gate * Tunable to increase the maximum number of POSIX timers per-process. This 49*7c478bd9Sstevel@tonic-gate * may _only_ be tuned in /etc/system or by patching the kernel binary; it 50*7c478bd9Sstevel@tonic-gate * _cannot_ be tuned on a running system. 51*7c478bd9Sstevel@tonic-gate */ 52*7c478bd9Sstevel@tonic-gate int timer_max = _TIMER_MAX; 53*7c478bd9Sstevel@tonic-gate 54*7c478bd9Sstevel@tonic-gate /* 55*7c478bd9Sstevel@tonic-gate * timer_lock() locks the specified interval timer. It doesn't look at the 56*7c478bd9Sstevel@tonic-gate * ITLK_REMOVE bit; it's up to callers to look at this if they need to 57*7c478bd9Sstevel@tonic-gate * care. p_lock must be held on entry; it may be dropped and reaquired, 58*7c478bd9Sstevel@tonic-gate * but timer_lock() will always return with p_lock held. 59*7c478bd9Sstevel@tonic-gate * 60*7c478bd9Sstevel@tonic-gate * Note that timer_create() doesn't call timer_lock(); it creates timers 61*7c478bd9Sstevel@tonic-gate * with the ITLK_LOCKED bit explictly set. 62*7c478bd9Sstevel@tonic-gate */ 63*7c478bd9Sstevel@tonic-gate static void 64*7c478bd9Sstevel@tonic-gate timer_lock(proc_t *p, itimer_t *it) 65*7c478bd9Sstevel@tonic-gate { 66*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&p->p_lock)); 67*7c478bd9Sstevel@tonic-gate 68*7c478bd9Sstevel@tonic-gate while (it->it_lock & ITLK_LOCKED) { 69*7c478bd9Sstevel@tonic-gate it->it_blockers++; 70*7c478bd9Sstevel@tonic-gate cv_wait(&it->it_cv, &p->p_lock); 71*7c478bd9Sstevel@tonic-gate it->it_blockers--; 72*7c478bd9Sstevel@tonic-gate } 73*7c478bd9Sstevel@tonic-gate 74*7c478bd9Sstevel@tonic-gate it->it_lock |= ITLK_LOCKED; 75*7c478bd9Sstevel@tonic-gate } 76*7c478bd9Sstevel@tonic-gate 77*7c478bd9Sstevel@tonic-gate /* 78*7c478bd9Sstevel@tonic-gate * timer_unlock() unlocks the specified interval timer, waking up any 79*7c478bd9Sstevel@tonic-gate * waiters. p_lock must be held on entry; it will not be dropped by 80*7c478bd9Sstevel@tonic-gate * timer_unlock(). 81*7c478bd9Sstevel@tonic-gate */ 82*7c478bd9Sstevel@tonic-gate static void 83*7c478bd9Sstevel@tonic-gate timer_unlock(proc_t *p, itimer_t *it) 84*7c478bd9Sstevel@tonic-gate { 85*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&p->p_lock)); 86*7c478bd9Sstevel@tonic-gate ASSERT(it->it_lock & ITLK_LOCKED); 87*7c478bd9Sstevel@tonic-gate it->it_lock &= ~ITLK_LOCKED; 88*7c478bd9Sstevel@tonic-gate cv_signal(&it->it_cv); 89*7c478bd9Sstevel@tonic-gate } 90*7c478bd9Sstevel@tonic-gate 91*7c478bd9Sstevel@tonic-gate /* 92*7c478bd9Sstevel@tonic-gate * timer_delete_locked() takes a proc pointer, timer ID and locked interval 93*7c478bd9Sstevel@tonic-gate * timer, and deletes the specified timer. It must be called with p_lock 94*7c478bd9Sstevel@tonic-gate * held, and cannot be called on a timer which already has ITLK_REMOVE set; 95*7c478bd9Sstevel@tonic-gate * the caller must check this. timer_delete_locked() will set the ITLK_REMOVE 96*7c478bd9Sstevel@tonic-gate * bit and will iteratively unlock and lock the interval timer until all 97*7c478bd9Sstevel@tonic-gate * blockers have seen the ITLK_REMOVE and cleared out. It will then zero 98*7c478bd9Sstevel@tonic-gate * out the specified entry in the p_itimer array, and call into the clock 99*7c478bd9Sstevel@tonic-gate * backend to complete the deletion. 100*7c478bd9Sstevel@tonic-gate * 101*7c478bd9Sstevel@tonic-gate * This function will always return with p_lock held. 102*7c478bd9Sstevel@tonic-gate */ 103*7c478bd9Sstevel@tonic-gate static void 104*7c478bd9Sstevel@tonic-gate timer_delete_locked(proc_t *p, timer_t tid, itimer_t *it) 105*7c478bd9Sstevel@tonic-gate { 106*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&p->p_lock)); 107*7c478bd9Sstevel@tonic-gate ASSERT(!(it->it_lock & ITLK_REMOVE)); 108*7c478bd9Sstevel@tonic-gate ASSERT(it->it_lock & ITLK_LOCKED); 109*7c478bd9Sstevel@tonic-gate 110*7c478bd9Sstevel@tonic-gate it->it_lock |= ITLK_REMOVE; 111*7c478bd9Sstevel@tonic-gate 112*7c478bd9Sstevel@tonic-gate /* 113*7c478bd9Sstevel@tonic-gate * If there are threads waiting to lock this timer, we'll unlock 114*7c478bd9Sstevel@tonic-gate * the timer, and block on the cv. Threads blocking our removal will 115*7c478bd9Sstevel@tonic-gate * have the opportunity to run; when they see the ITLK_REMOVE flag 116*7c478bd9Sstevel@tonic-gate * set, they will immediately unlock the timer. 117*7c478bd9Sstevel@tonic-gate */ 118*7c478bd9Sstevel@tonic-gate while (it->it_blockers) { 119*7c478bd9Sstevel@tonic-gate timer_unlock(p, it); 120*7c478bd9Sstevel@tonic-gate cv_wait(&it->it_cv, &p->p_lock); 121*7c478bd9Sstevel@tonic-gate timer_lock(p, it); 122*7c478bd9Sstevel@tonic-gate } 123*7c478bd9Sstevel@tonic-gate 124*7c478bd9Sstevel@tonic-gate ASSERT(p->p_itimer[tid] == it); 125*7c478bd9Sstevel@tonic-gate p->p_itimer[tid] = NULL; 126*7c478bd9Sstevel@tonic-gate 127*7c478bd9Sstevel@tonic-gate /* 128*7c478bd9Sstevel@tonic-gate * No one is blocked on this timer, and no one will be (we've set 129*7c478bd9Sstevel@tonic-gate * p_itimer[tid] to be NULL; no one can find it). Now we call into 130*7c478bd9Sstevel@tonic-gate * the clock backend to delete the timer; it is up to the backend to 131*7c478bd9Sstevel@tonic-gate * guarantee that timer_fire() has completed (and will never again 132*7c478bd9Sstevel@tonic-gate * be called) for this timer. 133*7c478bd9Sstevel@tonic-gate */ 134*7c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock); 135*7c478bd9Sstevel@tonic-gate 136*7c478bd9Sstevel@tonic-gate it->it_backend->clk_timer_delete(it); 137*7c478bd9Sstevel@tonic-gate 138*7c478bd9Sstevel@tonic-gate if (it->it_portev) { 139*7c478bd9Sstevel@tonic-gate mutex_enter(&it->it_mutex); 140*7c478bd9Sstevel@tonic-gate if (it->it_portev) { 141*7c478bd9Sstevel@tonic-gate /* dissociate timer from the event port */ 142*7c478bd9Sstevel@tonic-gate (void) port_dissociate_ksource(it->it_portfd, 143*7c478bd9Sstevel@tonic-gate PORT_SOURCE_TIMER, (port_source_t *)it->it_portsrc); 144*7c478bd9Sstevel@tonic-gate port_free_event((port_kevent_t *)it->it_portev); 145*7c478bd9Sstevel@tonic-gate it->it_portev = NULL; 146*7c478bd9Sstevel@tonic-gate it->it_flags &= ~IT_PORT; 147*7c478bd9Sstevel@tonic-gate it->it_pending = 0; 148*7c478bd9Sstevel@tonic-gate } 149*7c478bd9Sstevel@tonic-gate mutex_exit(&it->it_mutex); 150*7c478bd9Sstevel@tonic-gate } 151*7c478bd9Sstevel@tonic-gate 152*7c478bd9Sstevel@tonic-gate mutex_enter(&p->p_lock); 153*7c478bd9Sstevel@tonic-gate 154*7c478bd9Sstevel@tonic-gate /* 155*7c478bd9Sstevel@tonic-gate * We need to be careful freeing the sigqueue for this timer; 156*7c478bd9Sstevel@tonic-gate * if a signal is pending, the sigqueue needs to be freed 157*7c478bd9Sstevel@tonic-gate * synchronously in siginfofree(). The need to free the sigqueue 158*7c478bd9Sstevel@tonic-gate * in siginfofree() is indicated by setting sq_func to NULL. 159*7c478bd9Sstevel@tonic-gate */ 160*7c478bd9Sstevel@tonic-gate if (it->it_pending > 0) { 161*7c478bd9Sstevel@tonic-gate it->it_sigq->sq_func = NULL; 162*7c478bd9Sstevel@tonic-gate } else { 163*7c478bd9Sstevel@tonic-gate kmem_free(it->it_sigq, sizeof (sigqueue_t)); 164*7c478bd9Sstevel@tonic-gate } 165*7c478bd9Sstevel@tonic-gate 166*7c478bd9Sstevel@tonic-gate ASSERT(it->it_blockers == 0); 167*7c478bd9Sstevel@tonic-gate kmem_cache_free(clock_timer_cache, it); 168*7c478bd9Sstevel@tonic-gate } 169*7c478bd9Sstevel@tonic-gate 170*7c478bd9Sstevel@tonic-gate /* 171*7c478bd9Sstevel@tonic-gate * timer_grab() and its companion routine, timer_release(), are wrappers 172*7c478bd9Sstevel@tonic-gate * around timer_lock()/_unlock() which allow the timer_*(3R) routines to 173*7c478bd9Sstevel@tonic-gate * (a) share error handling code and (b) not grab p_lock themselves. Routines 174*7c478bd9Sstevel@tonic-gate * which are called with p_lock held (e.g. timer_lwpbind(), timer_lwpexit()) 175*7c478bd9Sstevel@tonic-gate * must call timer_lock()/_unlock() explictly. 176*7c478bd9Sstevel@tonic-gate * 177*7c478bd9Sstevel@tonic-gate * timer_grab() takes a proc and a timer ID, and returns a pointer to a 178*7c478bd9Sstevel@tonic-gate * locked interval timer. p_lock must _not_ be held on entry; timer_grab() 179*7c478bd9Sstevel@tonic-gate * may acquire p_lock, but will always return with p_lock dropped. 180*7c478bd9Sstevel@tonic-gate * 181*7c478bd9Sstevel@tonic-gate * If timer_grab() fails, it will return NULL. timer_grab() will fail if 182*7c478bd9Sstevel@tonic-gate * one or more of the following is true: 183*7c478bd9Sstevel@tonic-gate * 184*7c478bd9Sstevel@tonic-gate * (a) The specified timer ID is out of range. 185*7c478bd9Sstevel@tonic-gate * 186*7c478bd9Sstevel@tonic-gate * (b) The specified timer ID does not correspond to a timer ID returned 187*7c478bd9Sstevel@tonic-gate * from timer_create(3R). 188*7c478bd9Sstevel@tonic-gate * 189*7c478bd9Sstevel@tonic-gate * (c) The specified timer ID is currently being removed. 190*7c478bd9Sstevel@tonic-gate * 191*7c478bd9Sstevel@tonic-gate */ 192*7c478bd9Sstevel@tonic-gate static itimer_t * 193*7c478bd9Sstevel@tonic-gate timer_grab(proc_t *p, timer_t tid) 194*7c478bd9Sstevel@tonic-gate { 195*7c478bd9Sstevel@tonic-gate itimer_t **itp, *it; 196*7c478bd9Sstevel@tonic-gate 197*7c478bd9Sstevel@tonic-gate if (tid >= timer_max || tid < 0) 198*7c478bd9Sstevel@tonic-gate return (NULL); 199*7c478bd9Sstevel@tonic-gate 200*7c478bd9Sstevel@tonic-gate mutex_enter(&p->p_lock); 201*7c478bd9Sstevel@tonic-gate 202*7c478bd9Sstevel@tonic-gate if ((itp = p->p_itimer) == NULL || (it = itp[tid]) == NULL) { 203*7c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock); 204*7c478bd9Sstevel@tonic-gate return (NULL); 205*7c478bd9Sstevel@tonic-gate } 206*7c478bd9Sstevel@tonic-gate 207*7c478bd9Sstevel@tonic-gate timer_lock(p, it); 208*7c478bd9Sstevel@tonic-gate 209*7c478bd9Sstevel@tonic-gate if (it->it_lock & ITLK_REMOVE) { 210*7c478bd9Sstevel@tonic-gate /* 211*7c478bd9Sstevel@tonic-gate * Someone is removing this timer; it will soon be invalid. 212*7c478bd9Sstevel@tonic-gate */ 213*7c478bd9Sstevel@tonic-gate timer_unlock(p, it); 214*7c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock); 215*7c478bd9Sstevel@tonic-gate return (NULL); 216*7c478bd9Sstevel@tonic-gate } 217*7c478bd9Sstevel@tonic-gate 218*7c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock); 219*7c478bd9Sstevel@tonic-gate 220*7c478bd9Sstevel@tonic-gate return (it); 221*7c478bd9Sstevel@tonic-gate } 222*7c478bd9Sstevel@tonic-gate 223*7c478bd9Sstevel@tonic-gate /* 224*7c478bd9Sstevel@tonic-gate * timer_release() releases a timer acquired with timer_grab(). p_lock 225*7c478bd9Sstevel@tonic-gate * should not be held on entry; timer_release() will acquire p_lock but 226*7c478bd9Sstevel@tonic-gate * will drop it before returning. 227*7c478bd9Sstevel@tonic-gate */ 228*7c478bd9Sstevel@tonic-gate static void 229*7c478bd9Sstevel@tonic-gate timer_release(proc_t *p, itimer_t *it) 230*7c478bd9Sstevel@tonic-gate { 231*7c478bd9Sstevel@tonic-gate mutex_enter(&p->p_lock); 232*7c478bd9Sstevel@tonic-gate timer_unlock(p, it); 233*7c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock); 234*7c478bd9Sstevel@tonic-gate } 235*7c478bd9Sstevel@tonic-gate 236*7c478bd9Sstevel@tonic-gate /* 237*7c478bd9Sstevel@tonic-gate * timer_delete_grabbed() deletes a timer acquired with timer_grab(). 238*7c478bd9Sstevel@tonic-gate * p_lock should not be held on entry; timer_delete_grabbed() will acquire 239*7c478bd9Sstevel@tonic-gate * p_lock, but will drop it before returning. 240*7c478bd9Sstevel@tonic-gate */ 241*7c478bd9Sstevel@tonic-gate static void 242*7c478bd9Sstevel@tonic-gate timer_delete_grabbed(proc_t *p, timer_t tid, itimer_t *it) 243*7c478bd9Sstevel@tonic-gate { 244*7c478bd9Sstevel@tonic-gate mutex_enter(&p->p_lock); 245*7c478bd9Sstevel@tonic-gate timer_delete_locked(p, tid, it); 246*7c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock); 247*7c478bd9Sstevel@tonic-gate } 248*7c478bd9Sstevel@tonic-gate 249*7c478bd9Sstevel@tonic-gate void 250*7c478bd9Sstevel@tonic-gate clock_timer_init() 251*7c478bd9Sstevel@tonic-gate { 252*7c478bd9Sstevel@tonic-gate clock_timer_cache = kmem_cache_create("timer_cache", 253*7c478bd9Sstevel@tonic-gate sizeof (itimer_t), 0, NULL, NULL, NULL, NULL, NULL, 0); 254*7c478bd9Sstevel@tonic-gate } 255*7c478bd9Sstevel@tonic-gate 256*7c478bd9Sstevel@tonic-gate void 257*7c478bd9Sstevel@tonic-gate clock_add_backend(clockid_t clock, clock_backend_t *backend) 258*7c478bd9Sstevel@tonic-gate { 259*7c478bd9Sstevel@tonic-gate ASSERT(clock >= 0 && clock < CLOCK_MAX); 260*7c478bd9Sstevel@tonic-gate ASSERT(clock_backend[clock] == NULL); 261*7c478bd9Sstevel@tonic-gate 262*7c478bd9Sstevel@tonic-gate clock_backend[clock] = backend; 263*7c478bd9Sstevel@tonic-gate } 264*7c478bd9Sstevel@tonic-gate 265*7c478bd9Sstevel@tonic-gate int 266*7c478bd9Sstevel@tonic-gate clock_settime(clockid_t clock, timespec_t *tp) 267*7c478bd9Sstevel@tonic-gate { 268*7c478bd9Sstevel@tonic-gate timespec_t t; 269*7c478bd9Sstevel@tonic-gate clock_backend_t *backend; 270*7c478bd9Sstevel@tonic-gate int error; 271*7c478bd9Sstevel@tonic-gate 272*7c478bd9Sstevel@tonic-gate if ((backend = CLOCK_BACKEND(clock)) == NULL) 273*7c478bd9Sstevel@tonic-gate return (set_errno(EINVAL)); 274*7c478bd9Sstevel@tonic-gate 275*7c478bd9Sstevel@tonic-gate if (secpolicy_settime(CRED()) != 0) 276*7c478bd9Sstevel@tonic-gate return (set_errno(EPERM)); 277*7c478bd9Sstevel@tonic-gate 278*7c478bd9Sstevel@tonic-gate if (get_udatamodel() == DATAMODEL_NATIVE) { 279*7c478bd9Sstevel@tonic-gate if (copyin(tp, &t, sizeof (timespec_t)) != 0) 280*7c478bd9Sstevel@tonic-gate return (set_errno(EFAULT)); 281*7c478bd9Sstevel@tonic-gate } else { 282*7c478bd9Sstevel@tonic-gate timespec32_t t32; 283*7c478bd9Sstevel@tonic-gate 284*7c478bd9Sstevel@tonic-gate if (copyin(tp, &t32, sizeof (timespec32_t)) != 0) 285*7c478bd9Sstevel@tonic-gate return (set_errno(EFAULT)); 286*7c478bd9Sstevel@tonic-gate 287*7c478bd9Sstevel@tonic-gate TIMESPEC32_TO_TIMESPEC(&t, &t32); 288*7c478bd9Sstevel@tonic-gate } 289*7c478bd9Sstevel@tonic-gate 290*7c478bd9Sstevel@tonic-gate if (itimerspecfix(&t)) 291*7c478bd9Sstevel@tonic-gate return (set_errno(EINVAL)); 292*7c478bd9Sstevel@tonic-gate 293*7c478bd9Sstevel@tonic-gate error = backend->clk_clock_settime(&t); 294*7c478bd9Sstevel@tonic-gate 295*7c478bd9Sstevel@tonic-gate if (error) 296*7c478bd9Sstevel@tonic-gate return (set_errno(error)); 297*7c478bd9Sstevel@tonic-gate 298*7c478bd9Sstevel@tonic-gate return (0); 299*7c478bd9Sstevel@tonic-gate } 300*7c478bd9Sstevel@tonic-gate 301*7c478bd9Sstevel@tonic-gate int 302*7c478bd9Sstevel@tonic-gate clock_gettime(clockid_t clock, timespec_t *tp) 303*7c478bd9Sstevel@tonic-gate { 304*7c478bd9Sstevel@tonic-gate timespec_t t; 305*7c478bd9Sstevel@tonic-gate clock_backend_t *backend; 306*7c478bd9Sstevel@tonic-gate int error; 307*7c478bd9Sstevel@tonic-gate 308*7c478bd9Sstevel@tonic-gate if ((backend = CLOCK_BACKEND(clock)) == NULL) 309*7c478bd9Sstevel@tonic-gate return (set_errno(EINVAL)); 310*7c478bd9Sstevel@tonic-gate 311*7c478bd9Sstevel@tonic-gate error = backend->clk_clock_gettime(&t); 312*7c478bd9Sstevel@tonic-gate 313*7c478bd9Sstevel@tonic-gate if (error) 314*7c478bd9Sstevel@tonic-gate return (set_errno(error)); 315*7c478bd9Sstevel@tonic-gate 316*7c478bd9Sstevel@tonic-gate if (get_udatamodel() == DATAMODEL_NATIVE) { 317*7c478bd9Sstevel@tonic-gate if (copyout(&t, tp, sizeof (timespec_t)) != 0) 318*7c478bd9Sstevel@tonic-gate return (set_errno(EFAULT)); 319*7c478bd9Sstevel@tonic-gate } else { 320*7c478bd9Sstevel@tonic-gate timespec32_t t32; 321*7c478bd9Sstevel@tonic-gate 322*7c478bd9Sstevel@tonic-gate if (TIMESPEC_OVERFLOW(&t)) 323*7c478bd9Sstevel@tonic-gate return (set_errno(EOVERFLOW)); 324*7c478bd9Sstevel@tonic-gate TIMESPEC_TO_TIMESPEC32(&t32, &t); 325*7c478bd9Sstevel@tonic-gate 326*7c478bd9Sstevel@tonic-gate if (copyout(&t32, tp, sizeof (timespec32_t)) != 0) 327*7c478bd9Sstevel@tonic-gate return (set_errno(EFAULT)); 328*7c478bd9Sstevel@tonic-gate } 329*7c478bd9Sstevel@tonic-gate 330*7c478bd9Sstevel@tonic-gate return (0); 331*7c478bd9Sstevel@tonic-gate } 332*7c478bd9Sstevel@tonic-gate 333*7c478bd9Sstevel@tonic-gate int 334*7c478bd9Sstevel@tonic-gate clock_getres(clockid_t clock, timespec_t *tp) 335*7c478bd9Sstevel@tonic-gate { 336*7c478bd9Sstevel@tonic-gate timespec_t t; 337*7c478bd9Sstevel@tonic-gate clock_backend_t *backend; 338*7c478bd9Sstevel@tonic-gate int error; 339*7c478bd9Sstevel@tonic-gate 340*7c478bd9Sstevel@tonic-gate /* 341*7c478bd9Sstevel@tonic-gate * Strangely, the standard defines clock_getres() with a NULL tp 342*7c478bd9Sstevel@tonic-gate * to do nothing (regardless of the validity of the specified 343*7c478bd9Sstevel@tonic-gate * clock_id). Go figure. 344*7c478bd9Sstevel@tonic-gate */ 345*7c478bd9Sstevel@tonic-gate if (tp == NULL) 346*7c478bd9Sstevel@tonic-gate return (0); 347*7c478bd9Sstevel@tonic-gate 348*7c478bd9Sstevel@tonic-gate if ((backend = CLOCK_BACKEND(clock)) == NULL) 349*7c478bd9Sstevel@tonic-gate return (set_errno(EINVAL)); 350*7c478bd9Sstevel@tonic-gate 351*7c478bd9Sstevel@tonic-gate error = backend->clk_clock_getres(&t); 352*7c478bd9Sstevel@tonic-gate 353*7c478bd9Sstevel@tonic-gate if (error) 354*7c478bd9Sstevel@tonic-gate return (set_errno(error)); 355*7c478bd9Sstevel@tonic-gate 356*7c478bd9Sstevel@tonic-gate if (get_udatamodel() == DATAMODEL_NATIVE) { 357*7c478bd9Sstevel@tonic-gate if (copyout(&t, tp, sizeof (timespec_t)) != 0) 358*7c478bd9Sstevel@tonic-gate return (set_errno(EFAULT)); 359*7c478bd9Sstevel@tonic-gate } else { 360*7c478bd9Sstevel@tonic-gate timespec32_t t32; 361*7c478bd9Sstevel@tonic-gate 362*7c478bd9Sstevel@tonic-gate if (TIMESPEC_OVERFLOW(&t)) 363*7c478bd9Sstevel@tonic-gate return (set_errno(EOVERFLOW)); 364*7c478bd9Sstevel@tonic-gate TIMESPEC_TO_TIMESPEC32(&t32, &t); 365*7c478bd9Sstevel@tonic-gate 366*7c478bd9Sstevel@tonic-gate if (copyout(&t32, tp, sizeof (timespec32_t)) != 0) 367*7c478bd9Sstevel@tonic-gate return (set_errno(EFAULT)); 368*7c478bd9Sstevel@tonic-gate } 369*7c478bd9Sstevel@tonic-gate 370*7c478bd9Sstevel@tonic-gate return (0); 371*7c478bd9Sstevel@tonic-gate } 372*7c478bd9Sstevel@tonic-gate 373*7c478bd9Sstevel@tonic-gate void 374*7c478bd9Sstevel@tonic-gate timer_signal(sigqueue_t *sigq) 375*7c478bd9Sstevel@tonic-gate { 376*7c478bd9Sstevel@tonic-gate itimer_t *it = (itimer_t *)sigq->sq_backptr; 377*7c478bd9Sstevel@tonic-gate 378*7c478bd9Sstevel@tonic-gate /* 379*7c478bd9Sstevel@tonic-gate * There are some conditions during a fork or an exit when we can 380*7c478bd9Sstevel@tonic-gate * call siginfofree() without p_lock held. To prevent a race 381*7c478bd9Sstevel@tonic-gate * between timer_signal() and timer_fire() with regard to it_pending, 382*7c478bd9Sstevel@tonic-gate * we therefore acquire it_mutex in both paths. 383*7c478bd9Sstevel@tonic-gate */ 384*7c478bd9Sstevel@tonic-gate mutex_enter(&it->it_mutex); 385*7c478bd9Sstevel@tonic-gate ASSERT(it->it_pending > 0); 386*7c478bd9Sstevel@tonic-gate it->it_overrun = it->it_pending - 1; 387*7c478bd9Sstevel@tonic-gate it->it_pending = 0; 388*7c478bd9Sstevel@tonic-gate mutex_exit(&it->it_mutex); 389*7c478bd9Sstevel@tonic-gate } 390*7c478bd9Sstevel@tonic-gate 391*7c478bd9Sstevel@tonic-gate /* 392*7c478bd9Sstevel@tonic-gate * This routine is called from the clock backend. 393*7c478bd9Sstevel@tonic-gate */ 394*7c478bd9Sstevel@tonic-gate void 395*7c478bd9Sstevel@tonic-gate timer_fire(itimer_t *it) 396*7c478bd9Sstevel@tonic-gate { 397*7c478bd9Sstevel@tonic-gate proc_t *p; 398*7c478bd9Sstevel@tonic-gate int proc_lock_held; 399*7c478bd9Sstevel@tonic-gate 400*7c478bd9Sstevel@tonic-gate if (it->it_flags & IT_SIGNAL) { 401*7c478bd9Sstevel@tonic-gate /* 402*7c478bd9Sstevel@tonic-gate * See the comment in timer_signal() for why it is not 403*7c478bd9Sstevel@tonic-gate * sufficient to only grab p_lock here. Because p_lock can be 404*7c478bd9Sstevel@tonic-gate * held on entry to timer_signal(), the lock ordering is 405*7c478bd9Sstevel@tonic-gate * necessarily p_lock before it_mutex. 406*7c478bd9Sstevel@tonic-gate */ 407*7c478bd9Sstevel@tonic-gate 408*7c478bd9Sstevel@tonic-gate p = it->it_proc; 409*7c478bd9Sstevel@tonic-gate proc_lock_held = 1; 410*7c478bd9Sstevel@tonic-gate mutex_enter(&p->p_lock); 411*7c478bd9Sstevel@tonic-gate } else { 412*7c478bd9Sstevel@tonic-gate /* 413*7c478bd9Sstevel@tonic-gate * IT_PORT: 414*7c478bd9Sstevel@tonic-gate * If a timer was ever programmed to send events to a port, 415*7c478bd9Sstevel@tonic-gate * the IT_PORT flag will remain set until: 416*7c478bd9Sstevel@tonic-gate * a) the timer is deleted (see timer_delete_locked()) or 417*7c478bd9Sstevel@tonic-gate * b) the port is being closed (see timer_close_port()). 418*7c478bd9Sstevel@tonic-gate * Both cases are synchronized with the it_mutex. 419*7c478bd9Sstevel@tonic-gate * We don't need to use the p_lock because it is only 420*7c478bd9Sstevel@tonic-gate * required in the IT_SIGNAL case. 421*7c478bd9Sstevel@tonic-gate * If IT_PORT was set and the port is being closed then 422*7c478bd9Sstevel@tonic-gate * the timer notification is set to NONE. In such a case 423*7c478bd9Sstevel@tonic-gate * the timer itself and the it_pending counter remain active 424*7c478bd9Sstevel@tonic-gate * until the application deletes the counter or the process 425*7c478bd9Sstevel@tonic-gate * exits. 426*7c478bd9Sstevel@tonic-gate */ 427*7c478bd9Sstevel@tonic-gate proc_lock_held = 0; 428*7c478bd9Sstevel@tonic-gate } 429*7c478bd9Sstevel@tonic-gate mutex_enter(&it->it_mutex); 430*7c478bd9Sstevel@tonic-gate 431*7c478bd9Sstevel@tonic-gate if (it->it_pending > 0) { 432*7c478bd9Sstevel@tonic-gate if (it->it_pending < INT_MAX) 433*7c478bd9Sstevel@tonic-gate it->it_pending++; 434*7c478bd9Sstevel@tonic-gate mutex_exit(&it->it_mutex); 435*7c478bd9Sstevel@tonic-gate } else { 436*7c478bd9Sstevel@tonic-gate if (it->it_flags & IT_PORT) { 437*7c478bd9Sstevel@tonic-gate it->it_pending = 1; 438*7c478bd9Sstevel@tonic-gate (void) port_send_event((port_kevent_t *)it->it_portev); 439*7c478bd9Sstevel@tonic-gate mutex_exit(&it->it_mutex); 440*7c478bd9Sstevel@tonic-gate } else if (it->it_flags & IT_SIGNAL) { 441*7c478bd9Sstevel@tonic-gate it->it_pending = 1; 442*7c478bd9Sstevel@tonic-gate mutex_exit(&it->it_mutex); 443*7c478bd9Sstevel@tonic-gate sigaddqa(p, NULL, it->it_sigq); 444*7c478bd9Sstevel@tonic-gate } else { 445*7c478bd9Sstevel@tonic-gate mutex_exit(&it->it_mutex); 446*7c478bd9Sstevel@tonic-gate } 447*7c478bd9Sstevel@tonic-gate } 448*7c478bd9Sstevel@tonic-gate 449*7c478bd9Sstevel@tonic-gate if (proc_lock_held) 450*7c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock); 451*7c478bd9Sstevel@tonic-gate } 452*7c478bd9Sstevel@tonic-gate 453*7c478bd9Sstevel@tonic-gate int 454*7c478bd9Sstevel@tonic-gate timer_create(clockid_t clock, struct sigevent *evp, timer_t *tid) 455*7c478bd9Sstevel@tonic-gate { 456*7c478bd9Sstevel@tonic-gate struct sigevent ev; 457*7c478bd9Sstevel@tonic-gate proc_t *p = curproc; 458*7c478bd9Sstevel@tonic-gate clock_backend_t *backend; 459*7c478bd9Sstevel@tonic-gate itimer_t *it, **itp; 460*7c478bd9Sstevel@tonic-gate sigqueue_t *sigq; 461*7c478bd9Sstevel@tonic-gate cred_t *cr = CRED(); 462*7c478bd9Sstevel@tonic-gate int error = 0; 463*7c478bd9Sstevel@tonic-gate timer_t i; 464*7c478bd9Sstevel@tonic-gate port_notify_t tim_pnevp; 465*7c478bd9Sstevel@tonic-gate port_kevent_t *pkevp = NULL; 466*7c478bd9Sstevel@tonic-gate 467*7c478bd9Sstevel@tonic-gate if ((backend = CLOCK_BACKEND(clock)) == NULL) 468*7c478bd9Sstevel@tonic-gate return (set_errno(EINVAL)); 469*7c478bd9Sstevel@tonic-gate 470*7c478bd9Sstevel@tonic-gate if (evp != NULL) { 471*7c478bd9Sstevel@tonic-gate /* 472*7c478bd9Sstevel@tonic-gate * short copyin() for binary compatibility 473*7c478bd9Sstevel@tonic-gate * fetch oldsigevent to determine how much to copy in. 474*7c478bd9Sstevel@tonic-gate */ 475*7c478bd9Sstevel@tonic-gate if (get_udatamodel() == DATAMODEL_NATIVE) { 476*7c478bd9Sstevel@tonic-gate if (copyin(evp, &ev, sizeof (struct oldsigevent))) 477*7c478bd9Sstevel@tonic-gate return (set_errno(EFAULT)); 478*7c478bd9Sstevel@tonic-gate 479*7c478bd9Sstevel@tonic-gate if (ev.sigev_notify == SIGEV_PORT) { 480*7c478bd9Sstevel@tonic-gate if (copyin(ev.sigev_value.sival_ptr, &tim_pnevp, 481*7c478bd9Sstevel@tonic-gate sizeof (port_notify_t))) 482*7c478bd9Sstevel@tonic-gate return (set_errno(EFAULT)); 483*7c478bd9Sstevel@tonic-gate } 484*7c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL 485*7c478bd9Sstevel@tonic-gate } else { 486*7c478bd9Sstevel@tonic-gate struct sigevent32 ev32; 487*7c478bd9Sstevel@tonic-gate port_notify32_t tim_pnevp32; 488*7c478bd9Sstevel@tonic-gate 489*7c478bd9Sstevel@tonic-gate if (copyin(evp, &ev32, sizeof (struct oldsigevent32))) 490*7c478bd9Sstevel@tonic-gate return (set_errno(EFAULT)); 491*7c478bd9Sstevel@tonic-gate ev.sigev_notify = ev32.sigev_notify; 492*7c478bd9Sstevel@tonic-gate ev.sigev_signo = ev32.sigev_signo; 493*7c478bd9Sstevel@tonic-gate /* 494*7c478bd9Sstevel@tonic-gate * See comment in sigqueue32() on handling of 32-bit 495*7c478bd9Sstevel@tonic-gate * sigvals in a 64-bit kernel. 496*7c478bd9Sstevel@tonic-gate */ 497*7c478bd9Sstevel@tonic-gate ev.sigev_value.sival_int = ev32.sigev_value.sival_int; 498*7c478bd9Sstevel@tonic-gate if (ev.sigev_notify == SIGEV_PORT) { 499*7c478bd9Sstevel@tonic-gate if (copyin((void *)(uintptr_t) 500*7c478bd9Sstevel@tonic-gate ev32.sigev_value.sival_ptr, 501*7c478bd9Sstevel@tonic-gate (void *)&tim_pnevp32, 502*7c478bd9Sstevel@tonic-gate sizeof (port_notify32_t))) 503*7c478bd9Sstevel@tonic-gate return (set_errno(EFAULT)); 504*7c478bd9Sstevel@tonic-gate tim_pnevp.portnfy_port = 505*7c478bd9Sstevel@tonic-gate tim_pnevp32.portnfy_port; 506*7c478bd9Sstevel@tonic-gate tim_pnevp.portnfy_user = 507*7c478bd9Sstevel@tonic-gate (void *)(uintptr_t)tim_pnevp32.portnfy_user; 508*7c478bd9Sstevel@tonic-gate } 509*7c478bd9Sstevel@tonic-gate #endif 510*7c478bd9Sstevel@tonic-gate } 511*7c478bd9Sstevel@tonic-gate switch (ev.sigev_notify) { 512*7c478bd9Sstevel@tonic-gate case SIGEV_NONE: 513*7c478bd9Sstevel@tonic-gate break; 514*7c478bd9Sstevel@tonic-gate 515*7c478bd9Sstevel@tonic-gate case SIGEV_SIGNAL: 516*7c478bd9Sstevel@tonic-gate if (ev.sigev_signo < 1 || ev.sigev_signo >= NSIG) 517*7c478bd9Sstevel@tonic-gate return (set_errno(EINVAL)); 518*7c478bd9Sstevel@tonic-gate break; 519*7c478bd9Sstevel@tonic-gate case SIGEV_PORT: 520*7c478bd9Sstevel@tonic-gate break; 521*7c478bd9Sstevel@tonic-gate default: 522*7c478bd9Sstevel@tonic-gate return (set_errno(EINVAL)); 523*7c478bd9Sstevel@tonic-gate } 524*7c478bd9Sstevel@tonic-gate } else { 525*7c478bd9Sstevel@tonic-gate /* 526*7c478bd9Sstevel@tonic-gate * Use the clock's default sigevent (this is a structure copy). 527*7c478bd9Sstevel@tonic-gate */ 528*7c478bd9Sstevel@tonic-gate ev = backend->clk_default; 529*7c478bd9Sstevel@tonic-gate } 530*7c478bd9Sstevel@tonic-gate 531*7c478bd9Sstevel@tonic-gate /* 532*7c478bd9Sstevel@tonic-gate * We'll allocate our timer and sigqueue now, before we grab p_lock. 533*7c478bd9Sstevel@tonic-gate * If we can't find an empty slot, we'll free them before returning. 534*7c478bd9Sstevel@tonic-gate */ 535*7c478bd9Sstevel@tonic-gate it = kmem_cache_alloc(clock_timer_cache, KM_SLEEP); 536*7c478bd9Sstevel@tonic-gate bzero(it, sizeof (itimer_t)); 537*7c478bd9Sstevel@tonic-gate mutex_init(&it->it_mutex, NULL, MUTEX_DEFAULT, NULL); 538*7c478bd9Sstevel@tonic-gate sigq = kmem_zalloc(sizeof (sigqueue_t), KM_SLEEP); 539*7c478bd9Sstevel@tonic-gate 540*7c478bd9Sstevel@tonic-gate mutex_enter(&p->p_lock); 541*7c478bd9Sstevel@tonic-gate 542*7c478bd9Sstevel@tonic-gate /* 543*7c478bd9Sstevel@tonic-gate * If this is this process' first timer, we need to attempt to allocate 544*7c478bd9Sstevel@tonic-gate * an array of timerstr_t pointers. We drop p_lock to perform the 545*7c478bd9Sstevel@tonic-gate * allocation; if we return to discover that p_itimer is non-NULL, 546*7c478bd9Sstevel@tonic-gate * we will free our allocation and drive on. 547*7c478bd9Sstevel@tonic-gate */ 548*7c478bd9Sstevel@tonic-gate if ((itp = p->p_itimer) == NULL) { 549*7c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock); 550*7c478bd9Sstevel@tonic-gate itp = kmem_zalloc(timer_max * sizeof (itimer_t *), KM_SLEEP); 551*7c478bd9Sstevel@tonic-gate mutex_enter(&p->p_lock); 552*7c478bd9Sstevel@tonic-gate 553*7c478bd9Sstevel@tonic-gate if (p->p_itimer == NULL) 554*7c478bd9Sstevel@tonic-gate p->p_itimer = itp; 555*7c478bd9Sstevel@tonic-gate else { 556*7c478bd9Sstevel@tonic-gate kmem_free(itp, timer_max * sizeof (itimer_t *)); 557*7c478bd9Sstevel@tonic-gate itp = p->p_itimer; 558*7c478bd9Sstevel@tonic-gate } 559*7c478bd9Sstevel@tonic-gate } 560*7c478bd9Sstevel@tonic-gate 561*7c478bd9Sstevel@tonic-gate for (i = 0; i < timer_max && itp[i] != NULL; i++) 562*7c478bd9Sstevel@tonic-gate continue; 563*7c478bd9Sstevel@tonic-gate 564*7c478bd9Sstevel@tonic-gate if (i == timer_max) { 565*7c478bd9Sstevel@tonic-gate /* 566*7c478bd9Sstevel@tonic-gate * We couldn't find a slot. Drop p_lock, free the preallocated 567*7c478bd9Sstevel@tonic-gate * timer and sigqueue, and return an error. 568*7c478bd9Sstevel@tonic-gate */ 569*7c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock); 570*7c478bd9Sstevel@tonic-gate kmem_cache_free(clock_timer_cache, it); 571*7c478bd9Sstevel@tonic-gate kmem_free(sigq, sizeof (sigqueue_t)); 572*7c478bd9Sstevel@tonic-gate 573*7c478bd9Sstevel@tonic-gate return (set_errno(EAGAIN)); 574*7c478bd9Sstevel@tonic-gate } 575*7c478bd9Sstevel@tonic-gate 576*7c478bd9Sstevel@tonic-gate ASSERT(i < timer_max && itp[i] == NULL); 577*7c478bd9Sstevel@tonic-gate 578*7c478bd9Sstevel@tonic-gate /* 579*7c478bd9Sstevel@tonic-gate * If we develop other notification mechanisms, this will need 580*7c478bd9Sstevel@tonic-gate * to call into (yet another) backend. 581*7c478bd9Sstevel@tonic-gate */ 582*7c478bd9Sstevel@tonic-gate sigq->sq_info.si_signo = ev.sigev_signo; 583*7c478bd9Sstevel@tonic-gate sigq->sq_info.si_value = ev.sigev_value; 584*7c478bd9Sstevel@tonic-gate sigq->sq_info.si_code = SI_TIMER; 585*7c478bd9Sstevel@tonic-gate sigq->sq_info.si_pid = p->p_pid; 586*7c478bd9Sstevel@tonic-gate sigq->sq_info.si_ctid = PRCTID(p); 587*7c478bd9Sstevel@tonic-gate sigq->sq_info.si_zoneid = getzoneid(); 588*7c478bd9Sstevel@tonic-gate sigq->sq_info.si_uid = crgetruid(cr); 589*7c478bd9Sstevel@tonic-gate sigq->sq_func = timer_signal; 590*7c478bd9Sstevel@tonic-gate sigq->sq_next = NULL; 591*7c478bd9Sstevel@tonic-gate sigq->sq_backptr = it; 592*7c478bd9Sstevel@tonic-gate it->it_sigq = sigq; 593*7c478bd9Sstevel@tonic-gate it->it_backend = backend; 594*7c478bd9Sstevel@tonic-gate it->it_lock = ITLK_LOCKED; 595*7c478bd9Sstevel@tonic-gate itp[i] = it; 596*7c478bd9Sstevel@tonic-gate 597*7c478bd9Sstevel@tonic-gate 598*7c478bd9Sstevel@tonic-gate if (ev.sigev_notify == SIGEV_PORT) { 599*7c478bd9Sstevel@tonic-gate int port; 600*7c478bd9Sstevel@tonic-gate 601*7c478bd9Sstevel@tonic-gate /* 602*7c478bd9Sstevel@tonic-gate * This timer is programmed to use event port notification when 603*7c478bd9Sstevel@tonic-gate * the timer fires: 604*7c478bd9Sstevel@tonic-gate * - allocate a port event structure and prepare it to be sent 605*7c478bd9Sstevel@tonic-gate * to the port as soon as the timer fires. 606*7c478bd9Sstevel@tonic-gate * - when the timer fires : 607*7c478bd9Sstevel@tonic-gate * - if event structure was already sent to the port then this 608*7c478bd9Sstevel@tonic-gate * is a timer fire overflow => increment overflow counter. 609*7c478bd9Sstevel@tonic-gate * - otherwise send pre-allocated event structure to the port. 610*7c478bd9Sstevel@tonic-gate * - the events field of the port_event_t structure counts the 611*7c478bd9Sstevel@tonic-gate * number of timer fired events. 612*7c478bd9Sstevel@tonic-gate * - The event structured is allocated using the 613*7c478bd9Sstevel@tonic-gate * PORT_ALLOC_CACHED flag. 614*7c478bd9Sstevel@tonic-gate * This flag indicates that the timer itself will manage and 615*7c478bd9Sstevel@tonic-gate * free the event structure when required. 616*7c478bd9Sstevel@tonic-gate */ 617*7c478bd9Sstevel@tonic-gate 618*7c478bd9Sstevel@tonic-gate it->it_flags |= IT_PORT; 619*7c478bd9Sstevel@tonic-gate port = tim_pnevp.portnfy_port; 620*7c478bd9Sstevel@tonic-gate 621*7c478bd9Sstevel@tonic-gate /* associate timer as event source with the port */ 622*7c478bd9Sstevel@tonic-gate error = port_associate_ksource(port, PORT_SOURCE_TIMER, 623*7c478bd9Sstevel@tonic-gate (port_source_t **)&it->it_portsrc, timer_close_port, 624*7c478bd9Sstevel@tonic-gate (void *)it, NULL); 625*7c478bd9Sstevel@tonic-gate if (error) { 626*7c478bd9Sstevel@tonic-gate itp[i] = NULL; /* clear slot */ 627*7c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock); 628*7c478bd9Sstevel@tonic-gate kmem_cache_free(clock_timer_cache, it); 629*7c478bd9Sstevel@tonic-gate kmem_free(sigq, sizeof (sigqueue_t)); 630*7c478bd9Sstevel@tonic-gate return (set_errno(error)); 631*7c478bd9Sstevel@tonic-gate } 632*7c478bd9Sstevel@tonic-gate 633*7c478bd9Sstevel@tonic-gate /* allocate an event structure/slot */ 634*7c478bd9Sstevel@tonic-gate error = port_alloc_event(port, PORT_ALLOC_SCACHED, 635*7c478bd9Sstevel@tonic-gate PORT_SOURCE_TIMER, &pkevp); 636*7c478bd9Sstevel@tonic-gate if (error) { 637*7c478bd9Sstevel@tonic-gate (void) port_dissociate_ksource(port, PORT_SOURCE_TIMER, 638*7c478bd9Sstevel@tonic-gate (port_source_t *)it->it_portsrc); 639*7c478bd9Sstevel@tonic-gate itp[i] = NULL; /* clear slot */ 640*7c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock); 641*7c478bd9Sstevel@tonic-gate kmem_cache_free(clock_timer_cache, it); 642*7c478bd9Sstevel@tonic-gate kmem_free(sigq, sizeof (sigqueue_t)); 643*7c478bd9Sstevel@tonic-gate return (set_errno(error)); 644*7c478bd9Sstevel@tonic-gate } 645*7c478bd9Sstevel@tonic-gate 646*7c478bd9Sstevel@tonic-gate /* initialize event data */ 647*7c478bd9Sstevel@tonic-gate port_init_event(pkevp, i, tim_pnevp.portnfy_user, 648*7c478bd9Sstevel@tonic-gate timer_port_callback, it); 649*7c478bd9Sstevel@tonic-gate it->it_portev = pkevp; 650*7c478bd9Sstevel@tonic-gate it->it_portfd = port; 651*7c478bd9Sstevel@tonic-gate } else { 652*7c478bd9Sstevel@tonic-gate if (ev.sigev_notify == SIGEV_SIGNAL) 653*7c478bd9Sstevel@tonic-gate it->it_flags |= IT_SIGNAL; 654*7c478bd9Sstevel@tonic-gate } 655*7c478bd9Sstevel@tonic-gate 656*7c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock); 657*7c478bd9Sstevel@tonic-gate 658*7c478bd9Sstevel@tonic-gate /* 659*7c478bd9Sstevel@tonic-gate * Call on the backend to verify the event argument (or return 660*7c478bd9Sstevel@tonic-gate * EINVAL if this clock type does not support timers). 661*7c478bd9Sstevel@tonic-gate */ 662*7c478bd9Sstevel@tonic-gate if ((error = backend->clk_timer_create(it, &ev)) != 0) 663*7c478bd9Sstevel@tonic-gate goto err; 664*7c478bd9Sstevel@tonic-gate 665*7c478bd9Sstevel@tonic-gate it->it_lwp = ttolwp(curthread); 666*7c478bd9Sstevel@tonic-gate it->it_proc = p; 667*7c478bd9Sstevel@tonic-gate 668*7c478bd9Sstevel@tonic-gate if (copyout(&i, tid, sizeof (timer_t)) != 0) { 669*7c478bd9Sstevel@tonic-gate error = EFAULT; 670*7c478bd9Sstevel@tonic-gate goto err; 671*7c478bd9Sstevel@tonic-gate } 672*7c478bd9Sstevel@tonic-gate 673*7c478bd9Sstevel@tonic-gate /* 674*7c478bd9Sstevel@tonic-gate * If we're here, then we have successfully created the timer; we 675*7c478bd9Sstevel@tonic-gate * just need to release the timer and return. 676*7c478bd9Sstevel@tonic-gate */ 677*7c478bd9Sstevel@tonic-gate timer_release(p, it); 678*7c478bd9Sstevel@tonic-gate 679*7c478bd9Sstevel@tonic-gate return (0); 680*7c478bd9Sstevel@tonic-gate 681*7c478bd9Sstevel@tonic-gate err: 682*7c478bd9Sstevel@tonic-gate /* 683*7c478bd9Sstevel@tonic-gate * If we're here, an error has occurred late in the timer creation 684*7c478bd9Sstevel@tonic-gate * process. We need to regrab p_lock, and delete the incipient timer. 685*7c478bd9Sstevel@tonic-gate * Since we never unlocked the timer (it was born locked), it's 686*7c478bd9Sstevel@tonic-gate * impossible for a removal to be pending. 687*7c478bd9Sstevel@tonic-gate */ 688*7c478bd9Sstevel@tonic-gate ASSERT(!(it->it_lock & ITLK_REMOVE)); 689*7c478bd9Sstevel@tonic-gate timer_delete_grabbed(p, i, it); 690*7c478bd9Sstevel@tonic-gate 691*7c478bd9Sstevel@tonic-gate return (set_errno(error)); 692*7c478bd9Sstevel@tonic-gate } 693*7c478bd9Sstevel@tonic-gate 694*7c478bd9Sstevel@tonic-gate int 695*7c478bd9Sstevel@tonic-gate timer_gettime(timer_t tid, itimerspec_t *val) 696*7c478bd9Sstevel@tonic-gate { 697*7c478bd9Sstevel@tonic-gate proc_t *p = curproc; 698*7c478bd9Sstevel@tonic-gate itimer_t *it; 699*7c478bd9Sstevel@tonic-gate itimerspec_t when; 700*7c478bd9Sstevel@tonic-gate int error; 701*7c478bd9Sstevel@tonic-gate 702*7c478bd9Sstevel@tonic-gate if ((it = timer_grab(p, tid)) == NULL) 703*7c478bd9Sstevel@tonic-gate return (set_errno(EINVAL)); 704*7c478bd9Sstevel@tonic-gate 705*7c478bd9Sstevel@tonic-gate error = it->it_backend->clk_timer_gettime(it, &when); 706*7c478bd9Sstevel@tonic-gate 707*7c478bd9Sstevel@tonic-gate timer_release(p, it); 708*7c478bd9Sstevel@tonic-gate 709*7c478bd9Sstevel@tonic-gate if (error == 0) { 710*7c478bd9Sstevel@tonic-gate if (get_udatamodel() == DATAMODEL_NATIVE) { 711*7c478bd9Sstevel@tonic-gate if (copyout(&when, val, sizeof (itimerspec_t))) 712*7c478bd9Sstevel@tonic-gate error = EFAULT; 713*7c478bd9Sstevel@tonic-gate } else { 714*7c478bd9Sstevel@tonic-gate if (ITIMERSPEC_OVERFLOW(&when)) 715*7c478bd9Sstevel@tonic-gate error = EOVERFLOW; 716*7c478bd9Sstevel@tonic-gate else { 717*7c478bd9Sstevel@tonic-gate itimerspec32_t w32; 718*7c478bd9Sstevel@tonic-gate 719*7c478bd9Sstevel@tonic-gate ITIMERSPEC_TO_ITIMERSPEC32(&w32, &when) 720*7c478bd9Sstevel@tonic-gate if (copyout(&w32, val, sizeof (itimerspec32_t))) 721*7c478bd9Sstevel@tonic-gate error = EFAULT; 722*7c478bd9Sstevel@tonic-gate } 723*7c478bd9Sstevel@tonic-gate } 724*7c478bd9Sstevel@tonic-gate } 725*7c478bd9Sstevel@tonic-gate 726*7c478bd9Sstevel@tonic-gate return (error ? set_errno(error) : 0); 727*7c478bd9Sstevel@tonic-gate } 728*7c478bd9Sstevel@tonic-gate 729*7c478bd9Sstevel@tonic-gate int 730*7c478bd9Sstevel@tonic-gate timer_settime(timer_t tid, int flags, itimerspec_t *val, itimerspec_t *oval) 731*7c478bd9Sstevel@tonic-gate { 732*7c478bd9Sstevel@tonic-gate itimerspec_t when; 733*7c478bd9Sstevel@tonic-gate timespec_t res; 734*7c478bd9Sstevel@tonic-gate itimer_t *it; 735*7c478bd9Sstevel@tonic-gate proc_t *p = curproc; 736*7c478bd9Sstevel@tonic-gate int error; 737*7c478bd9Sstevel@tonic-gate 738*7c478bd9Sstevel@tonic-gate if (oval != NULL) { 739*7c478bd9Sstevel@tonic-gate if ((error = timer_gettime(tid, oval)) != 0) 740*7c478bd9Sstevel@tonic-gate return (error); 741*7c478bd9Sstevel@tonic-gate } 742*7c478bd9Sstevel@tonic-gate 743*7c478bd9Sstevel@tonic-gate if (get_udatamodel() == DATAMODEL_NATIVE) { 744*7c478bd9Sstevel@tonic-gate if (copyin(val, &when, sizeof (itimerspec_t))) 745*7c478bd9Sstevel@tonic-gate return (set_errno(EFAULT)); 746*7c478bd9Sstevel@tonic-gate } else { 747*7c478bd9Sstevel@tonic-gate itimerspec32_t w32; 748*7c478bd9Sstevel@tonic-gate 749*7c478bd9Sstevel@tonic-gate if (copyin(val, &w32, sizeof (itimerspec32_t))) 750*7c478bd9Sstevel@tonic-gate return (set_errno(EFAULT)); 751*7c478bd9Sstevel@tonic-gate 752*7c478bd9Sstevel@tonic-gate ITIMERSPEC32_TO_ITIMERSPEC(&when, &w32); 753*7c478bd9Sstevel@tonic-gate } 754*7c478bd9Sstevel@tonic-gate 755*7c478bd9Sstevel@tonic-gate if (itimerspecfix(&when.it_value) || 756*7c478bd9Sstevel@tonic-gate (itimerspecfix(&when.it_interval) && 757*7c478bd9Sstevel@tonic-gate timerspecisset(&when.it_value))) { 758*7c478bd9Sstevel@tonic-gate return (set_errno(EINVAL)); 759*7c478bd9Sstevel@tonic-gate } 760*7c478bd9Sstevel@tonic-gate 761*7c478bd9Sstevel@tonic-gate if ((it = timer_grab(p, tid)) == NULL) 762*7c478bd9Sstevel@tonic-gate return (set_errno(EINVAL)); 763*7c478bd9Sstevel@tonic-gate 764*7c478bd9Sstevel@tonic-gate /* 765*7c478bd9Sstevel@tonic-gate * From the man page: 766*7c478bd9Sstevel@tonic-gate * Time values that are between two consecutive non-negative 767*7c478bd9Sstevel@tonic-gate * integer multiples of the resolution of the specified timer 768*7c478bd9Sstevel@tonic-gate * shall be rounded up to the larger multiple of the resolution. 769*7c478bd9Sstevel@tonic-gate * We assume that the resolution of any clock is less than one second. 770*7c478bd9Sstevel@tonic-gate */ 771*7c478bd9Sstevel@tonic-gate if (it->it_backend->clk_clock_getres(&res) == 0 && res.tv_nsec > 1) { 772*7c478bd9Sstevel@tonic-gate long rem; 773*7c478bd9Sstevel@tonic-gate 774*7c478bd9Sstevel@tonic-gate if ((rem = when.it_interval.tv_nsec % res.tv_nsec) != 0) { 775*7c478bd9Sstevel@tonic-gate when.it_interval.tv_nsec += res.tv_nsec - rem; 776*7c478bd9Sstevel@tonic-gate timespecfix(&when.it_interval); 777*7c478bd9Sstevel@tonic-gate } 778*7c478bd9Sstevel@tonic-gate if ((rem = when.it_value.tv_nsec % res.tv_nsec) != 0) { 779*7c478bd9Sstevel@tonic-gate when.it_value.tv_nsec += res.tv_nsec - rem; 780*7c478bd9Sstevel@tonic-gate timespecfix(&when.it_value); 781*7c478bd9Sstevel@tonic-gate } 782*7c478bd9Sstevel@tonic-gate } 783*7c478bd9Sstevel@tonic-gate error = it->it_backend->clk_timer_settime(it, flags, &when); 784*7c478bd9Sstevel@tonic-gate 785*7c478bd9Sstevel@tonic-gate timer_release(p, it); 786*7c478bd9Sstevel@tonic-gate 787*7c478bd9Sstevel@tonic-gate return (error ? set_errno(error) : 0); 788*7c478bd9Sstevel@tonic-gate } 789*7c478bd9Sstevel@tonic-gate 790*7c478bd9Sstevel@tonic-gate int 791*7c478bd9Sstevel@tonic-gate timer_delete(timer_t tid) 792*7c478bd9Sstevel@tonic-gate { 793*7c478bd9Sstevel@tonic-gate proc_t *p = curproc; 794*7c478bd9Sstevel@tonic-gate itimer_t *it; 795*7c478bd9Sstevel@tonic-gate 796*7c478bd9Sstevel@tonic-gate if ((it = timer_grab(p, tid)) == NULL) 797*7c478bd9Sstevel@tonic-gate return (set_errno(EINVAL)); 798*7c478bd9Sstevel@tonic-gate 799*7c478bd9Sstevel@tonic-gate timer_delete_grabbed(p, tid, it); 800*7c478bd9Sstevel@tonic-gate 801*7c478bd9Sstevel@tonic-gate return (0); 802*7c478bd9Sstevel@tonic-gate } 803*7c478bd9Sstevel@tonic-gate 804*7c478bd9Sstevel@tonic-gate int 805*7c478bd9Sstevel@tonic-gate timer_getoverrun(timer_t tid) 806*7c478bd9Sstevel@tonic-gate { 807*7c478bd9Sstevel@tonic-gate int overrun; 808*7c478bd9Sstevel@tonic-gate proc_t *p = curproc; 809*7c478bd9Sstevel@tonic-gate itimer_t *it; 810*7c478bd9Sstevel@tonic-gate 811*7c478bd9Sstevel@tonic-gate if ((it = timer_grab(p, tid)) == NULL) 812*7c478bd9Sstevel@tonic-gate return (set_errno(EINVAL)); 813*7c478bd9Sstevel@tonic-gate 814*7c478bd9Sstevel@tonic-gate /* 815*7c478bd9Sstevel@tonic-gate * The it_overrun field is protected by p_lock; we need to acquire 816*7c478bd9Sstevel@tonic-gate * it before looking at the value. 817*7c478bd9Sstevel@tonic-gate */ 818*7c478bd9Sstevel@tonic-gate mutex_enter(&p->p_lock); 819*7c478bd9Sstevel@tonic-gate overrun = it->it_overrun; 820*7c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock); 821*7c478bd9Sstevel@tonic-gate 822*7c478bd9Sstevel@tonic-gate timer_release(p, it); 823*7c478bd9Sstevel@tonic-gate 824*7c478bd9Sstevel@tonic-gate return (overrun); 825*7c478bd9Sstevel@tonic-gate } 826*7c478bd9Sstevel@tonic-gate 827*7c478bd9Sstevel@tonic-gate /* 828*7c478bd9Sstevel@tonic-gate * Entered/exited with p_lock held, but will repeatedly drop and regrab p_lock. 829*7c478bd9Sstevel@tonic-gate */ 830*7c478bd9Sstevel@tonic-gate void 831*7c478bd9Sstevel@tonic-gate timer_lwpexit(void) 832*7c478bd9Sstevel@tonic-gate { 833*7c478bd9Sstevel@tonic-gate timer_t i; 834*7c478bd9Sstevel@tonic-gate proc_t *p = curproc; 835*7c478bd9Sstevel@tonic-gate klwp_t *lwp = ttolwp(curthread); 836*7c478bd9Sstevel@tonic-gate itimer_t *it, **itp; 837*7c478bd9Sstevel@tonic-gate 838*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&p->p_lock)); 839*7c478bd9Sstevel@tonic-gate 840*7c478bd9Sstevel@tonic-gate if ((itp = p->p_itimer) == NULL) 841*7c478bd9Sstevel@tonic-gate return; 842*7c478bd9Sstevel@tonic-gate 843*7c478bd9Sstevel@tonic-gate for (i = 0; i < timer_max; i++) { 844*7c478bd9Sstevel@tonic-gate if ((it = itp[i]) == NULL) 845*7c478bd9Sstevel@tonic-gate continue; 846*7c478bd9Sstevel@tonic-gate 847*7c478bd9Sstevel@tonic-gate timer_lock(p, it); 848*7c478bd9Sstevel@tonic-gate 849*7c478bd9Sstevel@tonic-gate if ((it->it_lock & ITLK_REMOVE) || it->it_lwp != lwp) { 850*7c478bd9Sstevel@tonic-gate /* 851*7c478bd9Sstevel@tonic-gate * This timer is either being removed or it isn't 852*7c478bd9Sstevel@tonic-gate * associated with this lwp. 853*7c478bd9Sstevel@tonic-gate */ 854*7c478bd9Sstevel@tonic-gate timer_unlock(p, it); 855*7c478bd9Sstevel@tonic-gate continue; 856*7c478bd9Sstevel@tonic-gate } 857*7c478bd9Sstevel@tonic-gate 858*7c478bd9Sstevel@tonic-gate /* 859*7c478bd9Sstevel@tonic-gate * The LWP that created this timer is going away. To the user, 860*7c478bd9Sstevel@tonic-gate * our behavior here is explicitly undefined. We will simply 861*7c478bd9Sstevel@tonic-gate * null out the it_lwp field; if the LWP was bound to a CPU, 862*7c478bd9Sstevel@tonic-gate * the cyclic will stay bound to that CPU until the process 863*7c478bd9Sstevel@tonic-gate * exits. 864*7c478bd9Sstevel@tonic-gate */ 865*7c478bd9Sstevel@tonic-gate it->it_lwp = NULL; 866*7c478bd9Sstevel@tonic-gate timer_unlock(p, it); 867*7c478bd9Sstevel@tonic-gate } 868*7c478bd9Sstevel@tonic-gate } 869*7c478bd9Sstevel@tonic-gate 870*7c478bd9Sstevel@tonic-gate /* 871*7c478bd9Sstevel@tonic-gate * Called to notify of an LWP binding change. Entered/exited with p_lock 872*7c478bd9Sstevel@tonic-gate * held, but will repeatedly drop and regrab p_lock. 873*7c478bd9Sstevel@tonic-gate */ 874*7c478bd9Sstevel@tonic-gate void 875*7c478bd9Sstevel@tonic-gate timer_lwpbind() 876*7c478bd9Sstevel@tonic-gate { 877*7c478bd9Sstevel@tonic-gate timer_t i; 878*7c478bd9Sstevel@tonic-gate proc_t *p = curproc; 879*7c478bd9Sstevel@tonic-gate klwp_t *lwp = ttolwp(curthread); 880*7c478bd9Sstevel@tonic-gate itimer_t *it, **itp; 881*7c478bd9Sstevel@tonic-gate 882*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&p->p_lock)); 883*7c478bd9Sstevel@tonic-gate 884*7c478bd9Sstevel@tonic-gate if ((itp = p->p_itimer) == NULL) 885*7c478bd9Sstevel@tonic-gate return; 886*7c478bd9Sstevel@tonic-gate 887*7c478bd9Sstevel@tonic-gate for (i = 0; i < timer_max; i++) { 888*7c478bd9Sstevel@tonic-gate if ((it = itp[i]) == NULL) 889*7c478bd9Sstevel@tonic-gate continue; 890*7c478bd9Sstevel@tonic-gate 891*7c478bd9Sstevel@tonic-gate timer_lock(p, it); 892*7c478bd9Sstevel@tonic-gate 893*7c478bd9Sstevel@tonic-gate if (!(it->it_lock & ITLK_REMOVE) && it->it_lwp == lwp) { 894*7c478bd9Sstevel@tonic-gate /* 895*7c478bd9Sstevel@tonic-gate * Drop p_lock and jump into the backend. 896*7c478bd9Sstevel@tonic-gate */ 897*7c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock); 898*7c478bd9Sstevel@tonic-gate it->it_backend->clk_timer_lwpbind(it); 899*7c478bd9Sstevel@tonic-gate mutex_enter(&p->p_lock); 900*7c478bd9Sstevel@tonic-gate } 901*7c478bd9Sstevel@tonic-gate 902*7c478bd9Sstevel@tonic-gate timer_unlock(p, it); 903*7c478bd9Sstevel@tonic-gate } 904*7c478bd9Sstevel@tonic-gate } 905*7c478bd9Sstevel@tonic-gate 906*7c478bd9Sstevel@tonic-gate /* 907*7c478bd9Sstevel@tonic-gate * This function should only be called if p_itimer is non-NULL. 908*7c478bd9Sstevel@tonic-gate */ 909*7c478bd9Sstevel@tonic-gate void 910*7c478bd9Sstevel@tonic-gate timer_exit(void) 911*7c478bd9Sstevel@tonic-gate { 912*7c478bd9Sstevel@tonic-gate timer_t i; 913*7c478bd9Sstevel@tonic-gate proc_t *p = curproc; 914*7c478bd9Sstevel@tonic-gate 915*7c478bd9Sstevel@tonic-gate ASSERT(p->p_itimer != NULL); 916*7c478bd9Sstevel@tonic-gate 917*7c478bd9Sstevel@tonic-gate for (i = 0; i < timer_max; i++) 918*7c478bd9Sstevel@tonic-gate (void) timer_delete(i); 919*7c478bd9Sstevel@tonic-gate 920*7c478bd9Sstevel@tonic-gate kmem_free(p->p_itimer, timer_max * sizeof (itimer_t *)); 921*7c478bd9Sstevel@tonic-gate p->p_itimer = NULL; 922*7c478bd9Sstevel@tonic-gate } 923*7c478bd9Sstevel@tonic-gate 924*7c478bd9Sstevel@tonic-gate /* 925*7c478bd9Sstevel@tonic-gate * timer_port_callback() is a callback function which is associated with the 926*7c478bd9Sstevel@tonic-gate * timer event and is activated just before the event is delivered to the user. 927*7c478bd9Sstevel@tonic-gate * The timer uses this function to update/set the overflow counter and 928*7c478bd9Sstevel@tonic-gate * to reenable the use of the event structure. 929*7c478bd9Sstevel@tonic-gate */ 930*7c478bd9Sstevel@tonic-gate 931*7c478bd9Sstevel@tonic-gate /* ARGSUSED */ 932*7c478bd9Sstevel@tonic-gate static int 933*7c478bd9Sstevel@tonic-gate timer_port_callback(void *arg, int *events, pid_t pid, int flag, void *evp) 934*7c478bd9Sstevel@tonic-gate { 935*7c478bd9Sstevel@tonic-gate itimer_t *it = arg; 936*7c478bd9Sstevel@tonic-gate 937*7c478bd9Sstevel@tonic-gate mutex_enter(&it->it_mutex); 938*7c478bd9Sstevel@tonic-gate if (curproc != it->it_proc) { 939*7c478bd9Sstevel@tonic-gate /* can not deliver timer events to another proc */ 940*7c478bd9Sstevel@tonic-gate mutex_exit(&it->it_mutex); 941*7c478bd9Sstevel@tonic-gate return (EACCES); 942*7c478bd9Sstevel@tonic-gate } 943*7c478bd9Sstevel@tonic-gate *events = it->it_pending; /* 1 = 1 event, >1 # of overflows */ 944*7c478bd9Sstevel@tonic-gate it->it_pending = 0; /* reinit overflow counter */ 945*7c478bd9Sstevel@tonic-gate /* 946*7c478bd9Sstevel@tonic-gate * This function can also be activated when the port is being closed 947*7c478bd9Sstevel@tonic-gate * and a timer event is already submitted to the port. 948*7c478bd9Sstevel@tonic-gate * In such a case the event port framework will use the 949*7c478bd9Sstevel@tonic-gate * close-callback function to notify the events sources. 950*7c478bd9Sstevel@tonic-gate * The timer close-callback function is timer_close_port() which 951*7c478bd9Sstevel@tonic-gate * will free all allocated resources (including the allocated 952*7c478bd9Sstevel@tonic-gate * port event structure). 953*7c478bd9Sstevel@tonic-gate * For that reason we don't need to check the value of flag here. 954*7c478bd9Sstevel@tonic-gate */ 955*7c478bd9Sstevel@tonic-gate mutex_exit(&it->it_mutex); 956*7c478bd9Sstevel@tonic-gate return (0); 957*7c478bd9Sstevel@tonic-gate } 958*7c478bd9Sstevel@tonic-gate 959*7c478bd9Sstevel@tonic-gate /* 960*7c478bd9Sstevel@tonic-gate * port is being closed ... free all allocated port event structures 961*7c478bd9Sstevel@tonic-gate * The delivered arg currently correspond to the first timer associated with 962*7c478bd9Sstevel@tonic-gate * the port and it is not useable in this case. 963*7c478bd9Sstevel@tonic-gate * We have to scan the list of activated timers in the current proc and 964*7c478bd9Sstevel@tonic-gate * compare them with the delivered port id. 965*7c478bd9Sstevel@tonic-gate */ 966*7c478bd9Sstevel@tonic-gate 967*7c478bd9Sstevel@tonic-gate /* ARGSUSED */ 968*7c478bd9Sstevel@tonic-gate static void 969*7c478bd9Sstevel@tonic-gate timer_close_port(void *arg, int port, pid_t pid, int lastclose) 970*7c478bd9Sstevel@tonic-gate { 971*7c478bd9Sstevel@tonic-gate proc_t *p = curproc; 972*7c478bd9Sstevel@tonic-gate timer_t tid; 973*7c478bd9Sstevel@tonic-gate itimer_t *it; 974*7c478bd9Sstevel@tonic-gate 975*7c478bd9Sstevel@tonic-gate for (tid = 0; tid < timer_max; tid++) { 976*7c478bd9Sstevel@tonic-gate if ((it = timer_grab(p, tid)) == NULL) 977*7c478bd9Sstevel@tonic-gate continue; 978*7c478bd9Sstevel@tonic-gate if (it->it_portev) { 979*7c478bd9Sstevel@tonic-gate mutex_enter(&it->it_mutex); 980*7c478bd9Sstevel@tonic-gate if (it->it_portfd == port) { 981*7c478bd9Sstevel@tonic-gate port_free_event((port_kevent_t *)it->it_portev); 982*7c478bd9Sstevel@tonic-gate it->it_portev = NULL; 983*7c478bd9Sstevel@tonic-gate it->it_flags &= ~IT_PORT; 984*7c478bd9Sstevel@tonic-gate } 985*7c478bd9Sstevel@tonic-gate mutex_exit(&it->it_mutex); 986*7c478bd9Sstevel@tonic-gate } 987*7c478bd9Sstevel@tonic-gate timer_release(p, it); 988*7c478bd9Sstevel@tonic-gate } 989*7c478bd9Sstevel@tonic-gate } 990