libroot/posix/stdio: Remove unused portions.
[haiku.git] / src / system / libroot / os / locks / rw_lock.cpp
blobbc8c6fc7b32fc3daefed5715b9ec727ebae339b7
1 /*
2 * Copyright 2009, Michael Lotz, mmlr@mlotz.ch.
3 * Distributed under the terms of the MIT License.
4 */
7 #include <locks.h>
9 #include <OS.h>
11 #include <syscalls.h>
12 #include <user_thread.h>
15 typedef struct rw_lock_waiter {
16 rw_lock_waiter * next;
17 thread_id thread;
18 bool writer;
19 } rw_lock_waiter;
22 static status_t
23 rw_lock_wait(rw_lock *lock, bool writer)
25 rw_lock_waiter waiter;
26 waiter.thread = find_thread(NULL);
27 waiter.next = NULL;
28 waiter.writer = writer;
30 if (lock->waiters != NULL)
31 lock->last_waiter->next = &waiter;
32 else
33 lock->waiters = &waiter;
35 lock->last_waiter = &waiter;
37 // the rw_lock is locked when entering, release it before blocking
38 get_user_thread()->wait_status = 1;
39 mutex_unlock(&lock->lock);
41 status_t result;
42 do {
43 result = _kern_block_thread(0, 0);
44 } while (result == B_INTERRUPTED);
46 // and lock it again before returning
47 mutex_lock(&lock->lock);
48 return result;
52 static void
53 rw_lock_unblock(rw_lock *lock)
55 // this is called locked
56 if (lock->holder >= 0)
57 return;
59 rw_lock_waiter *waiter = lock->waiters;
60 if (waiter == NULL)
61 return;
63 if (waiter->writer) {
64 if (lock->reader_count > 0)
65 return;
67 lock->waiters = waiter->next;
68 lock->holder = waiter->thread;
69 _kern_unblock_thread(waiter->thread, B_OK);
70 return;
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;
82 void
83 __rw_lock_init(rw_lock *lock, const char *name)
85 rw_lock_init_etc(lock, name, 0);
89 void
90 __rw_lock_init_etc(rw_lock *lock, const char *name, uint32 flags)
92 lock->waiters = NULL;
93 lock->holder = -1;
94 lock->reader_count = 0;
95 lock->writer_count = 0;
96 lock->owner_count = 0;
97 mutex_init_etc(&lock->lock, name, flags);
101 void
102 __rw_lock_destroy(rw_lock *lock)
104 mutex_lock(&lock->lock);
106 rw_lock_waiter *waiter = lock->waiters;
107 while (waiter != NULL) {
108 _kern_unblock_thread(waiter->thread, B_ERROR);
109 waiter = waiter->next;
112 mutex_destroy(&lock->lock);
116 status_t
117 __rw_lock_read_lock(rw_lock *lock)
119 MutexLocker locker(lock->lock);
121 if (lock->writer_count == 0) {
122 lock->reader_count++;
123 return B_OK;
126 if (lock->holder == find_thread(NULL)) {
127 lock->owner_count++;
128 return B_OK;
131 return rw_lock_wait(lock, false);
135 status_t
136 __rw_lock_read_unlock(rw_lock *lock)
138 MutexLocker locker(lock->lock);
140 if (lock->holder == find_thread(NULL)) {
141 if (--lock->owner_count > 0)
142 return B_OK;
144 // this originally has been a write lock
145 lock->writer_count--;
146 lock->holder = -1;
148 rw_lock_unblock(lock);
149 return B_OK;
152 if (lock->reader_count <= 0) {
153 debugger("rw_lock not read locked");
154 return B_ERROR;
157 lock->reader_count--;
158 rw_lock_unblock(lock);
159 return B_OK;
163 status_t
164 __rw_lock_write_lock(rw_lock *lock)
166 MutexLocker locker(lock->lock);
168 if (lock->reader_count == 0 && lock->writer_count == 0) {
169 lock->writer_count++;
170 lock->holder = find_thread(NULL);
171 lock->owner_count = 1;
172 return B_OK;
175 if (lock->holder == find_thread(NULL)) {
176 lock->owner_count++;
177 return B_OK;
180 lock->writer_count++;
182 status_t result = rw_lock_wait(lock, true);
183 if (result != B_OK)
184 return result;
186 if (lock->holder != find_thread(NULL)) {
187 debugger("write locked but holder not set");
188 return B_ERROR;
191 lock->owner_count = 1;
192 return B_OK;
196 status_t
197 __rw_lock_write_unlock(rw_lock *lock)
199 MutexLocker locker(lock->lock);
201 if (lock->holder != find_thread(NULL)) {
202 debugger("rw_lock not write locked");
203 return B_ERROR;
206 if (--lock->owner_count > 0)
207 return B_OK;
209 lock->writer_count--;
210 lock->holder = -1;
211 rw_lock_unblock(lock);
212 return B_OK;