1 /* 2 * Copyright 2009, Michael Lotz, mmlr@mlotz.ch. 3 * Copyright 2008-2009, Ingo Weinhold, ingo_weinhold@gmx.de. 4 * Copyright 2002-2009, Axel Dörfler, axeld@pinc-software.de. All rights reserved. 5 * Distributed under the terms of the MIT License. 6 * 7 * Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. 8 * Distributed under the terms of the NewOS License. 9 */ 10 11 12 #include <locks.h> 13 14 #include <OS.h> 15 16 17 // #pragma mark - mutex 18 19 20 status_t 21 mutex_init(mutex *lock, const char *name) 22 { 23 if (lock == NULL || name == NULL) 24 return B_BAD_VALUE; 25 26 lock->benaphore = 0; 27 lock->semaphore = create_sem(0, name); 28 if (lock->semaphore < 0) 29 return lock->semaphore; 30 31 return B_OK; 32 } 33 34 35 void 36 mutex_destroy(mutex *lock) 37 { 38 delete_sem(lock->semaphore); 39 } 40 41 42 status_t 43 mutex_lock(mutex *lock) 44 { 45 if (atomic_add(&lock->benaphore, 1) == 0) 46 return B_OK; 47 48 status_t result; 49 do { 50 result = acquire_sem(lock->semaphore); 51 } while (result == B_INTERRUPTED); 52 53 return result; 54 } 55 56 57 void 58 mutex_unlock(mutex *lock) 59 { 60 if (atomic_add(&lock->benaphore, -1) != 1) 61 release_sem(lock->semaphore); 62 } 63 64 65 // #pragma mark - lazy mutex 66 67 68 enum { 69 STATE_UNINITIALIZED = -1, 70 STATE_INITIALIZING = -2, 71 STATE_SPIN_LOCKED = -3, 72 STATE_SPIN_UNLOCKED = -4 73 }; 74 75 76 static inline bool 77 lazy_mutex_ensure_init(lazy_mutex *lock) 78 { 79 int32 value = atomic_test_and_set((vint32*)&lock->semaphore, 80 STATE_INITIALIZING, STATE_UNINITIALIZED); 81 82 if (value >= 0) 83 return true; 84 85 if (value == STATE_UNINITIALIZED) { 86 // we're the first -- perform the initialization 87 sem_id semaphore = create_sem(0, lock->name); 88 if (semaphore < 0) 89 semaphore = STATE_SPIN_UNLOCKED; 90 atomic_set((vint32*)&lock->semaphore, semaphore); 91 return semaphore >= 0; 92 } 93 94 if (value == STATE_INITIALIZING) { 95 // someone else is initializing -- spin until that is done 96 while (atomic_get((vint32*)&lock->semaphore) == STATE_INITIALIZING) { 97 } 98 } 99 100 return lock->semaphore >= 0; 101 } 102 103 104 status_t 105 lazy_mutex_init(lazy_mutex *lock, const char *name) 106 { 107 if (lock == NULL || name == NULL) 108 return B_BAD_VALUE; 109 110 lock->benaphore = 0; 111 lock->semaphore = STATE_UNINITIALIZED; 112 lock->name = name; 113 114 return B_OK; 115 } 116 117 118 void 119 lazy_mutex_destroy(lazy_mutex *lock) 120 { 121 if (lock->semaphore >= 0) 122 delete_sem(lock->semaphore); 123 } 124 125 126 status_t 127 lazy_mutex_lock(lazy_mutex *lock) 128 { 129 if (atomic_add(&lock->benaphore, 1) == 0) 130 return B_OK; 131 132 if (lazy_mutex_ensure_init(lock)) { 133 // acquire the semaphore 134 status_t result; 135 do { 136 result = acquire_sem(lock->semaphore); 137 } while (result == B_INTERRUPTED); 138 139 return result; 140 } else { 141 // the semaphore creation failed -- so we use it like a spinlock instead 142 while (atomic_test_and_set((vint32*)&lock->semaphore, 143 STATE_SPIN_LOCKED, STATE_SPIN_UNLOCKED) 144 != STATE_SPIN_UNLOCKED) { 145 } 146 return B_OK; 147 } 148 } 149 150 151 void 152 lazy_mutex_unlock(lazy_mutex *lock) 153 { 154 if (atomic_add(&lock->benaphore, -1) == 1) 155 return; 156 157 if (lazy_mutex_ensure_init(lock)) { 158 // release the semaphore 159 release_sem(lock->semaphore); 160 } else { 161 // the semaphore creation failed -- so we use it like a spinlock instead 162 atomic_set((vint32*)&lock->semaphore, STATE_SPIN_UNLOCKED); 163 } 164 } 165