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
19extern "C" int32_t
20fssh_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
29extern "C" void
30fssh_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
49extern "C" void
50fssh_recursive_lock_init(fssh_recursive_lock *lock, const char *name)
51{
52	fssh_recursive_lock_init_etc(lock, name, 0);
53}
54
55
56extern "C" void
57fssh_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
67extern "C" fssh_status_t
68fssh_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
84extern "C" fssh_status_t
85fssh_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
102extern "C" void
103fssh_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
115extern "C" void
116fssh_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
129extern "C" void
130fssh_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
146extern "C" void
147fssh_mutex_init_etc(fssh_mutex *m, const char *name, uint32_t flags)
148{
149	fssh_mutex_init(m, name);
150}
151
152
153extern "C" void
154fssh_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
167extern "C" fssh_status_t
168fssh_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
185extern "C" void
186fssh_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
200extern "C" void
201fssh_mutex_transfer_lock(fssh_mutex *mutex, fssh_thread_id thread)
202{
203	mutex->holder = thread;
204}
205
206
207//	#pragma mark -
208
209
210extern "C" void
211fssh_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
228extern "C" void
229fssh_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
235extern "C" void
236fssh_rw_lock_destroy(fssh_rw_lock *lock)
237{
238	if (lock == NULL)
239		return;
240
241	fssh_delete_sem(lock->sem);
242}
243
244
245extern "C" fssh_status_t
246fssh_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
257extern "C" fssh_status_t
258fssh_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
267extern "C" fssh_status_t
268fssh_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
285extern "C" fssh_status_t
286fssh_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