1 /* 2 * Copyright 2009, Michael Lotz, mmlr@mlotz.ch. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 7 #include <locks.h> 8 9 #include <OS.h> 10 11 #include <syscalls.h> 12 #include <user_thread.h> 13 14 15 typedef struct rw_lock_waiter { 16 rw_lock_waiter * next; 17 thread_id thread; 18 bool writer; 19 } rw_lock_waiter; 20 21 22 static status_t 23 rw_lock_wait(rw_lock *lock, bool writer) 24 { 25 rw_lock_waiter waiter; 26 waiter.thread = find_thread(NULL); 27 waiter.next = NULL; 28 waiter.writer = writer; 29 30 if (lock->waiters != NULL) 31 lock->last_waiter->next = &waiter; 32 else 33 lock->waiters = &waiter; 34 35 lock->last_waiter = &waiter; 36 37 // the rw_lock is locked when entering, release it before blocking 38 get_user_thread()->wait_status = 1; 39 mutex_unlock(&lock->lock); 40 41 status_t result; 42 do { 43 result = _kern_block_thread(0, 0); 44 } while (result == B_INTERRUPTED); 45 46 // and lock it again before returning 47 mutex_lock(&lock->lock); 48 return result; 49 } 50 51 52 static void 53 rw_lock_unblock(rw_lock *lock) 54 { 55 // this is called locked 56 if (lock->holder >= 0) 57 return; 58 59 rw_lock_waiter *waiter = lock->waiters; 60 if (waiter == NULL) 61 return; 62 63 if (waiter->writer) { 64 if (lock->reader_count > 0) 65 return; 66 67 lock->waiters = waiter->next; 68 lock->holder = waiter->thread; 69 _kern_unblock_thread(waiter->thread, B_OK); 70 return; 71 } 72 73 while (waiter != NULL && !waiter->writer) { 74 lock->reader_count++; 75 lock->waiters = waiter->next; 76 _kern_unblock_thread(waiter->thread, B_OK); 77 waiter = lock->waiters; 78 } 79 } 80 81 82 status_t 83 rw_lock_init(rw_lock *lock, const char *name) 84 { 85 lock->name = name; 86 lock->waiters = NULL; 87 lock->holder = -1; 88 lock->reader_count = 0; 89 lock->writer_count = 0; 90 lock->owner_count = 0; 91 return mutex_init(&lock->lock, name); 92 } 93 94 95 void 96 rw_lock_destroy(rw_lock *lock) 97 { 98 mutex_lock(&lock->lock); 99 100 rw_lock_waiter *waiter = lock->waiters; 101 while (waiter != NULL) { 102 _kern_unblock_thread(waiter->thread, B_ERROR); 103 waiter = waiter->next; 104 } 105 106 mutex_destroy(&lock->lock); 107 } 108 109 110 status_t 111 rw_lock_read_lock(rw_lock *lock) 112 { 113 MutexLocker locker(lock->lock); 114 115 if (lock->writer_count == 0) { 116 lock->reader_count++; 117 return B_OK; 118 } 119 120 if (lock->holder == find_thread(NULL)) { 121 lock->owner_count++; 122 return B_OK; 123 } 124 125 return rw_lock_wait(lock, false); 126 } 127 128 129 status_t 130 rw_lock_read_unlock(rw_lock *lock) 131 { 132 MutexLocker locker(lock->lock); 133 134 if (lock->holder == find_thread(NULL)) { 135 if (--lock->owner_count > 0) 136 return B_OK; 137 138 // this originally has been a write lock 139 lock->writer_count--; 140 lock->holder = -1; 141 142 rw_lock_unblock(lock); 143 return B_OK; 144 } 145 146 if (lock->reader_count <= 0) { 147 debugger("rw_lock not read locked"); 148 return B_ERROR; 149 } 150 151 lock->reader_count--; 152 rw_lock_unblock(lock); 153 return B_OK; 154 } 155 156 157 status_t 158 rw_lock_write_lock(rw_lock *lock) 159 { 160 MutexLocker locker(lock->lock); 161 162 if (lock->reader_count == 0 && lock->writer_count == 0) { 163 lock->writer_count++; 164 lock->holder = find_thread(NULL); 165 lock->owner_count = 1; 166 return B_OK; 167 } 168 169 if (lock->holder == find_thread(NULL)) { 170 lock->owner_count++; 171 return B_OK; 172 } 173 174 lock->writer_count++; 175 176 status_t result = rw_lock_wait(lock, true); 177 if (result != B_OK) 178 return result; 179 180 if (lock->holder != find_thread(NULL)) { 181 debugger("write locked but holder not set"); 182 return B_ERROR; 183 } 184 185 lock->owner_count = 1; 186 return B_OK; 187 } 188 189 190 status_t 191 rw_lock_write_unlock(rw_lock *lock) 192 { 193 MutexLocker locker(lock->lock); 194 195 if (lock->holder != find_thread(NULL)) { 196 debugger("rw_lock not write locked"); 197 return B_ERROR; 198 } 199 200 if (--lock->owner_count > 0) 201 return B_OK; 202 203 lock->writer_count--; 204 lock->holder = -1; 205 rw_lock_unblock(lock); 206 return B_OK; 207 } 208