xref: /illumos-gate/usr/src/uts/common/os/timer.c (revision 7c478bd9)
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