2 * Copyright (c) 2000-2003, 2007, 2008 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"
56 #include "plockstat.h"
57 #else /* !PLOCKSTAT */
58 #define PLOCKSTAT_MUTEX_SPIN(x)
59 #define PLOCKSTAT_MUTEX_SPUN(x, y, z)
60 #define PLOCKSTAT_MUTEX_ERROR(x, y)
61 #define PLOCKSTAT_MUTEX_BLOCK(x)
62 #define PLOCKSTAT_MUTEX_BLOCKED(x, y)
63 #define PLOCKSTAT_MUTEX_ACQUIRE(x, y, z)
64 #define PLOCKSTAT_MUTEX_RELEASE(x, y)
65 #endif /* PLOCKSTAT */
67 extern int __unix_conforming
;
69 #ifndef BUILDING_VARIANT /* [ */
71 #define BLOCK_FAIL_PLOCKSTAT 0
72 #define BLOCK_SUCCESS_PLOCKSTAT 1
74 /* This function is never called and exists to provide never-fired dtrace
75 * probes so that user d scripts don't get errors.
77 __private_extern__
void _plockstat_never_fired(void)
79 PLOCKSTAT_MUTEX_SPIN(NULL
);
80 PLOCKSTAT_MUTEX_SPUN(NULL
, 0, 0);
84 * Destroy a mutex variable.
87 pthread_mutex_destroy(pthread_mutex_t
*mutex
)
92 if (mutex
->sig
== _PTHREAD_MUTEX_SIG
)
94 if (mutex
->owner
== (pthread_t
)NULL
&&
95 mutex
->busy
== (pthread_cond_t
*)NULL
)
97 mutex
->sig
= _PTHREAD_NO_SIG
;
102 } else if (mutex
->sig
== _PTHREAD_KERN_MUTEX_SIG
) {
103 int mutexid
= mutex
->_pthread_mutex_kernid
;
105 if( __pthread_mutex_destroy(mutexid
) == -1)
107 mutex
->sig
= _PTHREAD_NO_SIG
;
116 /* 5243343 - temporary hack to detect if we are running the conformance test */
117 extern int PR_5243343_flag
;
118 #endif /* PR_5243343 */
120 * Initialize a mutex variable, possibly with additional attributes.
123 _pthread_mutex_init(pthread_mutex_t
*mutex
, const pthread_mutexattr_t
*attr
)
127 if (attr
->sig
!= _PTHREAD_MUTEX_ATTR_SIG
)
129 mutex
->prioceiling
= attr
->prioceiling
;
130 mutex
->protocol
= attr
->protocol
;
131 mutex
->type
= attr
->type
;
132 mutex
->pshared
= attr
->pshared
;
133 if (attr
->pshared
== PTHREAD_PROCESS_SHARED
) {
134 mutex
->lock_count
= 0;
135 mutex
->owner
= (pthread_t
)NULL
;
136 mutex
->next
= (pthread_mutex_t
*)NULL
;
137 mutex
->prev
= (pthread_mutex_t
*)NULL
;
138 mutex
->busy
= (pthread_cond_t
*)NULL
;
140 mutex
->sem
= SEMAPHORE_NULL
;
141 mutex
->order
= SEMAPHORE_NULL
;
143 if( __pthread_mutex_init(mutex
, attr
) == -1)
145 mutex
->sig
= _PTHREAD_KERN_MUTEX_SIG
;
149 mutex
->prioceiling
= _PTHREAD_DEFAULT_PRIOCEILING
;
150 mutex
->protocol
= _PTHREAD_DEFAULT_PROTOCOL
;
151 mutex
->type
= PTHREAD_MUTEX_DEFAULT
;
152 mutex
->pshared
= _PTHREAD_DEFAULT_PSHARED
;
154 mutex
->lock_count
= 0;
155 mutex
->owner
= (pthread_t
)NULL
;
156 mutex
->next
= (pthread_mutex_t
*)NULL
;
157 mutex
->prev
= (pthread_mutex_t
*)NULL
;
158 mutex
->busy
= (pthread_cond_t
*)NULL
;
160 mutex
->sem
= SEMAPHORE_NULL
;
161 mutex
->order
= SEMAPHORE_NULL
;
162 mutex
->sig
= _PTHREAD_MUTEX_SIG
;
167 * Initialize a mutex variable, possibly with additional attributes.
168 * Public interface - so don't trust the lock - initialize it first.
171 pthread_mutex_init(pthread_mutex_t
*mutex
, const pthread_mutexattr_t
*attr
)
174 /* conformance tests depend on not having this behavior */
175 /* The test for this behavior is optional */
176 if (mutex
->sig
== _PTHREAD_MUTEX_SIG
)
179 LOCK_INIT(mutex
->lock
);
180 return (_pthread_mutex_init(mutex
, attr
));
184 * Manage a list of mutex variables owned by a thread
188 _pthread_mutex_add(pthread_mutex_t
*mutex
, pthread_t self
)
191 if (self
!= (pthread_t
)0)
193 if ((m
= self
->mutexes
) != (pthread_mutex_t
*)NULL
)
198 mutex
->prev
= (pthread_mutex_t
*)NULL
;
199 self
->mutexes
= mutex
;
203 __private_extern__
void
204 _pthread_mutex_remove(pthread_mutex_t
*mutex
, pthread_t self
)
206 pthread_mutex_t
*n
, *prev
;
207 if ((n
= mutex
->next
) != (pthread_mutex_t
*)NULL
)
209 n
->prev
= mutex
->prev
;
211 if ((prev
= mutex
->prev
) != (pthread_mutex_t
*)NULL
)
213 prev
->next
= mutex
->next
;
215 { /* This is the first in the list */
216 if (self
!= (pthread_t
)0) {
225 * TODO: Priority inheritance stuff
228 pthread_mutex_lock(pthread_mutex_t
*mutex
)
230 kern_return_t kern_res
;
232 int sig
= mutex
->sig
;
234 /* To provide backwards compat for apps using mutex incorrectly */
235 if ((sig
!= _PTHREAD_MUTEX_SIG
) && (sig
!= _PTHREAD_MUTEX_SIG_init
) && (sig
!= _PTHREAD_KERN_MUTEX_SIG
)) {
236 PLOCKSTAT_MUTEX_ERROR(mutex
, EINVAL
);
240 if (mutex
->sig
!= _PTHREAD_MUTEX_SIG
)
242 if (mutex
->sig
!= _PTHREAD_MUTEX_SIG_init
)
244 if (mutex
->sig
== _PTHREAD_KERN_MUTEX_SIG
) {
245 int mutexid
= mutex
->_pthread_mutex_kernid
;
248 PLOCKSTAT_MUTEX_BLOCK(mutex
);
249 if( __pthread_mutex_lock(mutexid
) == -1) {
250 PLOCKSTAT_MUTEX_BLOCKED(mutex
, BLOCK_FAIL_PLOCKSTAT
);
251 PLOCKSTAT_MUTEX_ERROR(mutex
, errno
);
255 PLOCKSTAT_MUTEX_BLOCKED(mutex
, BLOCK_SUCCESS_PLOCKSTAT
);
256 PLOCKSTAT_MUTEX_ACQUIRE(mutex
, 0, 0);
260 PLOCKSTAT_MUTEX_ERROR(mutex
, EINVAL
);
264 _pthread_mutex_init(mutex
, NULL
);
265 self
= _PTHREAD_MUTEX_OWNER_SELF
;
267 else if (mutex
->type
!= PTHREAD_MUTEX_NORMAL
)
269 self
= pthread_self();
270 if (mutex
->owner
== self
)
274 if (mutex
->type
== PTHREAD_MUTEX_RECURSIVE
)
276 if (mutex
->lock_count
< USHRT_MAX
)
279 PLOCKSTAT_MUTEX_ACQUIRE(mutex
, 1, 0);
283 PLOCKSTAT_MUTEX_ERROR(mutex
, res
);
285 } else { /* PTHREAD_MUTEX_ERRORCHECK */
287 PLOCKSTAT_MUTEX_ERROR(mutex
, res
);
293 self
= _PTHREAD_MUTEX_OWNER_SELF
;
295 if (mutex
->owner
!= (pthread_t
)NULL
) {
296 if (mutex
->waiters
|| mutex
->owner
!= _PTHREAD_MUTEX_OWNER_SWITCHING
)
298 semaphore_t sem
, order
;
300 if (++mutex
->waiters
== 1)
302 mutex
->sem
= sem
= new_sem_from_pool();
303 mutex
->order
= order
= new_sem_from_pool();
308 order
= mutex
->order
;
310 PTHREAD_MACH_CALL(semaphore_wait(order
), kern_res
);
311 } while (kern_res
== KERN_ABORTED
);
315 PLOCKSTAT_MUTEX_BLOCK(mutex
);
316 PTHREAD_MACH_CALL(semaphore_wait_signal(sem
, order
), kern_res
);
317 while (kern_res
== KERN_ABORTED
)
319 PTHREAD_MACH_CALL(semaphore_wait(sem
), kern_res
);
322 PLOCKSTAT_MUTEX_BLOCKED(mutex
, BLOCK_SUCCESS_PLOCKSTAT
);
325 if (--mutex
->waiters
== 0)
327 PTHREAD_MACH_CALL(semaphore_wait(order
), kern_res
);
328 mutex
->sem
= mutex
->order
= SEMAPHORE_NULL
;
329 restore_sem_to_pool(order
);
330 restore_sem_to_pool(sem
);
333 else if (mutex
->owner
== _PTHREAD_MUTEX_OWNER_SWITCHING
)
335 semaphore_t sem
= mutex
->sem
;
337 PTHREAD_MACH_CALL(semaphore_wait(sem
), kern_res
);
338 } while (kern_res
== KERN_ABORTED
);
339 mutex
->sem
= SEMAPHORE_NULL
;
340 restore_sem_to_pool(sem
);
344 mutex
->lock_count
= 1;
347 _pthread_mutex_add(mutex
, self
);
350 PLOCKSTAT_MUTEX_ACQUIRE(mutex
, 0, 0);
355 * Attempt to lock a mutex, but don't block if this isn't possible.
358 pthread_mutex_trylock(pthread_mutex_t
*mutex
)
360 kern_return_t kern_res
;
364 if (mutex
->sig
!= _PTHREAD_MUTEX_SIG
)
366 if (mutex
->sig
!= _PTHREAD_MUTEX_SIG_init
)
369 if (mutex
->sig
== _PTHREAD_KERN_MUTEX_SIG
) {
370 int mutexid
= mutex
->_pthread_mutex_kernid
;
372 if( __pthread_mutex_trylock(mutexid
) == -1) {
373 PLOCKSTAT_MUTEX_ERROR(mutex
, errno
);
376 PLOCKSTAT_MUTEX_ACQUIRE(mutex
, 0, 0);
379 PLOCKSTAT_MUTEX_ERROR(mutex
, EINVAL
);
384 _pthread_mutex_init(mutex
, NULL
);
385 self
= _PTHREAD_MUTEX_OWNER_SELF
;
387 else if (mutex
->type
!= PTHREAD_MUTEX_NORMAL
)
389 self
= pthread_self();
390 if (mutex
->type
== PTHREAD_MUTEX_RECURSIVE
)
392 if (mutex
->owner
== self
)
396 if (mutex
->lock_count
< USHRT_MAX
)
399 PLOCKSTAT_MUTEX_ACQUIRE(mutex
, 1, 0);
403 PLOCKSTAT_MUTEX_ERROR(mutex
, res
);
410 self
= _PTHREAD_MUTEX_OWNER_SELF
;
412 if (mutex
->owner
!= (pthread_t
)NULL
)
414 if (mutex
->waiters
|| mutex
->owner
!= _PTHREAD_MUTEX_OWNER_SWITCHING
)
416 PLOCKSTAT_MUTEX_ERROR(mutex
, EBUSY
);
420 else if (mutex
->owner
== _PTHREAD_MUTEX_OWNER_SWITCHING
)
422 semaphore_t sem
= mutex
->sem
;
425 PTHREAD_MACH_CALL(semaphore_wait(sem
), kern_res
);
426 } while (kern_res
== KERN_ABORTED
);
427 restore_sem_to_pool(sem
);
428 mutex
->sem
= SEMAPHORE_NULL
;
432 mutex
->lock_count
= 1;
435 _pthread_mutex_add(mutex
, self
);
438 PLOCKSTAT_MUTEX_ACQUIRE(mutex
, 0, 0);
444 * TODO: Priority inheritance stuff
447 pthread_mutex_unlock(pthread_mutex_t
*mutex
)
449 kern_return_t kern_res
;
451 int sig
= mutex
->sig
;
453 /* To provide backwards compat for apps using mutex incorrectly */
455 if ((sig
!= _PTHREAD_MUTEX_SIG
) && (sig
!= _PTHREAD_MUTEX_SIG_init
) && (sig
!= _PTHREAD_KERN_MUTEX_SIG
)) {
456 PLOCKSTAT_MUTEX_ERROR(mutex
, EINVAL
);
460 if (mutex
->sig
!= _PTHREAD_MUTEX_SIG
)
462 if (mutex
->sig
!= _PTHREAD_MUTEX_SIG_init
)
464 if (mutex
->sig
== _PTHREAD_KERN_MUTEX_SIG
) {
465 int mutexid
= mutex
->_pthread_mutex_kernid
;
467 if( __pthread_mutex_unlock(mutexid
) == -1) {
468 PLOCKSTAT_MUTEX_ERROR(mutex
, errno
);
471 PLOCKSTAT_MUTEX_RELEASE(mutex
, 0);
474 PLOCKSTAT_MUTEX_ERROR(mutex
, EINVAL
);
479 _pthread_mutex_init(mutex
, NULL
);
483 if (mutex
->type
!= PTHREAD_MUTEX_NORMAL
)
486 pthread_t self
= pthread_self();
487 if (mutex
->owner
!= self
)
492 PLOCKSTAT_MUTEX_ERROR(mutex
, EPERM
);
495 } else if (mutex
->type
== PTHREAD_MUTEX_RECURSIVE
&&
498 PLOCKSTAT_MUTEX_RELEASE(mutex
, 1);
504 mutex
->lock_count
= 0;
506 _pthread_mutex_remove(mutex
, mutex
->owner
);
509 waiters
= mutex
->waiters
;
512 mutex
->owner
= _PTHREAD_MUTEX_OWNER_SWITCHING
;
513 PLOCKSTAT_MUTEX_RELEASE(mutex
, 0);
515 PTHREAD_MACH_CALL(semaphore_signal(mutex
->sem
), kern_res
);
519 mutex
->owner
= (pthread_t
)NULL
;
520 PLOCKSTAT_MUTEX_RELEASE(mutex
, 0);
527 * Fetch the priority ceiling value from a mutex variable.
528 * Note: written as a 'helper' function to hide implementation details.
531 pthread_mutex_getprioceiling(const pthread_mutex_t
*mutex
,
537 if (mutex
->sig
== _PTHREAD_MUTEX_SIG
)
539 *prioceiling
= mutex
->prioceiling
;
542 res
= EINVAL
; /* Not an initialized 'attribute' structure */
548 * Set the priority ceiling for a mutex.
549 * Note: written as a 'helper' function to hide implementation details.
552 pthread_mutex_setprioceiling(pthread_mutex_t
*mutex
,
554 int *old_prioceiling
)
559 if (mutex
->sig
== _PTHREAD_MUTEX_SIG
)
561 if ((prioceiling
>= -999) ||
562 (prioceiling
<= 999))
564 *old_prioceiling
= mutex
->prioceiling
;
565 mutex
->prioceiling
= prioceiling
;
568 res
= EINVAL
; /* Invalid parameter */
570 res
= EINVAL
; /* Not an initialized 'attribute' structure */
576 * Get the priority ceiling value from a mutex attribute structure.
577 * Note: written as a 'helper' function to hide implementation details.
580 pthread_mutexattr_getprioceiling(const pthread_mutexattr_t
*attr
,
583 if (attr
->sig
== _PTHREAD_MUTEX_ATTR_SIG
)
585 *prioceiling
= attr
->prioceiling
;
589 return (EINVAL
); /* Not an initialized 'attribute' structure */
594 * Get the mutex 'protocol' value from a mutex attribute structure.
595 * Note: written as a 'helper' function to hide implementation details.
598 pthread_mutexattr_getprotocol(const pthread_mutexattr_t
*attr
,
601 if (attr
->sig
== _PTHREAD_MUTEX_ATTR_SIG
)
603 *protocol
= attr
->protocol
;
607 return (EINVAL
); /* Not an initialized 'attribute' structure */
611 * Get the mutex 'type' value from a mutex attribute structure.
612 * Note: written as a 'helper' function to hide implementation details.
615 pthread_mutexattr_gettype(const pthread_mutexattr_t
*attr
,
618 if (attr
->sig
== _PTHREAD_MUTEX_ATTR_SIG
)
624 return (EINVAL
); /* Not an initialized 'attribute' structure */
632 pthread_mutexattr_getpshared(const pthread_mutexattr_t
*attr
, int *pshared
)
634 if (attr
->sig
== _PTHREAD_MUTEX_ATTR_SIG
)
636 *pshared
= (int)attr
->pshared
;
640 return (EINVAL
); /* Not an initialized 'attribute' structure */
645 * Initialize a mutex attribute structure to system defaults.
648 pthread_mutexattr_init(pthread_mutexattr_t
*attr
)
650 attr
->prioceiling
= _PTHREAD_DEFAULT_PRIOCEILING
;
651 attr
->protocol
= _PTHREAD_DEFAULT_PROTOCOL
;
652 attr
->type
= PTHREAD_MUTEX_DEFAULT
;
653 attr
->sig
= _PTHREAD_MUTEX_ATTR_SIG
;
654 attr
->pshared
= _PTHREAD_DEFAULT_PSHARED
;
659 * Set the priority ceiling value in a mutex attribute structure.
660 * Note: written as a 'helper' function to hide implementation details.
663 pthread_mutexattr_setprioceiling(pthread_mutexattr_t
*attr
,
666 if (attr
->sig
== _PTHREAD_MUTEX_ATTR_SIG
)
668 if ((prioceiling
>= -999) ||
669 (prioceiling
<= 999))
671 attr
->prioceiling
= prioceiling
;
675 return (EINVAL
); /* Invalid parameter */
679 return (EINVAL
); /* Not an initialized 'attribute' structure */
684 * Set the mutex 'protocol' value in a mutex attribute structure.
685 * Note: written as a 'helper' function to hide implementation details.
688 pthread_mutexattr_setprotocol(pthread_mutexattr_t
*attr
,
691 if (attr
->sig
== _PTHREAD_MUTEX_ATTR_SIG
)
693 if ((protocol
== PTHREAD_PRIO_NONE
) ||
694 (protocol
== PTHREAD_PRIO_INHERIT
) ||
695 (protocol
== PTHREAD_PRIO_PROTECT
))
697 attr
->protocol
= protocol
;
701 return (EINVAL
); /* Invalid parameter */
705 return (EINVAL
); /* Not an initialized 'attribute' structure */
709 * Set the mutex 'type' value in a mutex attribute structure.
710 * Note: written as a 'helper' function to hide implementation details.
713 pthread_mutexattr_settype(pthread_mutexattr_t
*attr
,
716 if (attr
->sig
== _PTHREAD_MUTEX_ATTR_SIG
)
718 if ((type
== PTHREAD_MUTEX_NORMAL
) ||
719 (type
== PTHREAD_MUTEX_ERRORCHECK
) ||
720 (type
== PTHREAD_MUTEX_RECURSIVE
) ||
721 (type
== PTHREAD_MUTEX_DEFAULT
))
727 return (EINVAL
); /* Invalid parameter */
731 return (EINVAL
); /* Not an initialized 'attribute' structure */
736 int mutex_try_lock(int *x
) {
737 return _spin_lock_try((pthread_lock_t
*)x
);
740 void mutex_wait_lock(int *x
) {
742 if( _spin_lock_try((pthread_lock_t
*)x
)) {
756 pthread_yield_np (void)
763 * Temp: till pshared is fixed correctly
766 pthread_mutexattr_setpshared(pthread_mutexattr_t
*attr
, int pshared
)
769 if (__unix_conforming
== 0)
770 __unix_conforming
= 1;
771 #endif /* __DARWIN_UNIX03 */
773 if (attr
->sig
== _PTHREAD_MUTEX_ATTR_SIG
)
777 if (( pshared
== PTHREAD_PROCESS_PRIVATE
) || (pshared
== PTHREAD_PROCESS_SHARED
&& PR_5243343_flag
))
778 #else /* !PR_5243343 */
779 if (( pshared
== PTHREAD_PROCESS_PRIVATE
) || (pshared
== PTHREAD_PROCESS_SHARED
))
780 #endif /* PR_5243343 */
781 #else /* __DARWIN_UNIX03 */
782 if ( pshared
== PTHREAD_PROCESS_PRIVATE
)
783 #endif /* __DARWIN_UNIX03 */
785 attr
->pshared
= pshared
;
789 return (EINVAL
); /* Invalid parameter */
793 return (EINVAL
); /* Not an initialized 'attribute' structure */
798 #endif /* !BUILDING_VARIANT ] */
801 * Destroy a mutex attribute structure.
804 pthread_mutexattr_destroy(pthread_mutexattr_t
*attr
)
807 if (__unix_conforming
== 0)
808 __unix_conforming
= 1;
809 if (attr
->sig
!= _PTHREAD_MUTEX_ATTR_SIG
)
811 #endif /* __DARWIN_UNIX03 */
813 attr
->sig
= _PTHREAD_NO_SIG
; /* Uninitialized */