OLD | NEW |
1 /* | 1 /* |
2 * Copyright (c) 2011 The Native Client Authors. All rights reserved. | 2 * Copyright (c) 2011 The Native Client Authors. All rights reserved. |
3 * Use of this source code is governed by a BSD-style license that can be | 3 * Use of this source code is governed by a BSD-style license that can be |
4 * found in the LICENSE file. | 4 * found in the LICENSE file. |
5 */ | 5 */ |
6 | 6 |
7 /* | 7 /* |
8 * Native Client semaphore API | 8 * Native Client semaphore API |
9 */ | 9 */ |
10 | 10 |
(...skipping 28 matching lines...) Expand all Loading... |
39 * creates a thundering herd problem. If the woken threads wake | 39 * creates a thundering herd problem. If the woken threads wake |
40 * quickly enough, all but one of them will fail to decrement the | 40 * quickly enough, all but one of them will fail to decrement the |
41 * semaphore count and will wait again. Because of this problem, I've | 41 * semaphore count and will wait again. Because of this problem, I've |
42 * chosen not to use this algorithm. sem_post() below wakes only a | 42 * chosen not to use this algorithm. sem_post() below wakes only a |
43 * single thread. | 43 * single thread. |
44 */ | 44 */ |
45 | 45 |
46 | 46 |
47 /* Initialize semaphore */ | 47 /* Initialize semaphore */ |
48 int sem_init(sem_t *sem, int pshared, unsigned int value) { | 48 int sem_init(sem_t *sem, int pshared, unsigned int value) { |
49 if (NULL == sem) { | |
50 errno = EINVAL; | |
51 return -1; | |
52 } | |
53 if (pshared) { | 49 if (pshared) { |
54 /* We don't support shared semaphores yet. */ | 50 /* We don't support shared semaphores yet. */ |
55 errno = ENOSYS; | 51 errno = ENOSYS; |
56 return -1; | 52 return -1; |
57 } | 53 } |
58 if (value > SEM_VALUE_MAX) { | 54 if (value > SEM_VALUE_MAX) { |
59 errno = EINVAL; | 55 errno = EINVAL; |
60 return -1; | 56 return -1; |
61 } | 57 } |
62 sem->count = value; | 58 sem->count = value; |
63 sem->nwaiters = 0; | 59 sem->nwaiters = 0; |
64 return 0; | 60 return 0; |
65 } | 61 } |
66 | 62 |
67 int sem_destroy(sem_t *sem) { | 63 int sem_destroy(sem_t *sem) { |
68 if (NULL == sem) { | |
69 errno = EINVAL; | |
70 return -1; | |
71 } | |
72 if (sem->nwaiters != 0) { | 64 if (sem->nwaiters != 0) { |
73 errno = EBUSY; | 65 errno = EBUSY; |
74 return -1; | 66 return -1; |
75 } | 67 } |
76 return 0; | 68 return 0; |
77 } | 69 } |
78 | 70 |
79 static int decrement_if_positive(volatile int *ptr) { | 71 static int decrement_if_positive(volatile int *ptr) { |
80 int old_value; | 72 int old_value; |
81 do { | 73 do { |
82 old_value = *ptr; | 74 old_value = *ptr; |
83 if (old_value == 0) | 75 if (old_value == 0) |
84 return 0; | 76 return 0; |
85 } while (!__sync_bool_compare_and_swap(ptr, old_value, old_value - 1)); | 77 } while (!__sync_bool_compare_and_swap(ptr, old_value, old_value - 1)); |
86 return 1; | 78 return 1; |
87 } | 79 } |
88 | 80 |
89 int sem_wait(sem_t *sem) { | 81 int sem_wait(sem_t *sem) { |
90 if (NULL == sem) { | |
91 errno = EINVAL; | |
92 return -1; | |
93 } | |
94 | |
95 if (decrement_if_positive(&sem->count)) | 82 if (decrement_if_positive(&sem->count)) |
96 return 0; | 83 return 0; |
97 | 84 |
98 __sync_fetch_and_add(&sem->nwaiters, 1); | 85 __sync_fetch_and_add(&sem->nwaiters, 1); |
99 do { | 86 do { |
100 __nc_irt_futex.futex_wait_abs(&sem->count, 0, NULL); | 87 __nc_irt_futex.futex_wait_abs(&sem->count, 0, NULL); |
101 } while (!decrement_if_positive(&sem->count)); | 88 } while (!decrement_if_positive(&sem->count)); |
102 __sync_fetch_and_sub(&sem->nwaiters, 1); | 89 __sync_fetch_and_sub(&sem->nwaiters, 1); |
103 return 0; | 90 return 0; |
104 } | 91 } |
105 | 92 |
106 int sem_post(sem_t *sem) { | 93 int sem_post(sem_t *sem) { |
107 if (NULL == sem) { | |
108 errno = EINVAL; | |
109 return -1; | |
110 } | |
111 | |
112 /* Increment sem->count, checking for overflow. */ | 94 /* Increment sem->count, checking for overflow. */ |
113 int old_value; | 95 int old_value; |
114 do { | 96 do { |
115 old_value = sem->count; | 97 old_value = sem->count; |
116 if (old_value == SEM_VALUE_MAX) { | 98 if (old_value == SEM_VALUE_MAX) { |
117 errno = EOVERFLOW; | 99 errno = EOVERFLOW; |
118 return -1; | 100 return -1; |
119 } | 101 } |
120 } while (!__sync_bool_compare_and_swap(&sem->count, old_value, | 102 } while (!__sync_bool_compare_and_swap(&sem->count, old_value, |
121 old_value + 1)); | 103 old_value + 1)); |
122 | 104 |
123 /* | 105 /* |
124 * We only need to call futex_wake() if there are waiters. Note | 106 * We only need to call futex_wake() if there are waiters. Note |
125 * that this might do an unnecessary call to futex_wake() if the | 107 * that this might do an unnecessary call to futex_wake() if the |
126 * last waiter has already been woken using futex_wake() but has not | 108 * last waiter has already been woken using futex_wake() but has not |
127 * yet decremented sem->nwaiters. | 109 * yet decremented sem->nwaiters. |
128 */ | 110 */ |
129 if (sem->nwaiters != 0) { | 111 if (sem->nwaiters != 0) { |
130 int woken_count; | 112 int woken_count; |
131 __nc_irt_futex.futex_wake(&sem->count, 1, &woken_count); | 113 __nc_irt_futex.futex_wake(&sem->count, 1, &woken_count); |
132 } | 114 } |
133 return 0; | 115 return 0; |
134 } | 116 } |
OLD | NEW |