2 * Copyright (c) 2005 David Xu <davidxu@freebsd.org>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice unmodified, this list of conditions, and the following
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 #include "namespace.h"
29 #include <machine/tls.h>
34 #include "un-namespace.h"
36 #include "thr_private.h"
38 #ifdef _PTHREADS_DEBUGGING
44 #define cpu_ccfence() __asm __volatile("" : : : "memory")
46 umtx_t _cond_static_lock
;
48 #ifdef _PTHREADS_DEBUGGING
52 cond_log(const char *ctl
, ...)
59 len
= vsnprintf(buf
, sizeof(buf
), ctl
, va
);
68 cond_log(const char *ctl __unused
, ...)
77 int __pthread_cond_wait(pthread_cond_t
*cond
, pthread_mutex_t
*mutex
);
78 int __pthread_cond_timedwait(pthread_cond_t
*cond
, pthread_mutex_t
*mutex
,
79 const struct timespec
*abstime
);
80 static int cond_wait_common(pthread_cond_t
*cond
, pthread_mutex_t
*mutex
,
81 const struct timespec
*abstime
, int cancel
);
82 static int cond_signal_common(pthread_cond_t
*cond
, int broadcast
);
85 cond_init(pthread_cond_t
*cond
, const pthread_condattr_t
*cond_attr
)
90 if ((pcond
= (pthread_cond_t
)
91 malloc(sizeof(struct pthread_cond
))) == NULL
) {
95 * Initialise the condition variable structure:
97 _thr_umtx_init(&pcond
->c_lock
);
98 if (cond_attr
== NULL
|| *cond_attr
== NULL
) {
100 pcond
->c_clockid
= CLOCK_REALTIME
;
102 pcond
->c_pshared
= (*cond_attr
)->c_pshared
;
103 pcond
->c_clockid
= (*cond_attr
)->c_clockid
;
105 TAILQ_INIT(&pcond
->c_waitlist
);
108 /* Return the completion status: */
114 _cond_reinit(pthread_cond_t cond
)
117 _thr_umtx_init(&cond
->c_lock
);
121 cond
->c_clockid
= CLOCK_REALTIME
;
123 TAILQ_INIT(&cond
->c_waitlist
);
129 init_static(struct pthread
*thread
, pthread_cond_t
*cond
)
133 THR_LOCK_ACQUIRE(thread
, &_cond_static_lock
);
136 ret
= cond_init(cond
, NULL
);
140 THR_LOCK_RELEASE(thread
, &_cond_static_lock
);
146 _pthread_cond_init(pthread_cond_t
*cond
, const pthread_condattr_t
*cond_attr
)
149 return cond_init(cond
, cond_attr
);
153 _pthread_cond_destroy(pthread_cond_t
*cond
)
155 struct pthread_cond
*cv
;
156 struct pthread
*curthread
= tls_get_curthread();
161 else if (*cond
== NULL
)
164 /* Lock the condition variable structure: */
165 THR_LOCK_ACQUIRE(curthread
, &(*cond
)->c_lock
);
166 if (TAILQ_FIRST(&(*cond
)->c_waitlist
)) {
167 THR_LOCK_RELEASE(curthread
, &(*cond
)->c_lock
);
172 * NULL the caller's pointer now that the condition
173 * variable has been destroyed:
178 /* Unlock the condition variable structure: */
179 THR_LOCK_RELEASE(curthread
, &cv
->c_lock
);
181 /* Free the cond lock structure: */
184 * Free the memory allocated for the condition
185 * variable structure:
190 /* Return the completion status: */
194 struct cond_cancel_info
{
195 TAILQ_ENTRY(cond_cancel_info
) entry
;
196 pthread_mutex_t
*mutex
;
197 pthread_cond_t
*cond
;
203 cond_cancel_handler(void *arg
)
205 struct pthread
*curthread
= tls_get_curthread();
206 struct cond_cancel_info
*info
= (struct cond_cancel_info
*)arg
;
210 THR_LOCK_ACQUIRE(curthread
, &cv
->c_lock
);
211 cond_log("cond_cancel %p\n", cv
);
215 cond_log("cond_cancel %p: info %p\n", cv
, info
);
216 TAILQ_REMOVE(&cv
->c_waitlist
, info
, entry
);
217 _thr_umtx_wake(&info
->queued
, 0);
219 THR_LOCK_RELEASE(curthread
, &cv
->c_lock
);
221 /* _mutex_cv_lock(info->mutex, info->count); */
225 * Wait for pthread_cond_t to be signaled.
227 * NOTE: EINTR is ignored and may not be returned by this function.
230 cond_wait_common(pthread_cond_t
*cond
, pthread_mutex_t
*mutex
,
231 const struct timespec
*abstime
, int cancel
)
233 struct pthread
*curthread
= tls_get_curthread();
234 struct timespec ts
, ts2
, *tsp
;
235 struct cond_cancel_info info
;
241 * If the condition variable is statically initialized,
242 * perform the dynamic initialization:
244 cond_log("cond_wait_common %p on mutex %p info %p\n",
245 *cond
, *mutex
, &info
);
246 if (__predict_false(*cond
== NULL
&&
247 (ret
= init_static(curthread
, cond
)) != 0)) {
248 cond_log("cond_wait_common %p (failedA %d)\n", *cond
, ret
);
253 THR_LOCK_ACQUIRE(curthread
, &cv
->c_lock
);
254 ret
= _mutex_cv_unlock(mutex
, &info
.count
);
256 cond_log("cond_wait_common %p (failedB %d)\n", cv
, ret
);
257 THR_LOCK_RELEASE(curthread
, &cv
->c_lock
);
265 TAILQ_INSERT_TAIL(&cv
->c_waitlist
, &info
, entry
);
268 * loop if we have never been told to wake up
271 while (info
.queued
) {
272 THR_LOCK_RELEASE(curthread
, &cv
->c_lock
);
274 if (abstime
!= NULL
) {
275 clock_gettime(cv
->c_clockid
, &ts
);
276 TIMESPEC_SUB(&ts2
, abstime
, &ts
);
283 THR_CLEANUP_PUSH(curthread
, cond_cancel_handler
, &info
);
284 oldcancel
= _thr_cancel_enter(curthread
);
285 ret
= _thr_umtx_wait(&info
.queued
, 1, tsp
,
287 _thr_cancel_leave(curthread
, oldcancel
);
288 THR_CLEANUP_POP(curthread
, 0);
290 ret
= _thr_umtx_wait(&info
.queued
, 1, tsp
,
295 * Ignore EINTR. Make sure ret is 0 if not ETIMEDOUT.
297 THR_LOCK_ACQUIRE(curthread
, &cv
->c_lock
);
298 if (abstime
!= NULL
&& ret
== ETIMEDOUT
)
305 TAILQ_REMOVE(&cv
->c_waitlist
, &info
, entry
);
310 THR_LOCK_RELEASE(curthread
, &cv
->c_lock
);
312 cond_log("cond_wait_common %p (doneA)\n", cv
);
313 _mutex_cv_lock(mutex
, info
.count
);
316 cond_log("cond_wait_common %p (failed %d)\n", cv
, ret
);
318 cond_log("cond_wait_common %p (doneB)\n", cv
);
324 _pthread_cond_wait(pthread_cond_t
*cond
, pthread_mutex_t
*mutex
)
326 return (cond_wait_common(cond
, mutex
, NULL
, 0));
330 __pthread_cond_wait(pthread_cond_t
*cond
, pthread_mutex_t
*mutex
)
332 return (cond_wait_common(cond
, mutex
, NULL
, 1));
336 _pthread_cond_timedwait(pthread_cond_t
*cond
, pthread_mutex_t
*mutex
,
337 const struct timespec
* abstime
)
339 if (abstime
== NULL
|| abstime
->tv_sec
< 0 || abstime
->tv_nsec
< 0 ||
340 abstime
->tv_nsec
>= 1000000000)
343 return (cond_wait_common(cond
, mutex
, abstime
, 0));
347 __pthread_cond_timedwait(pthread_cond_t
*cond
, pthread_mutex_t
*mutex
,
348 const struct timespec
*abstime
)
350 if (abstime
== NULL
|| abstime
->tv_sec
< 0 || abstime
->tv_nsec
< 0 ||
351 abstime
->tv_nsec
>= 1000000000)
354 return (cond_wait_common(cond
, mutex
, abstime
, 1));
358 cond_signal_common(pthread_cond_t
*cond
, int broadcast
)
360 struct pthread
*curthread
= tls_get_curthread();
361 struct cond_cancel_info
*info
;
365 cond_log("cond_signal_common %p broad=%d\n", *cond
, broadcast
);
368 * If the condition variable is statically initialized, perform dynamic
371 if (__predict_false(*cond
== NULL
&&
372 (ret
= init_static(curthread
, cond
)) != 0)) {
373 cond_log("cond_signal_common %p (failedA %d)\n", *cond
, ret
);
378 /* Lock the condition variable structure. */
379 THR_LOCK_ACQUIRE(curthread
, &cv
->c_lock
);
380 while ((info
= TAILQ_FIRST(&cv
->c_waitlist
)) != NULL
) {
382 TAILQ_REMOVE(&cv
->c_waitlist
, info
, entry
);
383 cond_log("cond_signal_common %p: wakeup %p\n", *cond
, info
);
384 _thr_umtx_wake(&info
->queued
, 0);
388 THR_LOCK_RELEASE(curthread
, &cv
->c_lock
);
391 cond_log("cond_signal_common %p (failedB %d)\n", *cond
, ret
);
393 cond_log("cond_signal_common %p (done)\n", *cond
);
399 _pthread_cond_signal(pthread_cond_t
* cond
)
401 return (cond_signal_common(cond
, 0));
405 _pthread_cond_broadcast(pthread_cond_t
* cond
)
407 return (cond_signal_common(cond
, 1));
411 * Double underscore versions are cancellation points. Single underscore
412 * versions are not and are provided for libc internal usage (which
413 * shouldn't introduce cancellation points).
415 __strong_reference(__pthread_cond_wait
, pthread_cond_wait
);
416 __strong_reference(__pthread_cond_timedwait
, pthread_cond_timedwait
);
418 __strong_reference(_pthread_cond_init
, pthread_cond_init
);
419 __strong_reference(_pthread_cond_destroy
, pthread_cond_destroy
);
420 __strong_reference(_pthread_cond_signal
, pthread_cond_signal
);
421 __strong_reference(_pthread_cond_broadcast
, pthread_cond_broadcast
);