xref: /haiku/src/tools/fs_shell/lock.cpp (revision 1e60bdeab63fa7a57bc9a55b032052e95a18bd2c)
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
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
30 fssh_recursive_lock_init(fssh_recursive_lock *lock, const char *name)
31 {
32 	if (lock == NULL)
33 		return;
34 
35 	if (name == NULL)
36 		name = "recursive lock";
37 
38 	lock->holder = -1;
39 	lock->recursion = 0;
40 	lock->sem = fssh_create_sem(1, name);
41 	if (lock->sem < FSSH_B_OK)
42 		fssh_panic("could not create recursive lock");
43 }
44 
45 
46 extern "C" void
47 fssh_recursive_lock_destroy(fssh_recursive_lock *lock)
48 {
49 	if (lock == NULL)
50 		return;
51 
52 	fssh_delete_sem(lock->sem);
53 	lock->sem = -1;
54 }
55 
56 
57 extern "C" fssh_status_t
58 fssh_recursive_lock_lock(fssh_recursive_lock *lock)
59 {
60 	fssh_thread_id thread = fssh_find_thread(NULL);
61 
62 	if (thread != lock->holder) {
63 		fssh_status_t status = fssh_acquire_sem(lock->sem);
64 		if (status < FSSH_B_OK)
65 			return status;
66 
67 		lock->holder = thread;
68 	}
69 	lock->recursion++;
70 	return FSSH_B_OK;
71 }
72 
73 
74 extern "C" fssh_status_t
75 fssh_recursive_lock_trylock(fssh_recursive_lock *lock)
76 {
77 	fssh_thread_id thread = fssh_find_thread(NULL);
78 
79 	if (thread != lock->holder) {
80 		fssh_status_t status = fssh_acquire_sem_etc(lock->sem, 1,
81 			FSSH_B_RELATIVE_TIMEOUT, 0);
82 		if (status < FSSH_B_OK)
83 			return status;
84 
85 		lock->holder = thread;
86 	}
87 	lock->recursion++;
88 	return FSSH_B_OK;
89 }
90 
91 
92 extern "C" void
93 fssh_recursive_lock_unlock(fssh_recursive_lock *lock)
94 {
95 	if (fssh_find_thread(NULL) != lock->holder)
96 		fssh_panic("recursive_lock %p unlocked by non-holder thread!\n", lock);
97 
98 	if (--lock->recursion == 0) {
99 		lock->holder = -1;
100 		fssh_release_sem(lock->sem);
101 	}
102 }
103 
104 
105 extern "C" void
106 fssh_recursive_lock_transfer_lock(fssh_recursive_lock *lock,
107 	fssh_thread_id thread)
108 {
109 	if (lock->recursion != 1)
110 		fssh_panic("invalid recursion level for lock transfer!");
111 
112 	lock->holder = thread;
113 }
114 
115 
116 //	#pragma mark -
117 
118 
119 extern "C" void
120 fssh_mutex_init(fssh_mutex *m, const char *name)
121 {
122 	if (m == NULL)
123 		return;
124 
125 	if (name == NULL)
126 		name = "mutex_sem";
127 
128 	m->holder = -1;
129 
130 	m->sem = fssh_create_sem(1, name);
131 	if (m->sem < FSSH_B_OK)
132 		fssh_panic("could not create mutex");
133 }
134 
135 
136 extern "C" void
137 fssh_mutex_init_etc(fssh_mutex *m, const char *name, uint32_t flags)
138 {
139 	fssh_mutex_init(m, name);
140 }
141 
142 
143 extern "C" void
144 fssh_mutex_destroy(fssh_mutex *mutex)
145 {
146 	if (mutex == NULL)
147 		return;
148 
149 	if (mutex->sem >= 0) {
150 		fssh_delete_sem(mutex->sem);
151 		mutex->sem = -1;
152 	}
153 	mutex->holder = -1;
154 }
155 
156 
157 extern "C" fssh_status_t
158 fssh_mutex_lock(fssh_mutex *mutex)
159 {
160 	fssh_thread_id me = fssh_find_thread(NULL);
161 	fssh_status_t status;
162 
163 	status = fssh_acquire_sem(mutex->sem);
164 	if (status < FSSH_B_OK)
165 		return status;
166 
167 	if (me == mutex->holder)
168 		fssh_panic("mutex_lock failure: mutex %p (sem = 0x%x) acquired twice by thread 0x%x\n", mutex, (int)mutex->sem, (int)me);
169 
170 	mutex->holder = me;
171 	return FSSH_B_OK;
172 }
173 
174 
175 extern "C" void
176 fssh_mutex_unlock(fssh_mutex *mutex)
177 {
178 	fssh_thread_id me = fssh_find_thread(NULL);
179 
180 	if (me != mutex->holder) {
181 		fssh_panic("mutex_unlock failure: thread 0x%x is trying to release mutex %p (current holder 0x%x)\n",
182 			(int)me, mutex, (int)mutex->holder);
183 	}
184 
185 	mutex->holder = -1;
186 	fssh_release_sem(mutex->sem);
187 }
188 
189 
190 extern "C" void
191 fssh_mutex_transfer_lock(fssh_mutex *mutex, fssh_thread_id thread)
192 {
193 	mutex->holder = thread;
194 }
195 
196 
197 //	#pragma mark -
198 
199 
200 extern "C" void
201 fssh_rw_lock_init(fssh_rw_lock *lock, const char *name)
202 {
203 	if (lock == NULL)
204 		return;
205 
206 	if (name == NULL)
207 		name = "r/w lock";
208 
209 	lock->count = 0;
210 	lock->holder = -1;
211 
212 	lock->sem = fssh_create_sem(FSSH_RW_MAX_READERS, name);
213 	if (lock->sem < FSSH_B_OK)
214 		fssh_panic("could not create r/w lock");
215 }
216 
217 
218 extern "C" void
219 fssh_rw_lock_init_etc(fssh_rw_lock *lock, const char *name, uint32_t flags)
220 {
221 	fssh_rw_lock_init(lock, name);
222 }
223 
224 
225 extern "C" void
226 fssh_rw_lock_destroy(fssh_rw_lock *lock)
227 {
228 	if (lock == NULL)
229 		return;
230 
231 	fssh_delete_sem(lock->sem);
232 }
233 
234 
235 extern "C" fssh_status_t
236 fssh_rw_lock_read_lock(fssh_rw_lock *lock)
237 {
238 	if (lock->holder == fssh_find_thread(NULL)) {
239 		lock->count++;
240 		return FSSH_B_OK;
241 	}
242 
243 	return fssh_acquire_sem(lock->sem);
244 }
245 
246 
247 extern "C" fssh_status_t
248 fssh_rw_lock_read_unlock(fssh_rw_lock *lock)
249 {
250 	if (lock->holder == fssh_find_thread(NULL) && --lock->count > 0)
251 		return FSSH_B_OK;
252 
253 	return fssh_release_sem(lock->sem);
254 }
255 
256 
257 extern "C" fssh_status_t
258 fssh_rw_lock_write_lock(fssh_rw_lock *lock)
259 {
260 	if (lock->holder == fssh_find_thread(NULL)) {
261 		lock->count++;
262 		return FSSH_B_OK;
263 	}
264 
265 	fssh_status_t status = fssh_acquire_sem_etc(lock->sem, FSSH_RW_MAX_READERS,
266 		0, 0);
267 	if (status == FSSH_B_OK) {
268 		lock->holder = fssh_find_thread(NULL);
269 		lock->count = 1;
270 	}
271 	return status;
272 }
273 
274 
275 extern "C" fssh_status_t
276 fssh_rw_lock_write_unlock(fssh_rw_lock *lock)
277 {
278 	if (--lock->count > 0)
279 		return FSSH_B_OK;
280 
281 	lock->holder = -1;
282 
283 	return fssh_release_sem_etc(lock->sem, FSSH_RW_MAX_READERS, 0);
284 }
285 
286