xref: /aosp_15_r20/external/musl/src/thread/pthread_once.c (revision c9945492fdd68bbe62686c5b452b4dc1be3f8453)
1*c9945492SAndroid Build Coastguard Worker #include "pthread_impl.h"
2*c9945492SAndroid Build Coastguard Worker 
undo(void * control)3*c9945492SAndroid Build Coastguard Worker static void undo(void *control)
4*c9945492SAndroid Build Coastguard Worker {
5*c9945492SAndroid Build Coastguard Worker 	/* Wake all waiters, since the waiter status is lost when
6*c9945492SAndroid Build Coastguard Worker 	 * resetting control to the initial state. */
7*c9945492SAndroid Build Coastguard Worker 	if (a_swap(control, 0) == 3)
8*c9945492SAndroid Build Coastguard Worker 		__wake(control, -1, 1);
9*c9945492SAndroid Build Coastguard Worker }
10*c9945492SAndroid Build Coastguard Worker 
__pthread_once_full(pthread_once_t * control,void (* init)(void))11*c9945492SAndroid Build Coastguard Worker hidden int __pthread_once_full(pthread_once_t *control, void (*init)(void))
12*c9945492SAndroid Build Coastguard Worker {
13*c9945492SAndroid Build Coastguard Worker 	/* Try to enter initializing state. Four possibilities:
14*c9945492SAndroid Build Coastguard Worker 	 *  0 - we're the first or the other cancelled; run init
15*c9945492SAndroid Build Coastguard Worker 	 *  1 - another thread is running init; wait
16*c9945492SAndroid Build Coastguard Worker 	 *  2 - another thread finished running init; just return
17*c9945492SAndroid Build Coastguard Worker 	 *  3 - another thread is running init, waiters present; wait */
18*c9945492SAndroid Build Coastguard Worker 
19*c9945492SAndroid Build Coastguard Worker 	for (;;) switch (a_cas(control, 0, 1)) {
20*c9945492SAndroid Build Coastguard Worker 	case 0:
21*c9945492SAndroid Build Coastguard Worker 		pthread_cleanup_push(undo, control);
22*c9945492SAndroid Build Coastguard Worker 		init();
23*c9945492SAndroid Build Coastguard Worker 		pthread_cleanup_pop(0);
24*c9945492SAndroid Build Coastguard Worker 
25*c9945492SAndroid Build Coastguard Worker 		if (a_swap(control, 2) == 3)
26*c9945492SAndroid Build Coastguard Worker 			__wake(control, -1, 1);
27*c9945492SAndroid Build Coastguard Worker 		return 0;
28*c9945492SAndroid Build Coastguard Worker 	case 1:
29*c9945492SAndroid Build Coastguard Worker 		/* If this fails, so will __wait. */
30*c9945492SAndroid Build Coastguard Worker 		a_cas(control, 1, 3);
31*c9945492SAndroid Build Coastguard Worker 	case 3:
32*c9945492SAndroid Build Coastguard Worker 		__wait(control, 0, 3, 1);
33*c9945492SAndroid Build Coastguard Worker 		continue;
34*c9945492SAndroid Build Coastguard Worker 	case 2:
35*c9945492SAndroid Build Coastguard Worker 		return 0;
36*c9945492SAndroid Build Coastguard Worker 	}
37*c9945492SAndroid Build Coastguard Worker }
38*c9945492SAndroid Build Coastguard Worker 
__pthread_once(pthread_once_t * control,void (* init)(void))39*c9945492SAndroid Build Coastguard Worker int __pthread_once(pthread_once_t *control, void (*init)(void))
40*c9945492SAndroid Build Coastguard Worker {
41*c9945492SAndroid Build Coastguard Worker 	/* Return immediately if init finished before, but ensure that
42*c9945492SAndroid Build Coastguard Worker 	 * effects of the init routine are visible to the caller. */
43*c9945492SAndroid Build Coastguard Worker 	if (*(volatile int *)control == 2) {
44*c9945492SAndroid Build Coastguard Worker 		a_barrier();
45*c9945492SAndroid Build Coastguard Worker 		return 0;
46*c9945492SAndroid Build Coastguard Worker 	}
47*c9945492SAndroid Build Coastguard Worker 	return __pthread_once_full(control, init);
48*c9945492SAndroid Build Coastguard Worker }
49*c9945492SAndroid Build Coastguard Worker 
50*c9945492SAndroid Build Coastguard Worker weak_alias(__pthread_once, pthread_once);
51