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 2008 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #pragma ident "%Z%%M% %I% %E% SMI"
30 #include "thr_uberdata.h"
32 static uint32_t _semvaluemax
;
35 * Check to see if anyone is waiting for this semaphore.
37 #pragma weak _sema_held = sema_held
41 return (sp
->count
== 0);
44 #pragma weak _sema_init = sema_init
47 sema_init(sema_t
*sp
, unsigned int count
, int type
, void *arg
)
49 if (_semvaluemax
== 0)
50 _semvaluemax
= (uint32_t)_sysconf(_SC_SEM_VALUE_MAX
);
51 if ((type
!= USYNC_THREAD
&& type
!= USYNC_PROCESS
) ||
52 (count
> _semvaluemax
))
54 (void) memset(sp
, 0, sizeof (*sp
));
56 sp
->type
= (uint16_t)type
;
57 sp
->magic
= SEMA_MAGIC
;
60 * This should be at the beginning of the function,
61 * but for the sake of old broken applications that
62 * do not have proper alignment for their semaphores
63 * (and don't check the return code from sema_init),
64 * we put it here, after initializing the semaphore regardless.
66 if (((uintptr_t)sp
& (_LONG_LONG_ALIGNMENT
- 1)) &&
67 curthread
->ul_misaligned
== 0)
73 #pragma weak _sema_destroy = sema_destroy
75 sema_destroy(sema_t
*sp
)
78 tdb_sync_obj_deregister(sp
);
83 sema_wait_impl(sema_t
*sp
, timespec_t
*tsp
)
85 lwp_sema_t
*lsp
= (lwp_sema_t
*)sp
;
86 ulwp_t
*self
= curthread
;
87 uberdata_t
*udp
= self
->ul_uberdata
;
88 tdb_sema_stats_t
*ssp
= SEMA_STATS(sp
, udp
);
89 hrtime_t begin_sleep
= 0;
94 * All variations of sema_wait() are cancellation points.
99 tdb_incr(ssp
->sema_wait
);
101 self
->ul_sp
= stkptr();
102 self
->ul_wchan
= lsp
;
103 if (__td_event_report(self
, TD_SLEEP
, udp
)) {
104 self
->ul_td_evbuf
.eventnum
= TD_SLEEP
;
105 self
->ul_td_evbuf
.eventdata
= lsp
;
106 tdb_event(TD_SLEEP
, udp
);
108 /* just a guess, but it looks like we will sleep */
109 if (ssp
&& lsp
->count
== 0) {
110 begin_sleep
= gethrtime();
111 if (lsp
->count
== 0) /* still looks like sleep */
112 tdb_incr(ssp
->sema_wait_sleep
);
113 else /* we changed our mind */
117 if (lsp
->type
== USYNC_PROCESS
) { /* kernel-level */
118 set_parking_flag(self
, 1);
119 if (self
->ul_cursig
!= 0 ||
120 (self
->ul_cancelable
&& self
->ul_cancel_pending
))
121 set_parking_flag(self
, 0);
122 /* the kernel always does FIFO queueing */
123 error
= ___lwp_sema_timedwait(lsp
, tsp
, 1);
124 set_parking_flag(self
, 0);
125 } else if (!udp
->uberflags
.uf_mt
&& /* single threaded */
126 lsp
->count
!= 0) { /* and non-blocking */
128 * Since we are single-threaded, we don't need the
129 * protection of queue_lock(). However, we do need
130 * to block signals while modifying the count.
135 } else { /* multithreaded or blocking */
140 qp
= queue_lock(lsp
, CV
);
141 while (error
== 0 && lsp
->count
== 0) {
143 * SUSV3 requires FIFO queueing for semaphores,
144 * at least for SCHED_FIFO and SCHED_RR scheduling.
146 enqueue(qp
, self
, 1);
147 lsp
->sema_waiters
= 1;
148 set_parking_flag(self
, 1);
151 * We may have received SIGCANCEL before we
152 * called queue_lock(). If so and we are
153 * cancelable we should return EINTR.
155 if (self
->ul_cursig
!= 0 ||
156 (self
->ul_cancelable
&& self
->ul_cancel_pending
))
157 set_parking_flag(self
, 0);
158 error
= __lwp_park(tsp
, 0);
159 set_parking_flag(self
, 0);
160 qp
= queue_lock(lsp
, CV
);
161 if (self
->ul_sleepq
) /* timeout or spurious wakeup */
162 lsp
->sema_waiters
= dequeue_self(qp
);
166 if (lsp
->count
!= 0 && lsp
->sema_waiters
) {
168 if ((ulwp
= dequeue(qp
, &more
)) != NULL
) {
170 lwpid
= ulwp
->ul_lwpid
;
172 lsp
->sema_waiters
= more
;
176 (void) __lwp_unpark(lwpid
);
181 self
->ul_wchan
= NULL
;
185 /* we just decremented the count */
187 if (ssp
->sema_min_count
> count
)
188 ssp
->sema_min_count
= count
;
191 ssp
->sema_wait_sleep_time
+= gethrtime() - begin_sleep
;
197 _canceloff_nocancel();
201 #pragma weak _sema_wait = sema_wait
203 sema_wait(sema_t
*sp
)
205 ASSERT(!curthread
->ul_critical
|| curthread
->ul_bindflags
);
206 return (sema_wait_impl(sp
, NULL
));
210 sema_reltimedwait(sema_t
*sp
, const timespec_t
*reltime
)
212 timespec_t tslocal
= *reltime
;
214 ASSERT(!curthread
->ul_critical
|| curthread
->ul_bindflags
);
215 return (sema_wait_impl(sp
, &tslocal
));
219 sema_timedwait(sema_t
*sp
, const timespec_t
*abstime
)
223 ASSERT(!curthread
->ul_critical
|| curthread
->ul_bindflags
);
224 abstime_to_reltime(CLOCK_REALTIME
, abstime
, &tslocal
);
225 return (sema_wait_impl(sp
, &tslocal
));
228 #pragma weak _sema_trywait = sema_trywait
230 sema_trywait(sema_t
*sp
)
232 lwp_sema_t
*lsp
= (lwp_sema_t
*)sp
;
233 ulwp_t
*self
= curthread
;
234 uberdata_t
*udp
= self
->ul_uberdata
;
235 tdb_sema_stats_t
*ssp
= SEMA_STATS(sp
, udp
);
239 ASSERT(!curthread
->ul_critical
|| curthread
->ul_bindflags
);
242 tdb_incr(ssp
->sema_trywait
);
244 if (lsp
->type
== USYNC_PROCESS
) { /* kernel-level */
245 error
= _lwp_sema_trywait(lsp
);
246 } else if (!udp
->uberflags
.uf_mt
) { /* single threaded */
253 } else { /* multithreaded */
258 qp
= queue_lock(lsp
, CV
);
261 else if (--lsp
->count
!= 0 && lsp
->sema_waiters
) {
263 if ((ulwp
= dequeue(qp
, &more
)) != NULL
) {
265 lwpid
= ulwp
->ul_lwpid
;
267 lsp
->sema_waiters
= more
;
271 (void) __lwp_unpark(lwpid
);
278 /* we just decremented the count */
280 if (ssp
->sema_min_count
> count
)
281 ssp
->sema_min_count
= count
;
285 tdb_incr(ssp
->sema_trywait_fail
);
286 if (__td_event_report(self
, TD_LOCK_TRY
, udp
)) {
287 self
->ul_td_evbuf
.eventnum
= TD_LOCK_TRY
;
288 tdb_event(TD_LOCK_TRY
, udp
);
295 #pragma weak _sema_post = sema_post
297 sema_post(sema_t
*sp
)
299 lwp_sema_t
*lsp
= (lwp_sema_t
*)sp
;
300 ulwp_t
*self
= curthread
;
301 uberdata_t
*udp
= self
->ul_uberdata
;
302 tdb_sema_stats_t
*ssp
= SEMA_STATS(sp
, udp
);
307 tdb_incr(ssp
->sema_post
);
308 if (_semvaluemax
== 0)
309 _semvaluemax
= (uint32_t)_sysconf(_SC_SEM_VALUE_MAX
);
311 if (lsp
->type
== USYNC_PROCESS
) { /* kernel-level */
312 error
= _lwp_sema_post(lsp
);
313 } else if (!udp
->uberflags
.uf_mt
) { /* single threaded */
315 if (lsp
->count
>= _semvaluemax
)
320 } else { /* multithreaded */
325 qp
= queue_lock(lsp
, CV
);
326 if (lsp
->count
>= _semvaluemax
)
328 else if (lsp
->count
++ == 0 && lsp
->sema_waiters
) {
330 if ((ulwp
= dequeue(qp
, &more
)) != NULL
) {
332 lwpid
= ulwp
->ul_lwpid
;
334 lsp
->sema_waiters
= more
;
338 (void) __lwp_unpark(lwpid
);
345 /* we just incremented the count */
347 if (ssp
->sema_max_count
< count
)
348 ssp
->sema_max_count
= count
;