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
fssh_recursive_lock_get_recursion(fssh_recursive_lock * lock)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
fssh_recursive_lock_init_etc(fssh_recursive_lock * lock,const char * name,uint32_t flags)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
fssh_recursive_lock_init(fssh_recursive_lock * lock,const char * name)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
fssh_recursive_lock_destroy(fssh_recursive_lock * lock)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
fssh_recursive_lock_lock(fssh_recursive_lock * lock)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
fssh_recursive_lock_trylock(fssh_recursive_lock * lock)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
fssh_recursive_lock_unlock(fssh_recursive_lock * lock)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
fssh_recursive_lock_transfer_lock(fssh_recursive_lock * lock,fssh_thread_id thread)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
fssh_mutex_init(fssh_mutex * m,const char * name)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
fssh_mutex_init_etc(fssh_mutex * m,const char * name,uint32_t flags)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
fssh_mutex_destroy(fssh_mutex * mutex)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
fssh_mutex_lock(fssh_mutex * mutex)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
fssh_mutex_unlock(fssh_mutex * mutex)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
fssh_mutex_transfer_lock(fssh_mutex * mutex,fssh_thread_id thread)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
fssh_rw_lock_init(fssh_rw_lock * lock,const char * name)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
fssh_rw_lock_init_etc(fssh_rw_lock * lock,const char * name,uint32_t flags)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
fssh_rw_lock_destroy(fssh_rw_lock * lock)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
fssh_rw_lock_read_lock(fssh_rw_lock * lock)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
fssh_rw_lock_read_unlock(fssh_rw_lock * lock)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
fssh_rw_lock_write_lock(fssh_rw_lock * lock)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
fssh_rw_lock_write_unlock(fssh_rw_lock * lock)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