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 pcond = __malloc(sizeof(struct __pthread_cond_s));
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(pthread_t 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 * __restrict cond,
147 const pthread_condattr_t * __restrict cond_attr)
150 return cond_init(cond, cond_attr);
154 _pthread_cond_destroy(pthread_cond_t *cond)
157 pthread_t curthread = tls_get_curthread();
162 } else if (*cond == NULL) {
165 /* Lock the condition variable structure: */
166 THR_LOCK_ACQUIRE(curthread, &(*cond)->c_lock);
167 if (TAILQ_FIRST(&(*cond)->c_waitlist)) {
168 THR_LOCK_RELEASE(curthread, &(*cond)->c_lock);
173 * NULL the caller's pointer now that the condition
174 * variable has been destroyed:
179 /* Unlock the condition variable structure: */
180 THR_LOCK_RELEASE(curthread, &cv->c_lock);
182 /* Free the cond lock structure: */
185 * Free the memory allocated for the condition
186 * variable structure:
191 /* Return the completion status: */
195 struct cond_cancel_info {
196 TAILQ_ENTRY(cond_cancel_info) entry;
197 pthread_mutex_t *mutex;
198 pthread_cond_t *cond;
204 cond_cancel_handler(void *arg)
206 pthread_t curthread = tls_get_curthread();
207 struct cond_cancel_info *info = (struct cond_cancel_info *)arg;
211 THR_LOCK_ACQUIRE(curthread, &cv->c_lock);
212 cond_log("cond_cancel %p\n", cv);
216 cond_log("cond_cancel %p: info %p\n", cv, info);
217 TAILQ_REMOVE(&cv->c_waitlist, info, entry);
218 _thr_umtx_wake(&info->queued, 0);
220 THR_LOCK_RELEASE(curthread, &cv->c_lock);
222 /* _mutex_cv_lock(info->mutex, info->count); */
226 * Wait for pthread_cond_t to be signaled.
228 * NOTE: EINTR is ignored and may not be returned by this function.
231 cond_wait_common(pthread_cond_t *cond, pthread_mutex_t *mutex,
232 const struct timespec *abstime, int cancel)
234 pthread_t curthread = tls_get_curthread();
235 struct timespec ts, ts2, *tsp;
236 struct cond_cancel_info info;
242 * If the condition variable is statically initialized,
243 * perform the dynamic initialization:
245 cond_log("cond_wait_common %p on mutex %p info %p\n",
246 *cond, *mutex, &info);
247 if (__predict_false(*cond == NULL &&
248 (ret = init_static(curthread, cond)) != 0)) {
249 cond_log("cond_wait_common %p (failedA %d)\n", *cond, ret);
254 THR_LOCK_ACQUIRE(curthread, &cv->c_lock);
255 ret = _mutex_cv_unlock(mutex, &info.count);
257 cond_log("cond_wait_common %p (failedB %d)\n", cv, ret);
258 THR_LOCK_RELEASE(curthread, &cv->c_lock);
266 TAILQ_INSERT_TAIL(&cv->c_waitlist, &info, entry);
269 * loop if we have never been told to wake up
272 while (info.queued) {
273 THR_LOCK_RELEASE(curthread, &cv->c_lock);
275 if (abstime != NULL) {
276 clock_gettime(cv->c_clockid, &ts);
277 timespecsub(abstime, &ts, &ts2);
284 THR_CLEANUP_PUSH(curthread, cond_cancel_handler, &info);
285 oldcancel = _thr_cancel_enter(curthread);
286 ret = _thr_umtx_wait(&info.queued, 1, tsp,
288 _thr_cancel_leave(curthread, oldcancel);
289 THR_CLEANUP_POP(curthread, 0);
291 ret = _thr_umtx_wait(&info.queued, 1, tsp,
296 * Ignore EINTR. Make sure ret is 0 if not ETIMEDOUT.
298 THR_LOCK_ACQUIRE(curthread, &cv->c_lock);
299 if (abstime != NULL && ret == ETIMEDOUT)
306 TAILQ_REMOVE(&cv->c_waitlist, &info, entry);
311 THR_LOCK_RELEASE(curthread, &cv->c_lock);
313 cond_log("cond_wait_common %p (doneA)\n", cv);
314 _mutex_cv_lock(mutex, info.count);
317 cond_log("cond_wait_common %p (failed %d)\n", cv, ret);
319 cond_log("cond_wait_common %p (doneB)\n", cv);
325 _pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
327 return (cond_wait_common(cond, mutex, NULL, 0));
331 __pthread_cond_wait(pthread_cond_t * __restrict cond,
332 pthread_mutex_t * __restrict mutex)
334 return (cond_wait_common(cond, mutex, NULL, 1));
338 _pthread_cond_timedwait(pthread_cond_t * __restrict cond,
339 pthread_mutex_t * __restrict mutex,
340 const struct timespec * __restrict abstime)
342 if (abstime == NULL || abstime->tv_sec < 0 || abstime->tv_nsec < 0 ||
343 abstime->tv_nsec >= 1000000000)
346 return (cond_wait_common(cond, mutex, abstime, 0));
350 __pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
351 const struct timespec *abstime)
353 if (abstime == NULL || abstime->tv_sec < 0 || abstime->tv_nsec < 0 ||
354 abstime->tv_nsec >= 1000000000)
357 return (cond_wait_common(cond, mutex, abstime, 1));
361 cond_signal_common(pthread_cond_t *cond, int broadcast)
363 pthread_t curthread = tls_get_curthread();
364 struct cond_cancel_info *info;
368 cond_log("cond_signal_common %p broad=%d\n", *cond, broadcast);
371 * If the condition variable is statically initialized, perform dynamic
374 if (__predict_false(*cond == NULL &&
375 (ret = init_static(curthread, cond)) != 0)) {
376 cond_log("cond_signal_common %p (failedA %d)\n", *cond, ret);
381 /* Lock the condition variable structure. */
382 THR_LOCK_ACQUIRE(curthread, &cv->c_lock);
383 while ((info = TAILQ_FIRST(&cv->c_waitlist)) != NULL) {
385 TAILQ_REMOVE(&cv->c_waitlist, info, entry);
386 cond_log("cond_signal_common %p: wakeup %p\n", *cond, info);
387 _thr_umtx_wake(&info->queued, 0);
391 THR_LOCK_RELEASE(curthread, &cv->c_lock);
394 cond_log("cond_signal_common %p (failedB %d)\n", *cond, ret);
396 cond_log("cond_signal_common %p (done)\n", *cond);
402 _pthread_cond_signal(pthread_cond_t * cond)
404 return (cond_signal_common(cond, 0));
408 _pthread_cond_broadcast(pthread_cond_t * cond)
410 return (cond_signal_common(cond, 1));
414 * Double underscore versions are cancellation points. Single underscore
415 * versions are not and are provided for libc internal usage (which
416 * shouldn't introduce cancellation points).
418 __strong_reference(__pthread_cond_wait, pthread_cond_wait);
419 __strong_reference(__pthread_cond_timedwait, pthread_cond_timedwait);
421 __strong_reference(_pthread_cond_init, pthread_cond_init);
422 __strong_reference(_pthread_cond_destroy, pthread_cond_destroy);
423 __strong_reference(_pthread_cond_signal, pthread_cond_signal);
424 __strong_reference(_pthread_cond_broadcast, pthread_cond_broadcast);