4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
28 #include <sys/systm.h>
29 #include <sys/debug.h>
30 #include <sys/mutex.h>
31 #include <sys/atomic.h>
32 #include <sys/timer.h>
33 #include <sys/lwp_timer_impl.h>
34 #include <sys/callo.h>
37 * lwp_timer_timeout() is called from a timeout set up in lwp_cond_wait(),
38 * lwp_mutex_timedlock(), lwp_sema_timedwait() or lwp_rwlock_lock().
40 * It recomputes the time remaining until the absolute time when the
41 * wait is supposed to timeout and either calls realtime_timeout()
42 * to reschedule itself or calls setrun() on the sleeping thread.
44 * This is done to ensure that the waiting thread does not wake up
45 * due to timer expiration until the absolute future time of the
46 * timeout has been reached. Until that time, the thread must
47 * remain on its sleep queue.
49 * An lwp_timer_t structure is used to pass information
50 * about the sleeping thread to the timeout function.
54 lwp_timer_timeout(void *arg
)
56 lwp_timer_t
*lwptp
= arg
;
57 kthread_t
*t
= lwptp
->lwpt_thread
;
58 timespec_t now
, delta
;
60 mutex_enter(&t
->t_delay_lock
);
63 * Requeue the timeout if no one has reset the system time
64 * and if the absolute future time has not been reached.
66 if (lwptp
->lwpt_timecheck
== timechanged
&&
67 (lwptp
->lwpt_rqtime
.tv_sec
> now
.tv_sec
||
68 (lwptp
->lwpt_rqtime
.tv_sec
== now
.tv_sec
&&
69 lwptp
->lwpt_rqtime
.tv_nsec
> now
.tv_nsec
))) {
70 lwptp
->lwpt_imm_timeout
= 0;
71 delta
= lwptp
->lwpt_rqtime
;
72 timespecsub(&delta
, &now
);
73 lwptp
->lwpt_id
= timeout_generic(CALLOUT_REALTIME
,
74 lwp_timer_timeout
, lwptp
, ts2hrt(&delta
), nsec_per_tick
,
75 (CALLOUT_FLAG_HRESTIME
| CALLOUT_FLAG_ROUNDUP
));
78 * Set the thread running only if it is asleep on
79 * its lwpchan sleep queue (not if it is asleep on
80 * the t_delay_lock mutex).
83 /* do this for the benefit of upi mutexes */
84 (void) atomic_cas_uint(&lwptp
->lwpt_imm_timeout
, 0, 1);
85 if (t
->t_state
== TS_SLEEP
&&
86 (t
->t_flag
& T_WAKEABLE
) &&
91 mutex_exit(&t
->t_delay_lock
);
95 lwp_timer_copyin(lwp_timer_t
*lwptp
, timespec_t
*tsp
)
100 if (tsp
== NULL
) /* not really an error, just need to bzero() */
102 lwptp
->lwpt_timecheck
= timechanged
; /* do this before gethrestime() */
103 gethrestime(&now
); /* do this before copyin() */
104 if (curproc
->p_model
== DATAMODEL_NATIVE
) {
105 if (copyin(tsp
, &lwptp
->lwpt_rqtime
, sizeof (timespec_t
))) {
111 if (copyin(tsp
, &ts32
, sizeof (timespec32_t
))) {
115 TIMESPEC32_TO_TIMESPEC(&lwptp
->lwpt_rqtime
, &ts32
);
117 if (itimerspecfix(&lwptp
->lwpt_rqtime
)) {
122 * Unless the requested timeout is zero,
123 * get the precise future (absolute) time at
124 * which we are to time out and return ETIME.
125 * We must not return ETIME before that time.
127 if (lwptp
->lwpt_rqtime
.tv_sec
== 0 && lwptp
->lwpt_rqtime
.tv_nsec
== 0) {
128 bzero(lwptp
, sizeof (lwp_timer_t
));
129 lwptp
->lwpt_imm_timeout
= 1;
131 lwptp
->lwpt_thread
= curthread
;
132 lwptp
->lwpt_tsp
= tsp
;
133 lwptp
->lwpt_time_error
= 0;
135 lwptp
->lwpt_imm_timeout
= 0;
136 timespecadd(&lwptp
->lwpt_rqtime
, &now
);
140 bzero(lwptp
, sizeof (lwp_timer_t
));
141 lwptp
->lwpt_time_error
= error
;
146 lwp_timer_enqueue(lwp_timer_t
*lwptp
)
148 timespec_t now
, delta
;
150 ASSERT(lwptp
->lwpt_thread
== curthread
);
151 ASSERT(MUTEX_HELD(&curthread
->t_delay_lock
));
153 if (lwptp
->lwpt_timecheck
== timechanged
&&
154 (lwptp
->lwpt_rqtime
.tv_sec
> now
.tv_sec
||
155 (lwptp
->lwpt_rqtime
.tv_sec
== now
.tv_sec
&&
156 lwptp
->lwpt_rqtime
.tv_nsec
> now
.tv_nsec
))) {
160 lwptp
->lwpt_imm_timeout
= 0;
161 delta
= lwptp
->lwpt_rqtime
;
162 timespecsub(&delta
, &now
);
163 lwptp
->lwpt_id
= timeout_generic(CALLOUT_REALTIME
,
164 lwp_timer_timeout
, lwptp
, ts2hrt(&delta
), nsec_per_tick
,
165 (CALLOUT_FLAG_HRESTIME
| CALLOUT_FLAG_ROUNDUP
));
170 * Time has already run out or someone reset the system time;
171 * just cause an immediate timeout.
173 lwptp
->lwpt_imm_timeout
= 1;
178 lwp_timer_dequeue(lwp_timer_t
*lwptp
)
180 kthread_t
*t
= curthread
;
184 mutex_enter(&t
->t_delay_lock
);
185 while ((tmp_id
= lwptp
->lwpt_id
) != 0) {
187 mutex_exit(&t
->t_delay_lock
);
188 tim
= untimeout_default(tmp_id
, 0);
189 mutex_enter(&t
->t_delay_lock
);
191 mutex_exit(&t
->t_delay_lock
);
196 lwp_timer_copyout(lwp_timer_t
*lwptp
, int error
)
201 if (lwptp
->lwpt_tsp
== NULL
) /* nothing to do */
204 rmtime
.tv_sec
= rmtime
.tv_nsec
= 0;
205 if (error
!= ETIME
) {
207 if ((now
.tv_sec
< lwptp
->lwpt_rqtime
.tv_sec
) ||
208 ((now
.tv_sec
== lwptp
->lwpt_rqtime
.tv_sec
) &&
209 (now
.tv_nsec
< lwptp
->lwpt_rqtime
.tv_nsec
))) {
210 rmtime
= lwptp
->lwpt_rqtime
;
211 timespecsub(&rmtime
, &now
);
214 if (curproc
->p_model
== DATAMODEL_NATIVE
) {
215 if (copyout(&rmtime
, lwptp
->lwpt_tsp
, sizeof (timespec_t
)))
218 timespec32_t rmtime32
;
220 TIMESPEC_TO_TIMESPEC32(&rmtime32
, &rmtime
);
221 if (copyout(&rmtime32
, lwptp
->lwpt_tsp
, sizeof (timespec32_t
)))