OLD | NEW |
(Empty) | |
| 1 #include "pthread_impl.h" |
| 2 |
| 3 static 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 |
| 11 int __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 |
| 39 int __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 |
| 50 weak_alias(__pthread_once, pthread_once); |
OLD | NEW |