From 00548408398ced546c540dab773ea66cea4fe1c2 Mon Sep 17 00:00:00 2001 From: Rich Felker Date: Mon, 13 Oct 2014 18:26:28 -0400 Subject: [PATCH] eliminate global waiters count in pthread_once --- src/thread/pthread_once.c | 22 +++++++++++++--------- 1 file 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;