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 /src | |
| parent | df37d3960abec482e17fad2274a99b790f6cc08b (diff) | |
| download | musl-00548408398ced546c540dab773ea66cea4fe1c2.tar.gz | |
eliminate global waiters count in pthread_once
Diffstat (limited to 'src')
| -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;  | 
