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