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