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