]> git.saurik.com Git - apple/libc.git/blob - pthreads.subproj/pthread_mutex.c
427026a78a0731c1d4ac71bfb8b2d845fe375950
[apple/libc.git] / pthreads.subproj / pthread_mutex.c
1 /*
2 * Copyright 1996 1995 by Open Software Foundation, Inc. 1997 1996 1995 1994 1993 1992 1991
3 * All Rights Reserved
4 *
5 * Permission to use, copy, modify, and distribute this software and
6 * its documentation for any purpose and without fee is hereby granted,
7 * provided that the above copyright notice appears in all copies and
8 * that both the copyright notice and this permission notice appear in
9 * supporting documentation.
10 *
11 * OSF DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
12 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
13 * FOR A PARTICULAR PURPOSE.
14 *
15 * IN NO EVENT SHALL OSF BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
16 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
17 * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
18 * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
19 * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20 *
21 */
22 /*
23 * MkLinux
24 */
25
26 /*
27 * POSIX Pthread Library
28 * -- Mutex variable support
29 */
30
31 #include "pthread_internals.h"
32
33 /*
34 * Destroy a mutex variable.
35 */
36 int
37 pthread_mutex_destroy(pthread_mutex_t *mutex)
38 {
39 if (mutex->sig != _PTHREAD_MUTEX_SIG)
40 return (EINVAL);
41 if ((mutex->owner != (pthread_t)NULL) ||
42 (mutex->busy != (pthread_cond_t *)NULL))
43 return (EBUSY);
44 mutex->sig = _PTHREAD_NO_SIG;
45 return (ESUCCESS);
46 }
47
48 /*
49 * Initialize a mutex variable, possibly with additional attributes.
50 */
51 int
52 pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr)
53 {
54 LOCK_INIT(mutex->lock);
55 mutex->sig = _PTHREAD_MUTEX_SIG;
56 if (attr)
57 {
58 if (attr->sig != _PTHREAD_MUTEX_ATTR_SIG)
59 return (EINVAL);
60 mutex->prioceiling = attr->prioceiling;
61 mutex->protocol = attr->protocol;
62 } else
63 {
64 mutex->prioceiling = _PTHREAD_DEFAULT_PRIOCEILING;
65 mutex->protocol = _PTHREAD_DEFAULT_PROTOCOL;
66 }
67 mutex->owner = (pthread_t)NULL;
68 mutex->next = (pthread_mutex_t *)NULL;
69 mutex->prev = (pthread_mutex_t *)NULL;
70 mutex->busy = (pthread_cond_t *)NULL;
71 mutex->waiters = 0;
72 mutex->cond_lock = 0;
73 mutex->sem = MACH_PORT_NULL;
74 return (ESUCCESS);
75 }
76
77 /*
78 * Manage a list of mutex variables owned by a thread
79 */
80 #if defined(DEBUG)
81 static void
82 _pthread_mutex_add(pthread_mutex_t *mutex)
83 {
84 pthread_mutex_t *m;
85 pthread_t self = pthread_self();
86 if (self != (pthread_t)0) {
87 mutex->owner = self;
88 if ((m = self->mutexes) != (pthread_mutex_t *)NULL)
89 { /* Add to list */
90 m->prev = mutex;
91 }
92 mutex->next = m;
93 mutex->prev = (pthread_mutex_t *)NULL;
94 self->mutexes = mutex;
95 }
96 }
97
98 static void
99 _pthread_mutex_remove(pthread_mutex_t *mutex, pthread_t self)
100 {
101 pthread_mutex_t *n, *prev;
102 if ((n = mutex->next) != (pthread_mutex_t *)NULL)
103 {
104 n->prev = mutex->prev;
105 }
106 if ((prev = mutex->prev) != (pthread_mutex_t *)NULL)
107 {
108 prev->next = mutex->next;
109 } else
110 { /* This is the first in the list */
111 if (self != (pthread_t)0) {
112 self->mutexes = n;
113 }
114 }
115 mutex->owner = (pthread_t)NULL;
116 }
117 #endif
118
119 /*
120 * Lock a mutex.
121 * TODO: Priority inheritance stuff
122 */
123 int
124 pthread_mutex_lock(pthread_mutex_t *mutex)
125 {
126 kern_return_t kern_res;
127
128 if (mutex->sig == _PTHREAD_MUTEX_SIG_init)
129 {
130 int res;
131 if (res = pthread_mutex_init(mutex, NULL))
132 return (res);
133 }
134 if (mutex->sig != _PTHREAD_MUTEX_SIG)
135 return (EINVAL); /* Not a mutex variable */
136 LOCK(mutex->lock);
137 if (mutex->waiters || (mutex->owner != (pthread_t)NULL))
138 {
139 mutex->waiters++;
140 if (mutex->sem == MACH_PORT_NULL) {
141 mutex->sem = new_sem_from_pool();
142 }
143 UNLOCK(mutex->lock);
144 do {
145 PTHREAD_MACH_CALL(semaphore_wait(mutex->sem), kern_res);
146 } while (kern_res == KERN_ABORTED);
147 LOCK(mutex->lock);
148 mutex->waiters--;
149 if (mutex->waiters == 0) {
150 restore_sem_to_pool(mutex->sem);
151 mutex->sem = MACH_PORT_NULL;
152 }
153 if (mutex->cond_lock) {
154 mutex->cond_lock = 0;
155 }
156 }
157 #if defined(DEBUG)
158 _pthread_mutex_add(mutex);
159 #else
160 mutex->owner = (pthread_t)0x12141968;
161 #endif
162 UNLOCK(mutex->lock);
163 return (ESUCCESS);
164 }
165
166 /*
167 * Attempt to lock a mutex, but don't block if this isn't possible.
168 */
169 int
170 pthread_mutex_trylock(pthread_mutex_t *mutex)
171 {
172 kern_return_t kern_res;
173
174 if (mutex->sig == _PTHREAD_MUTEX_SIG_init)
175 {
176 int res;
177 if (res = pthread_mutex_init(mutex, NULL))
178 return (res);
179 }
180 if (mutex->sig != _PTHREAD_MUTEX_SIG)
181 return (EINVAL); /* Not a mutex variable */
182 if (!TRY_LOCK(mutex->lock)) {
183 return (EBUSY);
184 }
185 if (mutex->waiters ||
186 ((mutex->owner != (pthread_t)NULL) && (mutex->cond_lock == 0)))
187 {
188 UNLOCK(mutex->lock);
189 return (EBUSY);
190 } else
191 {
192 #if defined(DEBUG)
193 _pthread_mutex_add(mutex);
194 #else
195 mutex->owner = (pthread_t)0x12141968;
196 #endif
197 if (mutex->cond_lock) {
198 PTHREAD_MACH_CALL(semaphore_wait(mutex->sem), kern_res);
199 mutex->cond_lock = 0;
200 restore_sem_to_pool(mutex->sem);
201 mutex->sem = MACH_PORT_NULL;
202 }
203 UNLOCK(mutex->lock);
204 return (ESUCCESS);
205 }
206 }
207
208 /*
209 * Unlock a mutex.
210 * TODO: Priority inheritance stuff
211 */
212 int
213 pthread_mutex_unlock(pthread_mutex_t *mutex)
214 {
215 kern_return_t kern_res;
216 int waiters;
217 if (mutex->sig == _PTHREAD_MUTEX_SIG_init)
218 {
219 int res;
220 if (res = pthread_mutex_init(mutex, NULL))
221 return (res);
222 }
223 if (mutex->sig != _PTHREAD_MUTEX_SIG)
224 return (EINVAL); /* Not a mutex variable */
225 LOCK(mutex->lock);
226 #if defined(DEBUG)
227 if (mutex->owner != pthread_self())
228 {
229 UNLOCK(mutex->lock);
230 abort();
231 return (EPERM);
232 } else
233 #endif
234 {
235 #if defined(DEBUG)
236 _pthread_mutex_remove(mutex, mutex->owner);
237 #else
238 mutex->owner = (pthread_t)NULL;
239 #endif
240 waiters = mutex->waiters;
241 UNLOCK(mutex->lock);
242 if (waiters)
243 {
244 PTHREAD_MACH_CALL(semaphore_signal(mutex->sem), kern_res);
245 }
246 return (ESUCCESS);
247 }
248 }
249
250 /*
251 * Fetch the priority ceiling value from a mutex variable.
252 * Note: written as a 'helper' function to hide implementation details.
253 */
254 int
255 pthread_mutex_getprioceiling(const pthread_mutex_t *mutex,
256 int *prioceiling)
257 {
258 if (mutex->sig == _PTHREAD_MUTEX_SIG)
259 {
260 *prioceiling = mutex->prioceiling;
261 return (ESUCCESS);
262 } else
263 {
264 return (EINVAL); /* Not an initialized 'attribute' structure */
265 }
266 }
267
268 /*
269 * Set the priority ceiling for a mutex.
270 * Note: written as a 'helper' function to hide implementation details.
271 */
272 int
273 pthread_mutex_setprioceiling(pthread_mutex_t *mutex,
274 int prioceiling,
275 int *old_prioceiling)
276 {
277 if (mutex->sig == _PTHREAD_MUTEX_SIG)
278 {
279 if ((prioceiling >= -999) ||
280 (prioceiling <= 999))
281 {
282 *old_prioceiling = mutex->prioceiling;
283 mutex->prioceiling = prioceiling;
284 return (ESUCCESS);
285 } else
286 {
287 return (EINVAL); /* Invalid parameter */
288 }
289 } else
290 {
291 return (EINVAL); /* Not an initialized 'attribute' structure */
292 }
293 }
294
295 /*
296 * Destroy a mutex attribute structure.
297 */
298 int
299 pthread_mutexattr_destroy(pthread_mutexattr_t *attr)
300 {
301 attr->sig = _PTHREAD_NO_SIG; /* Uninitialized */
302 return (ESUCCESS);
303 }
304
305 /*
306 * Get the priority ceiling value from a mutex attribute structure.
307 * Note: written as a 'helper' function to hide implementation details.
308 */
309 int
310 pthread_mutexattr_getprioceiling(const pthread_mutexattr_t *attr,
311 int *prioceiling)
312 {
313 if (attr->sig == _PTHREAD_MUTEX_ATTR_SIG)
314 {
315 *prioceiling = attr->prioceiling;
316 return (ESUCCESS);
317 } else
318 {
319 return (EINVAL); /* Not an initialized 'attribute' structure */
320 }
321 }
322
323 /*
324 * Get the mutex 'protocol' value from a mutex attribute structure.
325 * Note: written as a 'helper' function to hide implementation details.
326 */
327 int
328 pthread_mutexattr_getprotocol(const pthread_mutexattr_t *attr,
329 int *protocol)
330 {
331 if (attr->sig == _PTHREAD_MUTEX_ATTR_SIG)
332 {
333 *protocol = attr->protocol;
334 return (ESUCCESS);
335 } else
336 {
337 return (EINVAL); /* Not an initialized 'attribute' structure */
338 }
339 }
340
341 /*
342 * Initialize a mutex attribute structure to system defaults.
343 */
344 int
345 pthread_mutexattr_init(pthread_mutexattr_t *attr)
346 {
347 attr->prioceiling = _PTHREAD_DEFAULT_PRIOCEILING;
348 attr->protocol = _PTHREAD_DEFAULT_PROTOCOL;
349 attr->sig = _PTHREAD_MUTEX_ATTR_SIG;
350 return (ESUCCESS);
351 }
352
353 /*
354 * Set the priority ceiling value in a mutex attribute structure.
355 * Note: written as a 'helper' function to hide implementation details.
356 */
357 int
358 pthread_mutexattr_setprioceiling(pthread_mutexattr_t *attr,
359 int prioceiling)
360 {
361 if (attr->sig == _PTHREAD_MUTEX_ATTR_SIG)
362 {
363 if ((prioceiling >= -999) ||
364 (prioceiling <= 999))
365 {
366 attr->prioceiling = prioceiling;
367 return (ESUCCESS);
368 } else
369 {
370 return (EINVAL); /* Invalid parameter */
371 }
372 } else
373 {
374 return (EINVAL); /* Not an initialized 'attribute' structure */
375 }
376 }
377
378 /*
379 * Set the mutex 'protocol' value in a mutex attribute structure.
380 * Note: written as a 'helper' function to hide implementation details.
381 */
382 int
383 pthread_mutexattr_setprotocol(pthread_mutexattr_t *attr,
384 int protocol)
385 {
386 if (attr->sig == _PTHREAD_MUTEX_ATTR_SIG)
387 {
388 if ((protocol == PTHREAD_PRIO_NONE) ||
389 (protocol == PTHREAD_PRIO_INHERIT) ||
390 (protocol == PTHREAD_PRIO_PROTECT))
391 {
392 attr->protocol = protocol;
393 return (ESUCCESS);
394 } else
395 {
396 return (EINVAL); /* Invalid parameter */
397 }
398 } else
399 {
400 return (EINVAL); /* Not an initialized 'attribute' structure */
401 }
402 }
403
404 int mutex_try_lock(int *x) {
405 return _spin_lock_try((pthread_lock_t *)x);
406 }
407
408 void mutex_wait_lock(int *x) {
409 for (;;) {
410 if( _spin_lock_try((pthread_lock_t *)x)) {
411 return;
412 }
413 swtch_pri(0);
414 }
415 }
416
417 void cthread_yield(void) {
418 sched_yield();
419 }
420