]> git.saurik.com Git - apple/libc.git/blame - pthreads/pthread_mutex.c
Libc-262.3.2.tar.gz
[apple/libc.git] / pthreads / pthread_mutex.c
CommitLineData
e9ce8d39
A
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 */
36int
37pthread_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 */
51int
52pthread_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;
5b2abdfb
A
62 mutex->type = attr->type;
63 if ((mutex->type == PTHREAD_MUTEX_DEFAULT) || (mutex->type == PTHREAD_MUTEX_NORMAL))
64 mutex->def = 1;
65 else
66 mutex->def = 0;
67 } else {
e9ce8d39
A
68 mutex->prioceiling = _PTHREAD_DEFAULT_PRIOCEILING;
69 mutex->protocol = _PTHREAD_DEFAULT_PROTOCOL;
5b2abdfb
A
70 mutex->type = PTHREAD_MUTEX_DEFAULT;
71 mutex->def = 1;
e9ce8d39 72 }
5b2abdfb 73 mutex->lock_count = 0;
e9ce8d39
A
74 mutex->owner = (pthread_t)NULL;
75 mutex->next = (pthread_mutex_t *)NULL;
76 mutex->prev = (pthread_mutex_t *)NULL;
77 mutex->busy = (pthread_cond_t *)NULL;
78 mutex->waiters = 0;
79 mutex->cond_lock = 0;
80 mutex->sem = MACH_PORT_NULL;
81 return (ESUCCESS);
82}
83
84/*
85 * Manage a list of mutex variables owned by a thread
86 */
87#if defined(DEBUG)
88static void
5b2abdfb 89_pthread_mutex_add(pthread_mutex_t *mutex, pthread_t self)
e9ce8d39
A
90{
91 pthread_mutex_t *m;
e9ce8d39 92 if (self != (pthread_t)0) {
e9ce8d39
A
93 if ((m = self->mutexes) != (pthread_mutex_t *)NULL)
94 { /* Add to list */
5b2abdfb 95 m->prev = mutex;
e9ce8d39
A
96 }
97 mutex->next = m;
98 mutex->prev = (pthread_mutex_t *)NULL;
99 self->mutexes = mutex;
100 }
101}
102
103static void
104_pthread_mutex_remove(pthread_mutex_t *mutex, pthread_t self)
105{
106 pthread_mutex_t *n, *prev;
107 if ((n = mutex->next) != (pthread_mutex_t *)NULL)
108 {
109 n->prev = mutex->prev;
110 }
111 if ((prev = mutex->prev) != (pthread_mutex_t *)NULL)
112 {
113 prev->next = mutex->next;
114 } else
115 { /* This is the first in the list */
116 if (self != (pthread_t)0) {
117 self->mutexes = n;
118 }
119 }
e9ce8d39
A
120}
121#endif
122
123/*
124 * Lock a mutex.
125 * TODO: Priority inheritance stuff
126 */
127int
128pthread_mutex_lock(pthread_mutex_t *mutex)
129{
130 kern_return_t kern_res;
5b2abdfb
A
131 pthread_t self;
132 int slowpath;
e9ce8d39
A
133
134 if (mutex->sig == _PTHREAD_MUTEX_SIG_init)
135 {
136 int res;
137 if (res = pthread_mutex_init(mutex, NULL))
138 return (res);
139 }
140 if (mutex->sig != _PTHREAD_MUTEX_SIG)
141 return (EINVAL); /* Not a mutex variable */
5b2abdfb
A
142
143#if !defined(DEBUG)
144 if (mutex->def) {
145 slowpath = 0;
146 self = (pthread_t)0x12141968;
147 } else
148#endif /* DEBUG */
149 {
150 slowpath = 1;
151 self = pthread_self();
152 }
153
e9ce8d39 154 LOCK(mutex->lock);
5b2abdfb 155
e9ce8d39
A
156 if (mutex->waiters || (mutex->owner != (pthread_t)NULL))
157 {
5b2abdfb
A
158 if(slowpath && (mutex->owner == self)) {
159 if(mutex->type == PTHREAD_MUTEX_ERRORCHECK ) {
160 UNLOCK(mutex->lock);
161 return(EDEADLK);
162 } else if (mutex->type == PTHREAD_MUTEX_RECURSIVE ) {
163 if (mutex->lock_count >= USHRT_MAX){
164 UNLOCK(mutex->lock);
165 return(EAGAIN);
166 }
167 mutex->lock_count++;
168 UNLOCK(mutex->lock);
169 return(ESUCCESS);
170 }
171 }
e9ce8d39
A
172 mutex->waiters++;
173 if (mutex->sem == MACH_PORT_NULL) {
174 mutex->sem = new_sem_from_pool();
175 }
176 UNLOCK(mutex->lock);
3b2a1fe8
A
177 do {
178 PTHREAD_MACH_CALL(semaphore_wait(mutex->sem), kern_res);
179 } while (kern_res == KERN_ABORTED);
e9ce8d39
A
180 LOCK(mutex->lock);
181 mutex->waiters--;
182 if (mutex->waiters == 0) {
183 restore_sem_to_pool(mutex->sem);
184 mutex->sem = MACH_PORT_NULL;
185 }
186 if (mutex->cond_lock) {
187 mutex->cond_lock = 0;
188 }
189 }
5b2abdfb
A
190#if defined(DEBUG)
191 _pthread_mutex_add(mutex, self);
e9ce8d39 192#endif
5b2abdfb
A
193 mutex->owner = self;
194 if (slowpath && (mutex->type == PTHREAD_MUTEX_RECURSIVE))
195 mutex->lock_count = 1;
e9ce8d39
A
196 UNLOCK(mutex->lock);
197 return (ESUCCESS);
198}
199
200/*
201 * Attempt to lock a mutex, but don't block if this isn't possible.
202 */
203int
204pthread_mutex_trylock(pthread_mutex_t *mutex)
205{
206 kern_return_t kern_res;
5b2abdfb
A
207 pthread_t self;
208 int slowpath;
e9ce8d39
A
209
210 if (mutex->sig == _PTHREAD_MUTEX_SIG_init)
211 {
212 int res;
213 if (res = pthread_mutex_init(mutex, NULL))
214 return (res);
215 }
216 if (mutex->sig != _PTHREAD_MUTEX_SIG)
217 return (EINVAL); /* Not a mutex variable */
5b2abdfb
A
218
219#if !defined(DEBUG)
220 if (mutex->def) {
221 slowpath = 0;
222 self = (pthread_t)0x12141968;
223 } else
224#endif /* DEBUG */
225 {
226 slowpath = 1;
227 self = pthread_self();
228 }
229
e9ce8d39
A
230 if (!TRY_LOCK(mutex->lock)) {
231 return (EBUSY);
232 }
5b2abdfb
A
233
234 if(slowpath && (mutex->owner == self) && (mutex->type == PTHREAD_MUTEX_RECURSIVE )) {
235 if (mutex->lock_count >= USHRT_MAX) {
236 UNLOCK(mutex->lock);
237 return(EAGAIN);
238 }
239 mutex->lock_count++;
240 UNLOCK(mutex->lock);
241 return(ESUCCESS);
242 }
243
e9ce8d39
A
244 if (mutex->waiters ||
245 ((mutex->owner != (pthread_t)NULL) && (mutex->cond_lock == 0)))
246 {
247 UNLOCK(mutex->lock);
248 return (EBUSY);
5b2abdfb 249 } else {
e9ce8d39 250#if defined(DEBUG)
5b2abdfb 251 _pthread_mutex_add(mutex, self);
e9ce8d39 252#endif
5b2abdfb 253 mutex->owner = (pthread_t)self;
e9ce8d39
A
254 if (mutex->cond_lock) {
255 PTHREAD_MACH_CALL(semaphore_wait(mutex->sem), kern_res);
256 mutex->cond_lock = 0;
257 restore_sem_to_pool(mutex->sem);
258 mutex->sem = MACH_PORT_NULL;
259 }
5b2abdfb
A
260 if (slowpath && (mutex->type == PTHREAD_MUTEX_RECURSIVE))
261 mutex->lock_count = 1;
e9ce8d39
A
262 UNLOCK(mutex->lock);
263 return (ESUCCESS);
264 }
265}
266
267/*
268 * Unlock a mutex.
269 * TODO: Priority inheritance stuff
270 */
271int
272pthread_mutex_unlock(pthread_mutex_t *mutex)
273{
274 kern_return_t kern_res;
275 int waiters;
5b2abdfb
A
276 pthread_t self;
277 int slowpath;
278
e9ce8d39
A
279 if (mutex->sig == _PTHREAD_MUTEX_SIG_init)
280 {
281 int res;
282 if (res = pthread_mutex_init(mutex, NULL))
283 return (res);
284 }
285 if (mutex->sig != _PTHREAD_MUTEX_SIG)
286 return (EINVAL); /* Not a mutex variable */
5b2abdfb
A
287
288#if !defined(DEBUG)
289 if (mutex->def) {
290 slowpath = 0;
291 self = (pthread_t)0x12141968;
292 } else
293#endif /* DEBUG */
294 {
295 slowpath = 1;
296 self = pthread_self();
297 }
298
e9ce8d39 299 LOCK(mutex->lock);
5b2abdfb 300
e9ce8d39 301#if defined(DEBUG)
5b2abdfb
A
302 if (mutex->owner != self)
303#else
304 if (slowpath
305 && ((mutex->type == PTHREAD_MUTEX_ERRORCHECK )
306 || (mutex->type == PTHREAD_MUTEX_RECURSIVE ))
307 && (mutex->owner != self))
308#endif /* DEBUG */
309 {
310 UNLOCK(mutex->lock);
311#if defined(DEBUG)
312 abort();
e9ce8d39 313#endif
5b2abdfb
A
314 return(EPERM);
315 }
316
317 if (slowpath && (mutex->type == PTHREAD_MUTEX_RECURSIVE) && --mutex->lock_count) {
318 UNLOCK(mutex->lock);
319 return (ESUCCESS);
320
321 } else {
e9ce8d39
A
322#if defined(DEBUG)
323 _pthread_mutex_remove(mutex, mutex->owner);
5b2abdfb 324#endif /* DEBUG */
e9ce8d39 325 waiters = mutex->waiters;
5b2abdfb 326 mutex->owner = (pthread_t)NULL;
e9ce8d39
A
327 UNLOCK(mutex->lock);
328 if (waiters)
329 {
330 PTHREAD_MACH_CALL(semaphore_signal(mutex->sem), kern_res);
331 }
332 return (ESUCCESS);
5b2abdfb 333
e9ce8d39
A
334 }
335}
336
337/*
338 * Fetch the priority ceiling value from a mutex variable.
339 * Note: written as a 'helper' function to hide implementation details.
340 */
341int
342pthread_mutex_getprioceiling(const pthread_mutex_t *mutex,
343 int *prioceiling)
344{
345 if (mutex->sig == _PTHREAD_MUTEX_SIG)
346 {
347 *prioceiling = mutex->prioceiling;
348 return (ESUCCESS);
349 } else
350 {
351 return (EINVAL); /* Not an initialized 'attribute' structure */
352 }
353}
354
355/*
356 * Set the priority ceiling for a mutex.
357 * Note: written as a 'helper' function to hide implementation details.
358 */
359int
360pthread_mutex_setprioceiling(pthread_mutex_t *mutex,
361 int prioceiling,
362 int *old_prioceiling)
363{
364 if (mutex->sig == _PTHREAD_MUTEX_SIG)
365 {
366 if ((prioceiling >= -999) ||
367 (prioceiling <= 999))
368 {
369 *old_prioceiling = mutex->prioceiling;
370 mutex->prioceiling = prioceiling;
371 return (ESUCCESS);
372 } else
373 {
374 return (EINVAL); /* Invalid parameter */
375 }
376 } else
377 {
378 return (EINVAL); /* Not an initialized 'attribute' structure */
379 }
380}
381
382/*
383 * Destroy a mutex attribute structure.
384 */
385int
386pthread_mutexattr_destroy(pthread_mutexattr_t *attr)
387{
388 attr->sig = _PTHREAD_NO_SIG; /* Uninitialized */
389 return (ESUCCESS);
390}
391
392/*
393 * Get the priority ceiling value from a mutex attribute structure.
394 * Note: written as a 'helper' function to hide implementation details.
395 */
396int
397pthread_mutexattr_getprioceiling(const pthread_mutexattr_t *attr,
398 int *prioceiling)
399{
400 if (attr->sig == _PTHREAD_MUTEX_ATTR_SIG)
401 {
402 *prioceiling = attr->prioceiling;
403 return (ESUCCESS);
404 } else
405 {
406 return (EINVAL); /* Not an initialized 'attribute' structure */
407 }
408}
409
410/*
411 * Get the mutex 'protocol' value from a mutex attribute structure.
412 * Note: written as a 'helper' function to hide implementation details.
413 */
414int
415pthread_mutexattr_getprotocol(const pthread_mutexattr_t *attr,
416 int *protocol)
417{
418 if (attr->sig == _PTHREAD_MUTEX_ATTR_SIG)
419 {
420 *protocol = attr->protocol;
421 return (ESUCCESS);
422 } else
423 {
424 return (EINVAL); /* Not an initialized 'attribute' structure */
425 }
426}
5b2abdfb
A
427/*
428 * Get the mutex 'type' value from a mutex attribute structure.
429 * Note: written as a 'helper' function to hide implementation details.
430 */
431int
432pthread_mutexattr_gettype(const pthread_mutexattr_t *attr,
433 int *type)
434{
435 if (attr->sig == _PTHREAD_MUTEX_ATTR_SIG)
436 {
437 *type = attr->type;
438 return (ESUCCESS);
439 } else
440 {
441 return (EINVAL); /* Not an initialized 'attribute' structure */
442 }
443}
444
445/*
446 *
447 */
448int
449pthread_mutexattr_getpshared(const pthread_mutexattr_t *attr, int *pshared)
450{
451 if (attr->sig == _PTHREAD_MUTEX_ATTR_SIG)
452 {
453 *pshared = (int)PTHREAD_PROCESS_PRIVATE;
454 return (ESUCCESS);
455 } else
456 {
457 return (EINVAL); /* Not an initialized 'attribute' structure */
458 }
459}
e9ce8d39
A
460
461/*
462 * Initialize a mutex attribute structure to system defaults.
463 */
464int
465pthread_mutexattr_init(pthread_mutexattr_t *attr)
466{
467 attr->prioceiling = _PTHREAD_DEFAULT_PRIOCEILING;
468 attr->protocol = _PTHREAD_DEFAULT_PROTOCOL;
5b2abdfb 469 attr->type = PTHREAD_MUTEX_DEFAULT;
e9ce8d39
A
470 attr->sig = _PTHREAD_MUTEX_ATTR_SIG;
471 return (ESUCCESS);
472}
473
474/*
475 * Set the priority ceiling value in a mutex attribute structure.
476 * Note: written as a 'helper' function to hide implementation details.
477 */
478int
479pthread_mutexattr_setprioceiling(pthread_mutexattr_t *attr,
480 int prioceiling)
481{
482 if (attr->sig == _PTHREAD_MUTEX_ATTR_SIG)
483 {
484 if ((prioceiling >= -999) ||
485 (prioceiling <= 999))
486 {
487 attr->prioceiling = prioceiling;
488 return (ESUCCESS);
489 } else
490 {
491 return (EINVAL); /* Invalid parameter */
492 }
493 } else
494 {
495 return (EINVAL); /* Not an initialized 'attribute' structure */
496 }
497}
498
499/*
500 * Set the mutex 'protocol' value in a mutex attribute structure.
501 * Note: written as a 'helper' function to hide implementation details.
502 */
503int
504pthread_mutexattr_setprotocol(pthread_mutexattr_t *attr,
505 int protocol)
506{
507 if (attr->sig == _PTHREAD_MUTEX_ATTR_SIG)
508 {
509 if ((protocol == PTHREAD_PRIO_NONE) ||
510 (protocol == PTHREAD_PRIO_INHERIT) ||
511 (protocol == PTHREAD_PRIO_PROTECT))
512 {
513 attr->protocol = protocol;
514 return (ESUCCESS);
515 } else
516 {
517 return (EINVAL); /* Invalid parameter */
518 }
519 } else
520 {
521 return (EINVAL); /* Not an initialized 'attribute' structure */
522 }
523}
5b2abdfb
A
524/*
525 * Set the mutex 'type' value in a mutex attribute structure.
526 * Note: written as a 'helper' function to hide implementation details.
527 */
528int
529pthread_mutexattr_settype(pthread_mutexattr_t *attr,
530 int type)
531{
532 if (attr->sig == _PTHREAD_MUTEX_ATTR_SIG)
533 {
534 if ((type == PTHREAD_MUTEX_NORMAL) ||
535 (type == PTHREAD_MUTEX_ERRORCHECK) ||
536 (type == PTHREAD_MUTEX_RECURSIVE) ||
537 (type == PTHREAD_MUTEX_DEFAULT))
538 {
539 attr->type = type;
540 return (ESUCCESS);
541 } else
542 {
543 return (EINVAL); /* Invalid parameter */
544 }
545 } else
546 {
547 return (EINVAL); /* Not an initialized 'attribute' structure */
548 }
549}
550
551/*
552 *
553 */
554int
555pthread_mutexattr_setpshared(pthread_mutexattr_t *attr, int pshared)
556{
557 if (attr->sig == _PTHREAD_MUTEX_ATTR_SIG)
558 {
559 if (pshared == PTHREAD_PROCESS_PRIVATE)
560 {
561 /* attr->pshared = protocol; */
562 return (ESUCCESS);
563 } else
564 {
565 return (EINVAL); /* Invalid parameter */
566 }
567 } else
568 {
569 return (EINVAL); /* Not an initialized 'attribute' structure */
570 }
571}
e9ce8d39
A
572
573int mutex_try_lock(int *x) {
574 return _spin_lock_try((pthread_lock_t *)x);
575}
576
577void mutex_wait_lock(int *x) {
578 for (;;) {
579 if( _spin_lock_try((pthread_lock_t *)x)) {
580 return;
581 }
582 swtch_pri(0);
583 }
584}
585
5b2abdfb
A
586void
587cthread_yield(void)
588{
589 sched_yield();
590}
591
592void
593pthread_yield_np (void)
594{
e9ce8d39
A
595 sched_yield();
596}
597