]> git.saurik.com Git - apple/libc.git/blame - pthreads/pthread_mutex.c
Libc-391.1.21.tar.gz
[apple/libc.git] / pthreads / pthread_mutex.c
CommitLineData
9385eb3d
A
1/*
2 * Copyright (c) 2000-2003 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
9385eb3d
A
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
e9ce8d39
A
23/*
24 * Copyright 1996 1995 by Open Software Foundation, Inc. 1997 1996 1995 1994 1993 1992 1991
25 * All Rights Reserved
26 *
27 * Permission to use, copy, modify, and distribute this software and
28 * its documentation for any purpose and without fee is hereby granted,
29 * provided that the above copyright notice appears in all copies and
30 * that both the copyright notice and this permission notice appear in
31 * supporting documentation.
32 *
33 * OSF DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
34 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
35 * FOR A PARTICULAR PURPOSE.
36 *
37 * IN NO EVENT SHALL OSF BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
38 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
39 * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
40 * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
41 * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
42 *
43 */
44/*
45 * MkLinux
46 */
47
48/*
49 * POSIX Pthread Library
50 * -- Mutex variable support
51 */
52
53#include "pthread_internals.h"
54
55/*
56 * Destroy a mutex variable.
57 */
58int
59pthread_mutex_destroy(pthread_mutex_t *mutex)
60{
9385eb3d
A
61 int res;
62
63 LOCK(mutex->lock);
64 if (mutex->sig == _PTHREAD_MUTEX_SIG)
65 {
66 if (mutex->owner == (pthread_t)NULL &&
67 mutex->busy == (pthread_cond_t *)NULL)
68 {
69 mutex->sig = _PTHREAD_NO_SIG;
70 res = ESUCCESS;
71 }
72 else
73 res = EBUSY;
74 }
75 else
76 res = EINVAL;
77 UNLOCK(mutex->lock);
78 return (res);
79}
80
81/*
82 * Initialize a mutex variable, possibly with additional attributes.
83 */
84static int
85_pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr)
86{
87 if (attr)
88 {
89 if (attr->sig != _PTHREAD_MUTEX_ATTR_SIG)
90 return (EINVAL);
91 mutex->prioceiling = attr->prioceiling;
92 mutex->protocol = attr->protocol;
93 mutex->type = attr->type;
94 } else {
95 mutex->prioceiling = _PTHREAD_DEFAULT_PRIOCEILING;
96 mutex->protocol = _PTHREAD_DEFAULT_PROTOCOL;
97 mutex->type = PTHREAD_MUTEX_DEFAULT;
98 }
99 mutex->lock_count = 0;
100 mutex->owner = (pthread_t)NULL;
101 mutex->next = (pthread_mutex_t *)NULL;
102 mutex->prev = (pthread_mutex_t *)NULL;
103 mutex->busy = (pthread_cond_t *)NULL;
104 mutex->waiters = 0;
105 mutex->sem = SEMAPHORE_NULL;
106 mutex->order = SEMAPHORE_NULL;
107 mutex->sig = _PTHREAD_MUTEX_SIG;
e9ce8d39
A
108 return (ESUCCESS);
109}
110
111/*
112 * Initialize a mutex variable, possibly with additional attributes.
9385eb3d 113 * Public interface - so don't trust the lock - initialize it first.
e9ce8d39
A
114 */
115int
116pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr)
117{
9385eb3d
A
118 LOCK_INIT(mutex->lock);
119 return (_pthread_mutex_init(mutex, attr));
e9ce8d39
A
120}
121
122/*
123 * Manage a list of mutex variables owned by a thread
124 */
125#if defined(DEBUG)
126static void
5b2abdfb 127_pthread_mutex_add(pthread_mutex_t *mutex, pthread_t self)
e9ce8d39
A
128{
129 pthread_mutex_t *m;
9385eb3d
A
130 if (self != (pthread_t)0)
131 {
132 if ((m = self->mutexes) != (pthread_mutex_t *)NULL)
e9ce8d39 133 { /* Add to list */
9385eb3d 134 m->prev = mutex;
e9ce8d39 135 }
9385eb3d
A
136 mutex->next = m;
137 mutex->prev = (pthread_mutex_t *)NULL;
138 self->mutexes = mutex;
e9ce8d39
A
139 }
140}
141
9385eb3d 142__private_extern__ void
e9ce8d39
A
143_pthread_mutex_remove(pthread_mutex_t *mutex, pthread_t self)
144{
145 pthread_mutex_t *n, *prev;
146 if ((n = mutex->next) != (pthread_mutex_t *)NULL)
147 {
148 n->prev = mutex->prev;
149 }
150 if ((prev = mutex->prev) != (pthread_mutex_t *)NULL)
151 {
152 prev->next = mutex->next;
153 } else
154 { /* This is the first in the list */
9385eb3d
A
155 if (self != (pthread_t)0) {
156 self->mutexes = n;
157 }
e9ce8d39 158 }
e9ce8d39
A
159}
160#endif
161
162/*
163 * Lock a mutex.
164 * TODO: Priority inheritance stuff
165 */
166int
167pthread_mutex_lock(pthread_mutex_t *mutex)
168{
9385eb3d
A
169 kern_return_t kern_res;
170 pthread_t self;
171 int sig = mutex->sig;
5b2abdfb 172
9385eb3d
A
173 /* To provide backwards compat for apps using mutex incorrectly */
174 if ((sig != _PTHREAD_MUTEX_SIG) && (sig != _PTHREAD_MUTEX_SIG_init))
175 return(EINVAL);
176 LOCK(mutex->lock);
177 if (mutex->sig != _PTHREAD_MUTEX_SIG)
178 {
179 if (mutex->sig != _PTHREAD_MUTEX_SIG_init)
180 {
181 UNLOCK(mutex->lock);
182 return (EINVAL);
183 }
184 _pthread_mutex_init(mutex, NULL);
185 self = _PTHREAD_MUTEX_OWNER_SELF;
186 }
187 else if (mutex->type != PTHREAD_MUTEX_NORMAL)
5b2abdfb 188 {
5b2abdfb 189 self = pthread_self();
9385eb3d
A
190 if (mutex->owner == self)
191 {
192 int res;
5b2abdfb 193
9385eb3d
A
194 if (mutex->type == PTHREAD_MUTEX_RECURSIVE)
195 {
196 if (mutex->lock_count < USHRT_MAX)
197 {
198 mutex->lock_count++;
199 res = ESUCCESS;
200 } else
201 res = EAGAIN;
202 } else /* PTHREAD_MUTEX_ERRORCHECK */
203 res = EDEADLK;
204 UNLOCK(mutex->lock);
205 return (res);
e9ce8d39 206 }
9385eb3d
A
207 } else
208 self = _PTHREAD_MUTEX_OWNER_SELF;
209
210 if (mutex->owner != (pthread_t)NULL) {
211 if (mutex->waiters || mutex->owner != _PTHREAD_MUTEX_OWNER_SWITCHING)
212 {
213 semaphore_t sem, order;
214
215 if (++mutex->waiters == 1)
216 {
217 mutex->sem = sem = new_sem_from_pool();
218 mutex->order = order = new_sem_from_pool();
219 }
220 else
221 {
222 sem = mutex->sem;
223 order = mutex->order;
224 do {
225 PTHREAD_MACH_CALL(semaphore_wait(order), kern_res);
226 } while (kern_res == KERN_ABORTED);
227 }
228 UNLOCK(mutex->lock);
229
230 PTHREAD_MACH_CALL(semaphore_wait_signal(sem, order), kern_res);
231 while (kern_res == KERN_ABORTED)
232 {
233 PTHREAD_MACH_CALL(semaphore_wait(sem), kern_res);
234 }
235
236 LOCK(mutex->lock);
237 if (--mutex->waiters == 0)
238 {
239 PTHREAD_MACH_CALL(semaphore_wait(order), kern_res);
240 mutex->sem = mutex->order = SEMAPHORE_NULL;
241 restore_sem_to_pool(order);
242 restore_sem_to_pool(sem);
243 }
244 }
245 else if (mutex->owner == _PTHREAD_MUTEX_OWNER_SWITCHING)
246 {
247 semaphore_t sem = mutex->sem;
248 do {
249 PTHREAD_MACH_CALL(semaphore_wait(sem), kern_res);
250 } while (kern_res == KERN_ABORTED);
251 mutex->sem = SEMAPHORE_NULL;
252 restore_sem_to_pool(sem);
e9ce8d39 253 }
9385eb3d
A
254 }
255
256 mutex->lock_count = 1;
257 mutex->owner = self;
258#if defined(DEBUG)
259 _pthread_mutex_add(mutex, self);
e9ce8d39 260#endif
9385eb3d
A
261 UNLOCK(mutex->lock);
262 return (ESUCCESS);
e9ce8d39
A
263}
264
265/*
266 * Attempt to lock a mutex, but don't block if this isn't possible.
267 */
268int
269pthread_mutex_trylock(pthread_mutex_t *mutex)
270{
9385eb3d
A
271 kern_return_t kern_res;
272 pthread_t self;
273
274 LOCK(mutex->lock);
275 if (mutex->sig != _PTHREAD_MUTEX_SIG)
5b2abdfb 276 {
9385eb3d
A
277 if (mutex->sig != _PTHREAD_MUTEX_SIG_init)
278 {
279 UNLOCK(mutex->lock);
280 return (EINVAL);
281 }
282 _pthread_mutex_init(mutex, NULL);
283 self = _PTHREAD_MUTEX_OWNER_SELF;
5b2abdfb 284 }
9385eb3d
A
285 else if (mutex->type != PTHREAD_MUTEX_NORMAL)
286 {
287 self = pthread_self();
288 if (mutex->type == PTHREAD_MUTEX_RECURSIVE)
289 {
290 if (mutex->owner == self)
291 {
292 int res;
5b2abdfb 293
9385eb3d
A
294 if (mutex->lock_count < USHRT_MAX)
295 {
296 mutex->lock_count++;
297 res = ESUCCESS;
298 } else
299 res = EAGAIN;
300 UNLOCK(mutex->lock);
301 return (res);
302 }
303 }
304 } else
305 self = _PTHREAD_MUTEX_OWNER_SELF;
5b2abdfb 306
9385eb3d
A
307 if (mutex->owner != (pthread_t)NULL)
308 {
309 if (mutex->waiters || mutex->owner != _PTHREAD_MUTEX_OWNER_SWITCHING)
310 {
311 UNLOCK(mutex->lock);
312 return (EBUSY);
5b2abdfb 313 }
9385eb3d
A
314 else if (mutex->owner == _PTHREAD_MUTEX_OWNER_SWITCHING)
315 {
316 semaphore_t sem = mutex->sem;
317
318 do {
319 PTHREAD_MACH_CALL(semaphore_wait(sem), kern_res);
320 } while (kern_res == KERN_ABORTED);
321 restore_sem_to_pool(sem);
322 mutex->sem = SEMAPHORE_NULL;
323 }
324 }
325
326 mutex->lock_count = 1;
327 mutex->owner = self;
e9ce8d39 328#if defined(DEBUG)
9385eb3d 329 _pthread_mutex_add(mutex, self);
e9ce8d39 330#endif
9385eb3d
A
331 UNLOCK(mutex->lock);
332 return (ESUCCESS);
e9ce8d39
A
333}
334
335/*
336 * Unlock a mutex.
337 * TODO: Priority inheritance stuff
338 */
339int
340pthread_mutex_unlock(pthread_mutex_t *mutex)
341{
9385eb3d
A
342 kern_return_t kern_res;
343 int waiters;
344 int sig = mutex->sig;
5b2abdfb 345
9385eb3d
A
346 /* To provide backwards compat for apps using mutex incorrectly */
347
348 if ((sig != _PTHREAD_MUTEX_SIG) && (sig != _PTHREAD_MUTEX_SIG_init))
349 return(EINVAL);
350 LOCK(mutex->lock);
351 if (mutex->sig != _PTHREAD_MUTEX_SIG)
5b2abdfb 352 {
9385eb3d
A
353 if (mutex->sig != _PTHREAD_MUTEX_SIG_init)
354 {
355 UNLOCK(mutex->lock);
356 return (EINVAL); /* Not a mutex variable */
357 }
358 _pthread_mutex_init(mutex, NULL);
359 } else
5b2abdfb 360
9385eb3d
A
361#if !defined(DEBUG)
362 if (mutex->type != PTHREAD_MUTEX_NORMAL)
363#endif
5b2abdfb 364 {
9385eb3d
A
365 pthread_t self = pthread_self();
366 if (mutex->owner != self)
367 {
5b2abdfb 368#if defined(DEBUG)
9385eb3d 369 abort();
e9ce8d39 370#endif
9385eb3d
A
371 UNLOCK(mutex->lock);
372 return EPERM;
373 } else if (mutex->type == PTHREAD_MUTEX_RECURSIVE &&
374 --mutex->lock_count)
375 {
376 UNLOCK(mutex->lock);
377 return ESUCCESS;
378 }
379 }
380
381 mutex->lock_count = 0;
e9ce8d39 382#if defined(DEBUG)
9385eb3d 383 _pthread_mutex_remove(mutex, mutex->owner);
5b2abdfb 384#endif /* DEBUG */
9385eb3d
A
385
386 waiters = mutex->waiters;
387 if (waiters)
388 {
389 mutex->owner = _PTHREAD_MUTEX_OWNER_SWITCHING;
e9ce8d39 390 UNLOCK(mutex->lock);
9385eb3d
A
391 PTHREAD_MACH_CALL(semaphore_signal(mutex->sem), kern_res);
392 }
393 else
394 {
395 mutex->owner = (pthread_t)NULL;
396 UNLOCK(mutex->lock);
397 }
398 return (ESUCCESS);
e9ce8d39
A
399}
400
401/*
402 * Fetch the priority ceiling value from a mutex variable.
403 * Note: written as a 'helper' function to hide implementation details.
404 */
405int
406pthread_mutex_getprioceiling(const pthread_mutex_t *mutex,
407 int *prioceiling)
408{
9385eb3d
A
409 int res;
410
411 LOCK(mutex->lock);
e9ce8d39
A
412 if (mutex->sig == _PTHREAD_MUTEX_SIG)
413 {
414 *prioceiling = mutex->prioceiling;
9385eb3d 415 res = ESUCCESS;
e9ce8d39 416 } else
9385eb3d
A
417 res = EINVAL; /* Not an initialized 'attribute' structure */
418 UNLOCK(mutex->lock);
419 return (res);
e9ce8d39
A
420}
421
422/*
423 * Set the priority ceiling for a mutex.
424 * Note: written as a 'helper' function to hide implementation details.
425 */
426int
427pthread_mutex_setprioceiling(pthread_mutex_t *mutex,
428 int prioceiling,
429 int *old_prioceiling)
430{
9385eb3d
A
431 int res;
432
433 LOCK(mutex->lock);
e9ce8d39
A
434 if (mutex->sig == _PTHREAD_MUTEX_SIG)
435 {
436 if ((prioceiling >= -999) ||
437 (prioceiling <= 999))
438 {
439 *old_prioceiling = mutex->prioceiling;
440 mutex->prioceiling = prioceiling;
9385eb3d 441 res = ESUCCESS;
e9ce8d39 442 } else
9385eb3d 443 res = EINVAL; /* Invalid parameter */
e9ce8d39 444 } else
9385eb3d
A
445 res = EINVAL; /* Not an initialized 'attribute' structure */
446 UNLOCK(mutex->lock);
447 return (res);
e9ce8d39
A
448}
449
450/*
451 * Destroy a mutex attribute structure.
452 */
453int
454pthread_mutexattr_destroy(pthread_mutexattr_t *attr)
455{
456 attr->sig = _PTHREAD_NO_SIG; /* Uninitialized */
457 return (ESUCCESS);
458}
459
460/*
461 * Get the priority ceiling value from a mutex attribute structure.
462 * Note: written as a 'helper' function to hide implementation details.
463 */
464int
465pthread_mutexattr_getprioceiling(const pthread_mutexattr_t *attr,
466 int *prioceiling)
467{
468 if (attr->sig == _PTHREAD_MUTEX_ATTR_SIG)
469 {
470 *prioceiling = attr->prioceiling;
471 return (ESUCCESS);
472 } else
473 {
474 return (EINVAL); /* Not an initialized 'attribute' structure */
475 }
476}
477
478/*
479 * Get the mutex 'protocol' value from a mutex attribute structure.
480 * Note: written as a 'helper' function to hide implementation details.
481 */
482int
483pthread_mutexattr_getprotocol(const pthread_mutexattr_t *attr,
484 int *protocol)
485{
486 if (attr->sig == _PTHREAD_MUTEX_ATTR_SIG)
487 {
488 *protocol = attr->protocol;
489 return (ESUCCESS);
490 } else
491 {
492 return (EINVAL); /* Not an initialized 'attribute' structure */
493 }
494}
5b2abdfb
A
495/*
496 * Get the mutex 'type' value from a mutex attribute structure.
497 * Note: written as a 'helper' function to hide implementation details.
498 */
499int
500pthread_mutexattr_gettype(const pthread_mutexattr_t *attr,
501 int *type)
502{
503 if (attr->sig == _PTHREAD_MUTEX_ATTR_SIG)
504 {
505 *type = attr->type;
506 return (ESUCCESS);
507 } else
508 {
509 return (EINVAL); /* Not an initialized 'attribute' structure */
510 }
511}
512
513/*
514 *
515 */
516int
517pthread_mutexattr_getpshared(const pthread_mutexattr_t *attr, int *pshared)
518{
519 if (attr->sig == _PTHREAD_MUTEX_ATTR_SIG)
520 {
521 *pshared = (int)PTHREAD_PROCESS_PRIVATE;
522 return (ESUCCESS);
523 } else
524 {
525 return (EINVAL); /* Not an initialized 'attribute' structure */
526 }
527}
e9ce8d39
A
528
529/*
530 * Initialize a mutex attribute structure to system defaults.
531 */
532int
533pthread_mutexattr_init(pthread_mutexattr_t *attr)
534{
535 attr->prioceiling = _PTHREAD_DEFAULT_PRIOCEILING;
536 attr->protocol = _PTHREAD_DEFAULT_PROTOCOL;
5b2abdfb 537 attr->type = PTHREAD_MUTEX_DEFAULT;
e9ce8d39
A
538 attr->sig = _PTHREAD_MUTEX_ATTR_SIG;
539 return (ESUCCESS);
540}
541
542/*
543 * Set the priority ceiling value in a mutex attribute structure.
544 * Note: written as a 'helper' function to hide implementation details.
545 */
546int
547pthread_mutexattr_setprioceiling(pthread_mutexattr_t *attr,
548 int prioceiling)
549{
550 if (attr->sig == _PTHREAD_MUTEX_ATTR_SIG)
551 {
552 if ((prioceiling >= -999) ||
553 (prioceiling <= 999))
554 {
555 attr->prioceiling = prioceiling;
556 return (ESUCCESS);
557 } else
558 {
559 return (EINVAL); /* Invalid parameter */
560 }
561 } else
562 {
563 return (EINVAL); /* Not an initialized 'attribute' structure */
564 }
565}
566
567/*
568 * Set the mutex 'protocol' value in a mutex attribute structure.
569 * Note: written as a 'helper' function to hide implementation details.
570 */
571int
572pthread_mutexattr_setprotocol(pthread_mutexattr_t *attr,
573 int protocol)
574{
575 if (attr->sig == _PTHREAD_MUTEX_ATTR_SIG)
576 {
577 if ((protocol == PTHREAD_PRIO_NONE) ||
578 (protocol == PTHREAD_PRIO_INHERIT) ||
579 (protocol == PTHREAD_PRIO_PROTECT))
580 {
581 attr->protocol = protocol;
582 return (ESUCCESS);
583 } else
584 {
585 return (EINVAL); /* Invalid parameter */
586 }
587 } else
588 {
589 return (EINVAL); /* Not an initialized 'attribute' structure */
590 }
591}
5b2abdfb
A
592/*
593 * Set the mutex 'type' value in a mutex attribute structure.
594 * Note: written as a 'helper' function to hide implementation details.
595 */
596int
597pthread_mutexattr_settype(pthread_mutexattr_t *attr,
598 int type)
599{
600 if (attr->sig == _PTHREAD_MUTEX_ATTR_SIG)
601 {
602 if ((type == PTHREAD_MUTEX_NORMAL) ||
603 (type == PTHREAD_MUTEX_ERRORCHECK) ||
604 (type == PTHREAD_MUTEX_RECURSIVE) ||
605 (type == PTHREAD_MUTEX_DEFAULT))
606 {
607 attr->type = type;
608 return (ESUCCESS);
609 } else
610 {
611 return (EINVAL); /* Invalid parameter */
612 }
613 } else
614 {
615 return (EINVAL); /* Not an initialized 'attribute' structure */
616 }
617}
618
619/*
620 *
621 */
622int
623pthread_mutexattr_setpshared(pthread_mutexattr_t *attr, int pshared)
624{
625 if (attr->sig == _PTHREAD_MUTEX_ATTR_SIG)
626 {
627 if (pshared == PTHREAD_PROCESS_PRIVATE)
628 {
629 /* attr->pshared = protocol; */
630 return (ESUCCESS);
631 } else
632 {
633 return (EINVAL); /* Invalid parameter */
634 }
635 } else
636 {
637 return (EINVAL); /* Not an initialized 'attribute' structure */
638 }
639}
e9ce8d39
A
640
641int mutex_try_lock(int *x) {
642 return _spin_lock_try((pthread_lock_t *)x);
643}
644
645void mutex_wait_lock(int *x) {
646 for (;;) {
647 if( _spin_lock_try((pthread_lock_t *)x)) {
648 return;
649 }
650 swtch_pri(0);
651 }
652}
653
5b2abdfb
A
654void
655cthread_yield(void)
656{
657 sched_yield();
658}
659
660void
661pthread_yield_np (void)
662{
e9ce8d39
A
663 sched_yield();
664}
665