2 * Copyright (c) 2000-2003, 2007 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
24 * Copyright 1996 1995 by Open Software Foundation, Inc. 1997 1996 1995 1994 1993 1992 1991
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.
33 * OSF DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
34 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
35 * FOR A PARTICULAR PURPOSE.
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.
49 * POSIX Pthread Library
50 * -- Mutex variable support
53 #include "pthread_internals.h"
55 #include "plockstat.h"
57 extern int __unix_conforming
;
59 #ifndef BUILDING_VARIANT /* [ */
61 #define BLOCK_FAIL_PLOCKSTAT 0
62 #define BLOCK_SUCCESS_PLOCKSTAT 1
64 /* This function is never called and exists to provide never-fired dtrace
65 * probes so that user d scripts don't get errors.
67 __private_extern__
void _plockstat_never_fired(void)
69 PLOCKSTAT_MUTEX_SPIN(NULL
);
70 PLOCKSTAT_MUTEX_SPUN(NULL
, 0, 0);
74 * Destroy a mutex variable.
77 pthread_mutex_destroy(pthread_mutex_t
*mutex
)
82 if (mutex
->sig
== _PTHREAD_MUTEX_SIG
)
84 if (mutex
->owner
== (pthread_t
)NULL
&&
85 mutex
->busy
== (pthread_cond_t
*)NULL
)
87 mutex
->sig
= _PTHREAD_NO_SIG
;
92 } else if (mutex
->sig
== _PTHREAD_KERN_MUTEX_SIG
) {
93 int mutexid
= mutex
->_pthread_mutex_kernid
;
95 if( __pthread_mutex_destroy(mutexid
) == -1)
97 mutex
->sig
= _PTHREAD_NO_SIG
;
106 /* 5243343 - temporary hack to detect if we are running the conformance test */
107 extern int PR_5243343_flag
;
108 #endif /* PR_5243343 */
110 * Initialize a mutex variable, possibly with additional attributes.
113 _pthread_mutex_init(pthread_mutex_t
*mutex
, const pthread_mutexattr_t
*attr
)
117 if (attr
->sig
!= _PTHREAD_MUTEX_ATTR_SIG
)
119 mutex
->prioceiling
= attr
->prioceiling
;
120 mutex
->protocol
= attr
->protocol
;
121 mutex
->type
= attr
->type
;
122 mutex
->pshared
= attr
->pshared
;
123 if (attr
->pshared
== PTHREAD_PROCESS_SHARED
) {
124 mutex
->lock_count
= 0;
125 mutex
->owner
= (pthread_t
)NULL
;
126 mutex
->next
= (pthread_mutex_t
*)NULL
;
127 mutex
->prev
= (pthread_mutex_t
*)NULL
;
128 mutex
->busy
= (pthread_cond_t
*)NULL
;
130 mutex
->sem
= SEMAPHORE_NULL
;
131 mutex
->order
= SEMAPHORE_NULL
;
133 if( __pthread_mutex_init(mutex
, attr
) == -1)
135 mutex
->sig
= _PTHREAD_KERN_MUTEX_SIG
;
139 mutex
->prioceiling
= _PTHREAD_DEFAULT_PRIOCEILING
;
140 mutex
->protocol
= _PTHREAD_DEFAULT_PROTOCOL
;
141 mutex
->type
= PTHREAD_MUTEX_DEFAULT
;
142 mutex
->pshared
= _PTHREAD_DEFAULT_PSHARED
;
144 mutex
->lock_count
= 0;
145 mutex
->owner
= (pthread_t
)NULL
;
146 mutex
->next
= (pthread_mutex_t
*)NULL
;
147 mutex
->prev
= (pthread_mutex_t
*)NULL
;
148 mutex
->busy
= (pthread_cond_t
*)NULL
;
150 mutex
->sem
= SEMAPHORE_NULL
;
151 mutex
->order
= SEMAPHORE_NULL
;
152 mutex
->sig
= _PTHREAD_MUTEX_SIG
;
157 * Initialize a mutex variable, possibly with additional attributes.
158 * Public interface - so don't trust the lock - initialize it first.
161 pthread_mutex_init(pthread_mutex_t
*mutex
, const pthread_mutexattr_t
*attr
)
164 /* conformance tests depend on not having this behavior */
165 /* The test for this behavior is optional */
166 if (mutex
->sig
== _PTHREAD_MUTEX_SIG
)
169 LOCK_INIT(mutex
->lock
);
170 return (_pthread_mutex_init(mutex
, attr
));
174 * Manage a list of mutex variables owned by a thread
178 _pthread_mutex_add(pthread_mutex_t
*mutex
, pthread_t self
)
181 if (self
!= (pthread_t
)0)
183 if ((m
= self
->mutexes
) != (pthread_mutex_t
*)NULL
)
188 mutex
->prev
= (pthread_mutex_t
*)NULL
;
189 self
->mutexes
= mutex
;
193 __private_extern__
void
194 _pthread_mutex_remove(pthread_mutex_t
*mutex
, pthread_t self
)
196 pthread_mutex_t
*n
, *prev
;
197 if ((n
= mutex
->next
) != (pthread_mutex_t
*)NULL
)
199 n
->prev
= mutex
->prev
;
201 if ((prev
= mutex
->prev
) != (pthread_mutex_t
*)NULL
)
203 prev
->next
= mutex
->next
;
205 { /* This is the first in the list */
206 if (self
!= (pthread_t
)0) {
215 * TODO: Priority inheritance stuff
218 pthread_mutex_lock(pthread_mutex_t
*mutex
)
220 kern_return_t kern_res
;
222 int sig
= mutex
->sig
;
224 /* To provide backwards compat for apps using mutex incorrectly */
225 if ((sig
!= _PTHREAD_MUTEX_SIG
) && (sig
!= _PTHREAD_MUTEX_SIG_init
) && (sig
!= _PTHREAD_KERN_MUTEX_SIG
)) {
226 PLOCKSTAT_MUTEX_ERROR(mutex
, EINVAL
);
230 if (mutex
->sig
!= _PTHREAD_MUTEX_SIG
)
232 if (mutex
->sig
!= _PTHREAD_MUTEX_SIG_init
)
234 if (mutex
->sig
== _PTHREAD_KERN_MUTEX_SIG
) {
235 int mutexid
= mutex
->_pthread_mutex_kernid
;
238 PLOCKSTAT_MUTEX_BLOCK(mutex
);
239 if( __pthread_mutex_lock(mutexid
) == -1) {
240 PLOCKSTAT_MUTEX_BLOCKED(mutex
, BLOCK_FAIL_PLOCKSTAT
);
241 PLOCKSTAT_MUTEX_ERROR(mutex
, errno
);
245 PLOCKSTAT_MUTEX_BLOCKED(mutex
, BLOCK_SUCCESS_PLOCKSTAT
);
246 PLOCKSTAT_MUTEX_ACQUIRE(mutex
, 0, 0);
250 PLOCKSTAT_MUTEX_ERROR(mutex
, EINVAL
);
254 _pthread_mutex_init(mutex
, NULL
);
255 self
= _PTHREAD_MUTEX_OWNER_SELF
;
257 else if (mutex
->type
!= PTHREAD_MUTEX_NORMAL
)
259 self
= pthread_self();
260 if (mutex
->owner
== self
)
264 if (mutex
->type
== PTHREAD_MUTEX_RECURSIVE
)
266 if (mutex
->lock_count
< USHRT_MAX
)
269 PLOCKSTAT_MUTEX_ACQUIRE(mutex
, 1, 0);
273 PLOCKSTAT_MUTEX_ERROR(mutex
, res
);
275 } else { /* PTHREAD_MUTEX_ERRORCHECK */
277 PLOCKSTAT_MUTEX_ERROR(mutex
, res
);
283 self
= _PTHREAD_MUTEX_OWNER_SELF
;
285 if (mutex
->owner
!= (pthread_t
)NULL
) {
286 if (mutex
->waiters
|| mutex
->owner
!= _PTHREAD_MUTEX_OWNER_SWITCHING
)
288 semaphore_t sem
, order
;
290 if (++mutex
->waiters
== 1)
292 mutex
->sem
= sem
= new_sem_from_pool();
293 mutex
->order
= order
= new_sem_from_pool();
298 order
= mutex
->order
;
300 PTHREAD_MACH_CALL(semaphore_wait(order
), kern_res
);
301 } while (kern_res
== KERN_ABORTED
);
305 PLOCKSTAT_MUTEX_BLOCK(mutex
);
306 PTHREAD_MACH_CALL(semaphore_wait_signal(sem
, order
), kern_res
);
307 while (kern_res
== KERN_ABORTED
)
309 PTHREAD_MACH_CALL(semaphore_wait(sem
), kern_res
);
312 PLOCKSTAT_MUTEX_BLOCKED(mutex
, BLOCK_SUCCESS_PLOCKSTAT
);
315 if (--mutex
->waiters
== 0)
317 PTHREAD_MACH_CALL(semaphore_wait(order
), kern_res
);
318 mutex
->sem
= mutex
->order
= SEMAPHORE_NULL
;
319 restore_sem_to_pool(order
);
320 restore_sem_to_pool(sem
);
323 else if (mutex
->owner
== _PTHREAD_MUTEX_OWNER_SWITCHING
)
325 semaphore_t sem
= mutex
->sem
;
327 PTHREAD_MACH_CALL(semaphore_wait(sem
), kern_res
);
328 } while (kern_res
== KERN_ABORTED
);
329 mutex
->sem
= SEMAPHORE_NULL
;
330 restore_sem_to_pool(sem
);
334 mutex
->lock_count
= 1;
337 _pthread_mutex_add(mutex
, self
);
340 PLOCKSTAT_MUTEX_ACQUIRE(mutex
, 0, 0);
345 * Attempt to lock a mutex, but don't block if this isn't possible.
348 pthread_mutex_trylock(pthread_mutex_t
*mutex
)
350 kern_return_t kern_res
;
354 if (mutex
->sig
!= _PTHREAD_MUTEX_SIG
)
356 if (mutex
->sig
!= _PTHREAD_MUTEX_SIG_init
)
359 if (mutex
->sig
== _PTHREAD_KERN_MUTEX_SIG
) {
360 int mutexid
= mutex
->_pthread_mutex_kernid
;
362 if( __pthread_mutex_trylock(mutexid
) == -1) {
363 PLOCKSTAT_MUTEX_ERROR(mutex
, errno
);
366 PLOCKSTAT_MUTEX_ACQUIRE(mutex
, 0, 0);
369 PLOCKSTAT_MUTEX_ERROR(mutex
, EINVAL
);
374 _pthread_mutex_init(mutex
, NULL
);
375 self
= _PTHREAD_MUTEX_OWNER_SELF
;
377 else if (mutex
->type
!= PTHREAD_MUTEX_NORMAL
)
379 self
= pthread_self();
380 if (mutex
->type
== PTHREAD_MUTEX_RECURSIVE
)
382 if (mutex
->owner
== self
)
386 if (mutex
->lock_count
< USHRT_MAX
)
389 PLOCKSTAT_MUTEX_ACQUIRE(mutex
, 1, 0);
393 PLOCKSTAT_MUTEX_ERROR(mutex
, res
);
400 self
= _PTHREAD_MUTEX_OWNER_SELF
;
402 if (mutex
->owner
!= (pthread_t
)NULL
)
404 if (mutex
->waiters
|| mutex
->owner
!= _PTHREAD_MUTEX_OWNER_SWITCHING
)
406 PLOCKSTAT_MUTEX_ERROR(mutex
, EBUSY
);
410 else if (mutex
->owner
== _PTHREAD_MUTEX_OWNER_SWITCHING
)
412 semaphore_t sem
= mutex
->sem
;
415 PTHREAD_MACH_CALL(semaphore_wait(sem
), kern_res
);
416 } while (kern_res
== KERN_ABORTED
);
417 restore_sem_to_pool(sem
);
418 mutex
->sem
= SEMAPHORE_NULL
;
422 mutex
->lock_count
= 1;
425 _pthread_mutex_add(mutex
, self
);
428 PLOCKSTAT_MUTEX_ACQUIRE(mutex
, 0, 0);
434 * TODO: Priority inheritance stuff
437 pthread_mutex_unlock(pthread_mutex_t
*mutex
)
439 kern_return_t kern_res
;
441 int sig
= mutex
->sig
;
443 /* To provide backwards compat for apps using mutex incorrectly */
445 if ((sig
!= _PTHREAD_MUTEX_SIG
) && (sig
!= _PTHREAD_MUTEX_SIG_init
) && (sig
!= _PTHREAD_KERN_MUTEX_SIG
)) {
446 PLOCKSTAT_MUTEX_ERROR(mutex
, EINVAL
);
450 if (mutex
->sig
!= _PTHREAD_MUTEX_SIG
)
452 if (mutex
->sig
!= _PTHREAD_MUTEX_SIG_init
)
454 if (mutex
->sig
== _PTHREAD_KERN_MUTEX_SIG
) {
455 int mutexid
= mutex
->_pthread_mutex_kernid
;
457 if( __pthread_mutex_unlock(mutexid
) == -1) {
458 PLOCKSTAT_MUTEX_ERROR(mutex
, errno
);
461 PLOCKSTAT_MUTEX_RELEASE(mutex
, 0);
464 PLOCKSTAT_MUTEX_ERROR(mutex
, EINVAL
);
469 _pthread_mutex_init(mutex
, NULL
);
473 if (mutex
->type
!= PTHREAD_MUTEX_NORMAL
)
476 pthread_t self
= pthread_self();
477 if (mutex
->owner
!= self
)
482 PLOCKSTAT_MUTEX_ERROR(mutex
, EPERM
);
485 } else if (mutex
->type
== PTHREAD_MUTEX_RECURSIVE
&&
488 PLOCKSTAT_MUTEX_RELEASE(mutex
, 1);
494 mutex
->lock_count
= 0;
496 _pthread_mutex_remove(mutex
, mutex
->owner
);
499 waiters
= mutex
->waiters
;
502 mutex
->owner
= _PTHREAD_MUTEX_OWNER_SWITCHING
;
503 PLOCKSTAT_MUTEX_RELEASE(mutex
, 0);
505 PTHREAD_MACH_CALL(semaphore_signal(mutex
->sem
), kern_res
);
509 mutex
->owner
= (pthread_t
)NULL
;
510 PLOCKSTAT_MUTEX_RELEASE(mutex
, 0);
517 * Fetch the priority ceiling value from a mutex variable.
518 * Note: written as a 'helper' function to hide implementation details.
521 pthread_mutex_getprioceiling(const pthread_mutex_t
*mutex
,
527 if (mutex
->sig
== _PTHREAD_MUTEX_SIG
)
529 *prioceiling
= mutex
->prioceiling
;
532 res
= EINVAL
; /* Not an initialized 'attribute' structure */
538 * Set the priority ceiling for a mutex.
539 * Note: written as a 'helper' function to hide implementation details.
542 pthread_mutex_setprioceiling(pthread_mutex_t
*mutex
,
544 int *old_prioceiling
)
549 if (mutex
->sig
== _PTHREAD_MUTEX_SIG
)
551 if ((prioceiling
>= -999) ||
552 (prioceiling
<= 999))
554 *old_prioceiling
= mutex
->prioceiling
;
555 mutex
->prioceiling
= prioceiling
;
558 res
= EINVAL
; /* Invalid parameter */
560 res
= EINVAL
; /* Not an initialized 'attribute' structure */
566 * Get the priority ceiling value from a mutex attribute structure.
567 * Note: written as a 'helper' function to hide implementation details.
570 pthread_mutexattr_getprioceiling(const pthread_mutexattr_t
*attr
,
573 if (attr
->sig
== _PTHREAD_MUTEX_ATTR_SIG
)
575 *prioceiling
= attr
->prioceiling
;
579 return (EINVAL
); /* Not an initialized 'attribute' structure */
584 * Get the mutex 'protocol' value from a mutex attribute structure.
585 * Note: written as a 'helper' function to hide implementation details.
588 pthread_mutexattr_getprotocol(const pthread_mutexattr_t
*attr
,
591 if (attr
->sig
== _PTHREAD_MUTEX_ATTR_SIG
)
593 *protocol
= attr
->protocol
;
597 return (EINVAL
); /* Not an initialized 'attribute' structure */
601 * Get the mutex 'type' value from a mutex attribute structure.
602 * Note: written as a 'helper' function to hide implementation details.
605 pthread_mutexattr_gettype(const pthread_mutexattr_t
*attr
,
608 if (attr
->sig
== _PTHREAD_MUTEX_ATTR_SIG
)
614 return (EINVAL
); /* Not an initialized 'attribute' structure */
622 pthread_mutexattr_getpshared(const pthread_mutexattr_t
*attr
, int *pshared
)
624 if (attr
->sig
== _PTHREAD_MUTEX_ATTR_SIG
)
626 *pshared
= (int)attr
->pshared
;
630 return (EINVAL
); /* Not an initialized 'attribute' structure */
635 * Initialize a mutex attribute structure to system defaults.
638 pthread_mutexattr_init(pthread_mutexattr_t
*attr
)
640 attr
->prioceiling
= _PTHREAD_DEFAULT_PRIOCEILING
;
641 attr
->protocol
= _PTHREAD_DEFAULT_PROTOCOL
;
642 attr
->type
= PTHREAD_MUTEX_DEFAULT
;
643 attr
->sig
= _PTHREAD_MUTEX_ATTR_SIG
;
644 attr
->pshared
= _PTHREAD_DEFAULT_PSHARED
;
649 * Set the priority ceiling value in a mutex attribute structure.
650 * Note: written as a 'helper' function to hide implementation details.
653 pthread_mutexattr_setprioceiling(pthread_mutexattr_t
*attr
,
656 if (attr
->sig
== _PTHREAD_MUTEX_ATTR_SIG
)
658 if ((prioceiling
>= -999) ||
659 (prioceiling
<= 999))
661 attr
->prioceiling
= prioceiling
;
665 return (EINVAL
); /* Invalid parameter */
669 return (EINVAL
); /* Not an initialized 'attribute' structure */
674 * Set the mutex 'protocol' value in a mutex attribute structure.
675 * Note: written as a 'helper' function to hide implementation details.
678 pthread_mutexattr_setprotocol(pthread_mutexattr_t
*attr
,
681 if (attr
->sig
== _PTHREAD_MUTEX_ATTR_SIG
)
683 if ((protocol
== PTHREAD_PRIO_NONE
) ||
684 (protocol
== PTHREAD_PRIO_INHERIT
) ||
685 (protocol
== PTHREAD_PRIO_PROTECT
))
687 attr
->protocol
= protocol
;
691 return (EINVAL
); /* Invalid parameter */
695 return (EINVAL
); /* Not an initialized 'attribute' structure */
699 * Set the mutex 'type' value in a mutex attribute structure.
700 * Note: written as a 'helper' function to hide implementation details.
703 pthread_mutexattr_settype(pthread_mutexattr_t
*attr
,
706 if (attr
->sig
== _PTHREAD_MUTEX_ATTR_SIG
)
708 if ((type
== PTHREAD_MUTEX_NORMAL
) ||
709 (type
== PTHREAD_MUTEX_ERRORCHECK
) ||
710 (type
== PTHREAD_MUTEX_RECURSIVE
) ||
711 (type
== PTHREAD_MUTEX_DEFAULT
))
717 return (EINVAL
); /* Invalid parameter */
721 return (EINVAL
); /* Not an initialized 'attribute' structure */
726 int mutex_try_lock(int *x
) {
727 return _spin_lock_try((pthread_lock_t
*)x
);
730 void mutex_wait_lock(int *x
) {
732 if( _spin_lock_try((pthread_lock_t
*)x
)) {
746 pthread_yield_np (void)
753 * Temp: till pshared is fixed correctly
756 pthread_mutexattr_setpshared(pthread_mutexattr_t
*attr
, int pshared
)
759 if (__unix_conforming
== 0)
760 __unix_conforming
= 1;
761 #endif /* __DARWIN_UNIX03 */
763 if (attr
->sig
== _PTHREAD_MUTEX_ATTR_SIG
)
767 if (( pshared
== PTHREAD_PROCESS_PRIVATE
) || (pshared
== PTHREAD_PROCESS_SHARED
&& PR_5243343_flag
))
768 #else /* !PR_5243343 */
769 if (( pshared
== PTHREAD_PROCESS_PRIVATE
) || (pshared
== PTHREAD_PROCESS_SHARED
))
770 #endif /* PR_5243343 */
771 #else /* __DARWIN_UNIX03 */
772 if ( pshared
== PTHREAD_PROCESS_PRIVATE
)
773 #endif /* __DARWIN_UNIX03 */
775 attr
->pshared
= pshared
;
779 return (EINVAL
); /* Invalid parameter */
783 return (EINVAL
); /* Not an initialized 'attribute' structure */
788 #endif /* !BUILDING_VARIANT ] */
791 * Destroy a mutex attribute structure.
794 pthread_mutexattr_destroy(pthread_mutexattr_t
*attr
)
797 if (__unix_conforming
== 0)
798 __unix_conforming
= 1;
799 if (attr
->sig
!= _PTHREAD_MUTEX_ATTR_SIG
)
801 #endif /* __DARWIN_UNIX03 */
803 attr
->sig
= _PTHREAD_NO_SIG
; /* Uninitialized */