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