| 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 |