| 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 mutex implementation | 8 * Native Client mutex implementation |
| 9 */ | 9 */ |
| 10 | 10 |
| (...skipping 18 matching lines...) Expand all Loading... |
| 29 | 29 |
| 30 if (nc_token_acquire(&mutex->token)) { | 30 if (nc_token_acquire(&mutex->token)) { |
| 31 /* Mutex_type was set by pthread_mutex_init */ | 31 /* Mutex_type was set by pthread_mutex_init */ |
| 32 rv = nc_thread_mutex_init(mutex); | 32 rv = nc_thread_mutex_init(mutex); |
| 33 nc_token_release(&mutex->token); | 33 nc_token_release(&mutex->token); |
| 34 } | 34 } |
| 35 | 35 |
| 36 return rv; | 36 return rv; |
| 37 } | 37 } |
| 38 | 38 |
| 39 int pthread_mutex_init (pthread_mutex_t *mutex, | 39 int pthread_mutex_init(pthread_mutex_t *mutex, |
| 40 const pthread_mutexattr_t *mutex_attr) { | 40 const pthread_mutexattr_t *mutex_attr) { |
| 41 int retval; | 41 int retval; |
| 42 nc_token_init(&mutex->token, 1); | 42 nc_token_init(&mutex->token, 1); |
| 43 if (mutex_attr != NULL) { | 43 if (mutex_attr != NULL) { |
| 44 mutex->mutex_type = mutex_attr->kind; | 44 mutex->mutex_type = mutex_attr->kind; |
| 45 } else { | 45 } else { |
| 46 mutex->mutex_type = PTHREAD_MUTEX_FAST_NP; | 46 mutex->mutex_type = PTHREAD_MUTEX_FAST_NP; |
| 47 } | 47 } |
| 48 retval = nc_thread_mutex_init(mutex); | 48 retval = nc_thread_mutex_init(mutex); |
| 49 nc_token_release(&mutex->token); | 49 nc_token_release(&mutex->token); |
| 50 return retval; | 50 return retval; |
| 51 } | 51 } |
| 52 | 52 |
| 53 int pthread_mutex_destroy (pthread_mutex_t *mutex) { | 53 int pthread_mutex_destroy(pthread_mutex_t *mutex) { |
| 54 int retval; | 54 int retval; |
| 55 pthread_mutex_validate(mutex); | 55 pthread_mutex_validate(mutex); |
| 56 if (NACL_PTHREAD_ILLEGAL_THREAD_ID != mutex->owner_thread_id) { | 56 if (NACL_PTHREAD_ILLEGAL_THREAD_ID != mutex->owner_thread_id) { |
| 57 /* the mutex is still locked - cannot destroy */ | 57 /* The mutex is still locked - cannot destroy. */ |
| 58 return EBUSY; | 58 return EBUSY; |
| 59 } | 59 } |
| 60 retval = __nc_irt_mutex.mutex_destroy(mutex->mutex_handle); | 60 retval = __nc_irt_mutex.mutex_destroy(mutex->mutex_handle); |
| 61 mutex->mutex_handle = NC_INVALID_HANDLE; | 61 mutex->mutex_handle = NC_INVALID_HANDLE; |
| 62 mutex->owner_thread_id = NACL_PTHREAD_ILLEGAL_THREAD_ID; | 62 mutex->owner_thread_id = NACL_PTHREAD_ILLEGAL_THREAD_ID; |
| 63 mutex->recursion_counter = 0; | 63 mutex->recursion_counter = 0; |
| 64 return retval; | 64 return retval; |
| 65 } | 65 } |
| 66 | 66 |
| 67 static int nc_thread_mutex_lock(pthread_mutex_t *mutex, int try_only) { | 67 static int nc_thread_mutex_lock(pthread_mutex_t *mutex, int try_only) { |
| (...skipping 10 matching lines...) Expand all Loading... |
| 78 * by a single machine instruction, so the current thread can only read | 78 * by a single machine instruction, so the current thread can only read |
| 79 * a value that it or some other thread wrote. | 79 * a value that it or some other thread wrote. |
| 80 * - Cache is not an issue since a thread will always update its own cache | 80 * - Cache is not an issue since a thread will always update its own cache |
| 81 * when unlocking a mutex (see pthread_mutex_unlock implementation). | 81 * when unlocking a mutex (see pthread_mutex_unlock implementation). |
| 82 */ | 82 */ |
| 83 if ((mutex->mutex_type != PTHREAD_MUTEX_FAST_NP) && | 83 if ((mutex->mutex_type != PTHREAD_MUTEX_FAST_NP) && |
| 84 (pthread_self() == mutex->owner_thread_id)) { | 84 (pthread_self() == mutex->owner_thread_id)) { |
| 85 if (mutex->mutex_type == PTHREAD_MUTEX_ERRORCHECK_NP) { | 85 if (mutex->mutex_type == PTHREAD_MUTEX_ERRORCHECK_NP) { |
| 86 return EDEADLK; | 86 return EDEADLK; |
| 87 } else { | 87 } else { |
| 88 /* This thread already owns the mutex */ | 88 /* This thread already owns the mutex. */ |
| 89 ++mutex->recursion_counter; | 89 ++mutex->recursion_counter; |
| 90 return 0; | 90 return 0; |
| 91 } | 91 } |
| 92 } | 92 } |
| 93 if (try_only) { | 93 if (try_only) { |
| 94 rv = __nc_irt_mutex.mutex_trylock(mutex->mutex_handle); | 94 rv = __nc_irt_mutex.mutex_trylock(mutex->mutex_handle); |
| 95 } else { | 95 } else { |
| 96 rv = __nc_irt_mutex.mutex_lock(mutex->mutex_handle); | 96 rv = __nc_irt_mutex.mutex_lock(mutex->mutex_handle); |
| 97 } | 97 } |
| 98 if (rv) { | 98 if (rv) { |
| 99 return rv; | 99 return rv; |
| 100 } | 100 } |
| 101 | 101 |
| 102 mutex->owner_thread_id = pthread_self(); | 102 mutex->owner_thread_id = pthread_self(); |
| 103 mutex->recursion_counter = 1; | 103 mutex->recursion_counter = 1; |
| 104 | 104 |
| 105 return 0; | 105 return 0; |
| 106 } | 106 } |
| 107 | 107 |
| 108 int pthread_mutex_trylock (pthread_mutex_t *mutex) { | 108 int pthread_mutex_trylock(pthread_mutex_t *mutex) { |
| 109 return nc_thread_mutex_lock(mutex, 1); | 109 return nc_thread_mutex_lock(mutex, 1); |
| 110 } | 110 } |
| 111 | 111 |
| 112 int pthread_mutex_lock (pthread_mutex_t *mutex) { | 112 int pthread_mutex_lock(pthread_mutex_t *mutex) { |
| 113 return nc_thread_mutex_lock(mutex, 0); | 113 return nc_thread_mutex_lock(mutex, 0); |
| 114 } | 114 } |
| 115 | 115 |
| 116 int pthread_mutex_unlock (pthread_mutex_t *mutex) { | 116 int pthread_mutex_unlock(pthread_mutex_t *mutex) { |
| 117 pthread_mutex_validate(mutex); | 117 pthread_mutex_validate(mutex); |
| 118 if (mutex->mutex_type != PTHREAD_MUTEX_FAST_NP) { | 118 if (mutex->mutex_type != PTHREAD_MUTEX_FAST_NP) { |
| 119 if ((PTHREAD_MUTEX_RECURSIVE_NP == mutex->mutex_type) && | 119 if ((PTHREAD_MUTEX_RECURSIVE_NP == mutex->mutex_type) && |
| 120 (0 != (--mutex->recursion_counter))) { | 120 (0 != (--mutex->recursion_counter))) { |
| 121 /* | 121 /* |
| 122 * We assume that this thread owns the lock | 122 * We assume that this thread owns the lock |
| 123 * (no verification for recursive locks), | 123 * (no verification for recursive locks), |
| 124 * so just decrement the counter, this thread is still the owner | 124 * so just decrement the counter, this thread is still the owner. |
| 125 */ | 125 */ |
| 126 return 0; | 126 return 0; |
| 127 } | 127 } |
| 128 if ((PTHREAD_MUTEX_ERRORCHECK_NP == mutex->mutex_type) && | 128 if ((PTHREAD_MUTEX_ERRORCHECK_NP == mutex->mutex_type) && |
| 129 (pthread_self() != mutex->owner_thread_id)) { | 129 (pthread_self() != mutex->owner_thread_id)) { |
| 130 /* error - releasing a mutex that's free or owned by another thread */ | 130 /* Error - releasing a mutex that's free or owned by another thread. */ |
| 131 return EPERM; | 131 return EPERM; |
| 132 } | 132 } |
| 133 } | 133 } |
| 134 mutex->owner_thread_id = NACL_PTHREAD_ILLEGAL_THREAD_ID; | 134 mutex->owner_thread_id = NACL_PTHREAD_ILLEGAL_THREAD_ID; |
| 135 mutex->recursion_counter = 0; | 135 mutex->recursion_counter = 0; |
| 136 return __nc_irt_mutex.mutex_unlock(mutex->mutex_handle); | 136 return __nc_irt_mutex.mutex_unlock(mutex->mutex_handle); |
| 137 } | 137 } |
| 138 | 138 |
| 139 /* | 139 /* |
| 140 * NOTE(sehr): pthread_once needs to be defined in the same module as contains | 140 * NOTE(sehr): pthread_once needs to be defined in the same module as contains |
| 141 * the mutex definitions, so that it overrides the weak symbol in the libstdc++ | 141 * the mutex definitions, so that it overrides the weak symbol in the libstdc++ |
| 142 * library. Otherwise we get calls through address zero. | 142 * library. Otherwise we get calls through address zero. |
| 143 */ | 143 */ |
| 144 int pthread_once(pthread_once_t* __once_control, | 144 int pthread_once(pthread_once_t *once_control, |
| 145 void (*__init_routine) (void)) { | 145 void (*init_routine)(void)) { |
| 146 /* | 146 /* |
| 147 * NOTE(gregoryd): calling pthread_once from __init_routine providing the same | 147 * NOTE(gregoryd): calling pthread_once from init_routine providing |
| 148 * __once_control argument is an error and will cause a deadlock | 148 * the same once_control argument is an error and will cause a |
| 149 */ | 149 * deadlock |
| 150 volatile AtomicInt32* pdone = &__once_control->done; | 150 */ |
| 151 volatile AtomicInt32 *pdone = &once_control->done; |
| 151 if (*pdone == 0) { | 152 if (*pdone == 0) { |
| 152 /* not done yet */ | 153 /* Not done yet. */ |
| 153 pthread_mutex_lock(&__once_control->lock); | 154 pthread_mutex_lock(&once_control->lock); |
| 154 if (*pdone == 0) { | 155 if (*pdone == 0) { |
| 155 /* still not done - but this time we own the lock */ | 156 /* Still not done - but this time we own the lock. */ |
| 156 (*__init_routine)(); | 157 (*init_routine)(); |
| 157 | 158 |
| 158 /* GCC intrinsic; see: | 159 /* |
| 160 * GCC intrinsic; see: |
| 159 * http://gcc.gnu.org/onlinedocs/gcc/Atomic-Builtins.html. | 161 * http://gcc.gnu.org/onlinedocs/gcc/Atomic-Builtins.html. |
| 160 * The x86-{32,64} compilers generate inline code. The ARM | 162 * The x86-{32,64} compilers generate inline code. The ARM |
| 161 * implementation is external: stubs/intrinsics_arm.S. | 163 * implementation is external: stubs/intrinsics_arm.S. |
| 162 */ | 164 */ |
| 163 __sync_fetch_and_add(pdone, 1); | 165 __sync_fetch_and_add(pdone, 1); |
| 164 } | 166 } |
| 165 pthread_mutex_unlock(&__once_control->lock); | 167 pthread_mutex_unlock(&once_control->lock); |
| 166 } | 168 } |
| 167 return 0; | 169 return 0; |
| 168 } | 170 } |
| 169 | 171 |
| 170 int pthread_mutexattr_init(pthread_mutexattr_t *attr) { | 172 int pthread_mutexattr_init(pthread_mutexattr_t *attr) { |
| 171 /* The default mutex type is non-recursive */ | 173 /* The default mutex type is non-recursive. */ |
| 172 attr->kind = PTHREAD_MUTEX_FAST_NP; | 174 attr->kind = PTHREAD_MUTEX_FAST_NP; |
| 173 return 0; | 175 return 0; |
| 174 } | 176 } |
| 175 | 177 |
| 176 int pthread_mutexattr_destroy(pthread_mutexattr_t *attr) { | 178 int pthread_mutexattr_destroy(pthread_mutexattr_t *attr) { |
| 177 /* nothing to do */ | 179 /* Nothing to do. */ |
| 178 return 0; | 180 return 0; |
| 179 } | 181 } |
| 180 | 182 |
| 181 int pthread_mutexattr_settype(pthread_mutexattr_t *attr, | 183 int pthread_mutexattr_settype(pthread_mutexattr_t *attr, |
| 182 int kind) { | 184 int kind) { |
| 183 if ((kind == PTHREAD_MUTEX_FAST_NP) || | 185 if ((kind == PTHREAD_MUTEX_FAST_NP) || |
| 184 (kind == PTHREAD_MUTEX_RECURSIVE_NP) || | 186 (kind == PTHREAD_MUTEX_RECURSIVE_NP) || |
| 185 (kind == PTHREAD_MUTEX_ERRORCHECK_NP)) { | 187 (kind == PTHREAD_MUTEX_ERRORCHECK_NP)) { |
| 186 attr->kind = kind; | 188 attr->kind = kind; |
| 187 } else { | 189 } else { |
| 188 /* unknown kind */ | 190 /* Unknown kind. */ |
| 189 return -1; | 191 return -1; |
| 190 } | 192 } |
| 191 return 0; | 193 return 0; |
| 192 } | 194 } |
| 193 | 195 |
| 194 int pthread_mutexattr_gettype(const pthread_mutexattr_t *attr, | 196 int pthread_mutexattr_gettype(const pthread_mutexattr_t *attr, |
| 195 int *kind) { | 197 int *kind) { |
| 196 *kind = attr->kind; | 198 *kind = attr->kind; |
| 197 return 0; | 199 return 0; |
| 198 } | 200 } |
| OLD | NEW |