1 /* 2 * Copyright 2002-2012, Axel Dörfler, axeld@pinc-software.de. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. 6 * Distributed under the terms of the NewOS License. 7 */ 8 9 /* Mutex and recursive_lock code */ 10 11 #include "fssh_lock.h" 12 13 #include "fssh_kernel_export.h" 14 15 16 #define FSSH_RW_MAX_READERS 100000 17 18 19 extern "C" int32_t 20 fssh_recursive_lock_get_recursion(fssh_recursive_lock *lock) 21 { 22 if (lock->holder == fssh_find_thread(NULL)) 23 return lock->recursion; 24 25 return -1; 26 } 27 28 29 extern "C" void 30 fssh_recursive_lock_init(fssh_recursive_lock *lock, const char *name) 31 { 32 if (lock == NULL) 33 return; 34 35 if (name == NULL) 36 name = "recursive lock"; 37 38 lock->holder = -1; 39 lock->recursion = 0; 40 lock->sem = fssh_create_sem(1, name); 41 if (lock->sem < FSSH_B_OK) 42 fssh_panic("could not create recursive lock"); 43 } 44 45 46 extern "C" void 47 fssh_recursive_lock_destroy(fssh_recursive_lock *lock) 48 { 49 if (lock == NULL) 50 return; 51 52 fssh_delete_sem(lock->sem); 53 lock->sem = -1; 54 } 55 56 57 extern "C" fssh_status_t 58 fssh_recursive_lock_lock(fssh_recursive_lock *lock) 59 { 60 fssh_thread_id thread = fssh_find_thread(NULL); 61 62 if (thread != lock->holder) { 63 fssh_status_t status = fssh_acquire_sem(lock->sem); 64 if (status < FSSH_B_OK) 65 return status; 66 67 lock->holder = thread; 68 } 69 lock->recursion++; 70 return FSSH_B_OK; 71 } 72 73 74 extern "C" fssh_status_t 75 fssh_recursive_lock_trylock(fssh_recursive_lock *lock) 76 { 77 fssh_thread_id thread = fssh_find_thread(NULL); 78 79 if (thread != lock->holder) { 80 fssh_status_t status = fssh_acquire_sem_etc(lock->sem, 1, 81 FSSH_B_RELATIVE_TIMEOUT, 0); 82 if (status < FSSH_B_OK) 83 return status; 84 85 lock->holder = thread; 86 } 87 lock->recursion++; 88 return FSSH_B_OK; 89 } 90 91 92 extern "C" void 93 fssh_recursive_lock_unlock(fssh_recursive_lock *lock) 94 { 95 if (fssh_find_thread(NULL) != lock->holder) 96 fssh_panic("recursive_lock %p unlocked by non-holder thread!\n", lock); 97 98 if (--lock->recursion == 0) { 99 lock->holder = -1; 100 fssh_release_sem(lock->sem); 101 } 102 } 103 104 105 extern "C" void 106 fssh_recursive_lock_transfer_lock(fssh_recursive_lock *lock, 107 fssh_thread_id thread) 108 { 109 if (lock->recursion != 1) 110 fssh_panic("invalid recursion level for lock transfer!"); 111 112 lock->holder = thread; 113 } 114 115 116 // #pragma mark - 117 118 119 extern "C" void 120 fssh_mutex_init(fssh_mutex *m, const char *name) 121 { 122 if (m == NULL) 123 return; 124 125 if (name == NULL) 126 name = "mutex_sem"; 127 128 m->holder = -1; 129 130 m->sem = fssh_create_sem(1, name); 131 if (m->sem < FSSH_B_OK) 132 fssh_panic("could not create mutex"); 133 } 134 135 136 extern "C" void 137 fssh_mutex_init_etc(fssh_mutex *m, const char *name, uint32_t flags) 138 { 139 fssh_mutex_init(m, name); 140 } 141 142 143 extern "C" void 144 fssh_mutex_destroy(fssh_mutex *mutex) 145 { 146 if (mutex == NULL) 147 return; 148 149 if (mutex->sem >= 0) { 150 fssh_delete_sem(mutex->sem); 151 mutex->sem = -1; 152 } 153 mutex->holder = -1; 154 } 155 156 157 extern "C" fssh_status_t 158 fssh_mutex_lock(fssh_mutex *mutex) 159 { 160 fssh_thread_id me = fssh_find_thread(NULL); 161 fssh_status_t status; 162 163 status = fssh_acquire_sem(mutex->sem); 164 if (status < FSSH_B_OK) 165 return status; 166 167 if (me == mutex->holder) 168 fssh_panic("mutex_lock failure: mutex %p (sem = 0x%x) acquired twice by thread 0x%x\n", mutex, (int)mutex->sem, (int)me); 169 170 mutex->holder = me; 171 return FSSH_B_OK; 172 } 173 174 175 extern "C" void 176 fssh_mutex_unlock(fssh_mutex *mutex) 177 { 178 fssh_thread_id me = fssh_find_thread(NULL); 179 180 if (me != mutex->holder) { 181 fssh_panic("mutex_unlock failure: thread 0x%x is trying to release mutex %p (current holder 0x%x)\n", 182 (int)me, mutex, (int)mutex->holder); 183 } 184 185 mutex->holder = -1; 186 fssh_release_sem(mutex->sem); 187 } 188 189 190 extern "C" void 191 fssh_mutex_transfer_lock(fssh_mutex *mutex, fssh_thread_id thread) 192 { 193 mutex->holder = thread; 194 } 195 196 197 // #pragma mark - 198 199 200 extern "C" void 201 fssh_rw_lock_init(fssh_rw_lock *lock, const char *name) 202 { 203 if (lock == NULL) 204 return; 205 206 if (name == NULL) 207 name = "r/w lock"; 208 209 lock->count = 0; 210 lock->holder = -1; 211 212 lock->sem = fssh_create_sem(FSSH_RW_MAX_READERS, name); 213 if (lock->sem < FSSH_B_OK) 214 fssh_panic("could not create r/w lock"); 215 } 216 217 218 extern "C" void 219 fssh_rw_lock_init_etc(fssh_rw_lock *lock, const char *name, uint32_t flags) 220 { 221 fssh_rw_lock_init(lock, name); 222 } 223 224 225 extern "C" void 226 fssh_rw_lock_destroy(fssh_rw_lock *lock) 227 { 228 if (lock == NULL) 229 return; 230 231 fssh_delete_sem(lock->sem); 232 } 233 234 235 extern "C" fssh_status_t 236 fssh_rw_lock_read_lock(fssh_rw_lock *lock) 237 { 238 if (lock->holder == fssh_find_thread(NULL)) { 239 lock->count++; 240 return FSSH_B_OK; 241 } 242 243 return fssh_acquire_sem(lock->sem); 244 } 245 246 247 extern "C" fssh_status_t 248 fssh_rw_lock_read_unlock(fssh_rw_lock *lock) 249 { 250 if (lock->holder == fssh_find_thread(NULL) && --lock->count > 0) 251 return FSSH_B_OK; 252 253 return fssh_release_sem(lock->sem); 254 } 255 256 257 extern "C" fssh_status_t 258 fssh_rw_lock_write_lock(fssh_rw_lock *lock) 259 { 260 if (lock->holder == fssh_find_thread(NULL)) { 261 lock->count++; 262 return FSSH_B_OK; 263 } 264 265 fssh_status_t status = fssh_acquire_sem_etc(lock->sem, FSSH_RW_MAX_READERS, 266 0, 0); 267 if (status == FSSH_B_OK) { 268 lock->holder = fssh_find_thread(NULL); 269 lock->count = 1; 270 } 271 return status; 272 } 273 274 275 extern "C" fssh_status_t 276 fssh_rw_lock_write_unlock(fssh_rw_lock *lock) 277 { 278 if (--lock->count > 0) 279 return FSSH_B_OK; 280 281 lock->holder = -1; 282 283 return fssh_release_sem_etc(lock->sem, FSSH_RW_MAX_READERS, 0); 284 } 285 286