From: Rich Felker Date: Mon, 13 Oct 2014 22:26:28 +0000 (-0400) Subject: eliminate global waiters count in pthread_once X-Git-Tag: v1.1.5~3 X-Git-Url: https://git.librecmc.org/?a=commitdiff_plain;h=00548408398ced546c540dab773ea66cea4fe1c2;p=oweals%2Fmusl.git eliminate global waiters count in pthread_once --- 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;