summaryrefslogtreecommitdiffstats
path: root/lib/libthr
diff options
context:
space:
mode:
authordavidxu <davidxu@FreeBSD.org>2008-05-30 00:02:59 +0000
committerdavidxu <davidxu@FreeBSD.org>2008-05-30 00:02:59 +0000
commit8951bcd14cbf45e5917c52c16236bfa5515c6d1b (patch)
tree8b97dd790b5232097957cf65f57e0f1065e5a2b0 /lib/libthr
parent6d8aba47d87aef0990fa09d8791fef79d7a5d5ff (diff)
downloadFreeBSD-src-8951bcd14cbf45e5917c52c16236bfa5515c6d1b.zip
FreeBSD-src-8951bcd14cbf45e5917c52c16236bfa5515c6d1b.tar.gz
Eliminate global mutex by using pthread_once's state field as
a semaphore.
Diffstat (limited to 'lib/libthr')
-rw-r--r--lib/libthr/thread/thr_once.c62
1 files changed, 29 insertions, 33 deletions
diff --git a/lib/libthr/thread/thr_once.c b/lib/libthr/thread/thr_once.c
index bd1bed1..eb07066 100644
--- a/lib/libthr/thread/thr_once.c
+++ b/lib/libthr/thread/thr_once.c
@@ -38,10 +38,7 @@ __weak_reference(_pthread_once, pthread_once);
#define ONCE_NEVER_DONE PTHREAD_NEEDS_INIT
#define ONCE_DONE PTHREAD_DONE_INIT
#define ONCE_IN_PROGRESS 0x02
-#define ONCE_MASK 0x03
-
-static pthread_mutex_t _thr_once_lock = PTHREAD_MUTEX_INITIALIZER;
-static pthread_cond_t _thr_once_cv = PTHREAD_COND_INITIALIZER;
+#define ONCE_WAIT 0x03
/*
* POSIX:
@@ -55,47 +52,46 @@ once_cancel_handler(void *arg)
{
pthread_once_t *once_control = arg;
- _pthread_mutex_lock(&_thr_once_lock);
- once_control->state = ONCE_NEVER_DONE;
- _pthread_mutex_unlock(&_thr_once_lock);
- _pthread_cond_broadcast(&_thr_once_cv);
+ if (atomic_cmpset_rel_int(&once_control->state, ONCE_IN_PROGRESS, ONCE_NEVER_DONE))
+ return;
+ atomic_store_rel_int(&once_control->state, ONCE_NEVER_DONE);
+ _thr_umtx_wake(&once_control->state, INT_MAX, 0);
}
int
_pthread_once(pthread_once_t *once_control, void (*init_routine) (void))
{
struct pthread *curthread;
- int wakeup = 0;
+ int state;
+
+ for (;;) {
+ state = once_control->state;
+ if (state == ONCE_DONE)
+ return (0);
+ if (state == ONCE_NEVER_DONE) {
+ if (atomic_cmpset_acq_int(&once_control->state, state, ONCE_IN_PROGRESS))
+ break;
+ } else if (state == ONCE_IN_PROGRESS) {
+ if (atomic_cmpset_acq_int(&once_control->state, state, ONCE_WAIT))
+ _thr_umtx_wait_uint(&once_control->state, ONCE_WAIT, NULL, 0);
+ } else if (state == ONCE_WAIT) {
+ _thr_umtx_wait_uint(&once_control->state, state, NULL, 0);
+ } else
+ return (EINVAL);
+ }
- if (once_control->state == ONCE_DONE)
+ curthread = _get_curthread();
+ THR_CLEANUP_PUSH(curthread, once_cancel_handler, once_control);
+ init_routine();
+ THR_CLEANUP_POP(curthread, 0);
+ if (atomic_cmpset_rel_int(&once_control->state, ONCE_IN_PROGRESS, ONCE_DONE))
return (0);
- _pthread_mutex_lock(&_thr_once_lock);
- while (*(volatile int *)&(once_control->state) == ONCE_IN_PROGRESS)
- _pthread_cond_wait(&_thr_once_cv, &_thr_once_lock);
- /*
- * If previous thread was canceled, then the state still
- * could be ONCE_NEVER_DONE, we need to check it again.
- */
- if (*(volatile int *)&(once_control->state) == ONCE_NEVER_DONE) {
- once_control->state = ONCE_IN_PROGRESS;
- _pthread_mutex_unlock(&_thr_once_lock);
- curthread = _get_curthread();
- THR_CLEANUP_PUSH(curthread, once_cancel_handler, once_control);
- init_routine();
- THR_CLEANUP_POP(curthread, 0);
- _pthread_mutex_lock(&_thr_once_lock);
- once_control->state = ONCE_DONE;
- wakeup = 1;
- }
- _pthread_mutex_unlock(&_thr_once_lock);
- if (wakeup)
- _pthread_cond_broadcast(&_thr_once_cv);
+ atomic_store_rel_int(&once_control->state, ONCE_DONE);
+ _thr_umtx_wake(&once_control->state, INT_MAX, 0);
return (0);
}
void
_thr_once_init()
{
- _thr_once_lock = PTHREAD_MUTEX_INITIALIZER;
- _thr_once_cv = PTHREAD_COND_INITIALIZER;
}
OpenPOWER on IntegriCloud