diff options
author | Rich Felker <dalias@aerifal.cx> | 2014-10-13 18:26:28 -0400 |
---|---|---|
committer | Rich Felker <dalias@aerifal.cx> | 2014-10-13 18:26:28 -0400 |
commit | 00548408398ced546c540dab773ea66cea4fe1c2 (patch) | |
tree | 547a52d425979a2528953a2252c11d424b32b0ab | |
parent | df37d3960abec482e17fad2274a99b790f6cc08b (diff) | |
download | musl-00548408398ced546c540dab773ea66cea4fe1c2.tar.gz musl-00548408398ced546c540dab773ea66cea4fe1c2.tar.xz musl-00548408398ced546c540dab773ea66cea4fe1c2.zip |
eliminate global waiters count in pthread_once
-rw-r--r-- | src/thread/pthread_once.c | 22 |
1 files changed, 13 insertions, 9 deletions
diff --git a/src/thread/pthread_once.c b/src/thread/pthread_once.c index b7388b93..7c47385c 100644 --- a/src/thread/pthread_once.c +++ b/src/thread/pthread_once.c @@ -2,14 +2,14 @@ static void undo(void *control) { - a_store(control, 0); - __wake(control, 1, 1); + /* Wake all waiters, since the waiter status is lost when + * resetting control to the initial state. */ + if (a_swap(control, 0) == 3) + __wake(control, -1, 1); } int __pthread_once(pthread_once_t *control, void (*init)(void)) { - static int waiters; - /* Return immediately if init finished before, but ensure that * effects of the init routine are visible to the caller. */ if (*control == 2) { @@ -17,10 +17,11 @@ int __pthread_once(pthread_once_t *control, void (*init)(void)) return 0; } - /* Try to enter initializing state. Three possibilities: + /* Try to enter initializing state. Four possibilities: * 0 - we're the first or the other cancelled; run init * 1 - another thread is running init; wait - * 2 - another thread finished running init; just return */ + * 2 - another thread finished running init; just return + * 3 - another thread is running init, waiters present; wait */ for (;;) switch (a_cas(control, 0, 1)) { case 0: @@ -28,11 +29,14 @@ int __pthread_once(pthread_once_t *control, void (*init)(void)) init(); pthread_cleanup_pop(0); - a_store(control, 2); - if (waiters) __wake(control, -1, 1); + if (a_swap(control, 2) == 3) + __wake(control, -1, 1); return 0; case 1: - __wait(control, &waiters, 1, 1); + /* If this fails, so will __wait. */ + a_cas(control, 1, 3); + case 3: + __wait(control, 0, 3, 1); continue; case 2: return 0; |