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
;
68 extern int __unix_conforming
;
70 #ifndef BUILDING_VARIANT
71 __private_extern__
int usenew_mtximpl
= 1;
72 static void __pthread_mutex_set_signature(npthread_mutex_t
* mutex
);
73 int __mtx_markprepost(npthread_mutex_t
*mutex
, uint32_t oupdateval
, int firstfit
);
74 static int _pthread_mutex_destroy_locked(pthread_mutex_t
*omutex
);
75 #else /* BUILDING_VARIANT */
76 extern int usenew_mtximpl
;
77 #endif /* BUILDING_VARIANT */
82 extern int _commpage_pthread_mutex_lock(uint32_t * lvalp
, int flags
, uint64_t mtid
, uint32_t mask
, uint64_t * tidp
, int *sysret
);
85 #include <machine/cpu_capabilities.h>
87 int _pthread_mutex_init(pthread_mutex_t
*mutex
, const pthread_mutexattr_t
*attr
, uint32_t static_type
);
91 #define MUTEX_GETSEQ_ADDR(mutex, lseqaddr, useqaddr) \
93 if (mutex->mtxopts.options.misalign != 0) { \
94 lseqaddr = &mutex->m_seq[0]; \
95 useqaddr = &mutex->m_seq[1]; \
97 lseqaddr = &mutex->m_seq[1]; \
98 useqaddr = &mutex->m_seq[2]; \
102 #define MUTEX_GETSEQ_ADDR(mutex, lseqaddr, useqaddr) \
104 if (mutex->mtxopts.options.misalign != 0) { \
105 lseqaddr = &mutex->m_seq[1]; \
106 useqaddr = &mutex->m_seq[2]; \
108 lseqaddr = &mutex->m_seq[0]; \
109 useqaddr = &mutex->m_seq[1]; \
112 #endif /* __LP64__ */
114 #define _KSYN_TRACE_ 0
117 /* The Function qualifiers */
118 #define DBG_FUNC_START 1
119 #define DBG_FUNC_END 2
120 #define DBG_FUNC_NONE 0
122 int __kdebug_trace(uint32_t, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t);
124 #define _KSYN_TRACE_UM_LOCK 0x9000060
125 #define _KSYN_TRACE_UM_UNLOCK 0x9000064
126 #define _KSYN_TRACE_UM_MHOLD 0x9000068
127 #define _KSYN_TRACE_UM_MDROP 0x900006c
128 #define _KSYN_TRACE_UM_MUBITS 0x900007c
129 #define _KSYN_TRACE_UM_MARKPP 0x90000a8
131 #endif /* _KSYN_TRACE_ */
133 #ifndef BUILDING_VARIANT /* [ */
135 #define BLOCK_FAIL_PLOCKSTAT 0
136 #define BLOCK_SUCCESS_PLOCKSTAT 1
139 /* 5243343 - temporary hack to detect if we are running the conformance test */
140 extern int PR_5243343_flag
;
141 #endif /* PR_5243343 */
143 /* This function is never called and exists to provide never-fired dtrace
144 * probes so that user d scripts don't get errors.
146 __private_extern__
void _plockstat_never_fired(void)
148 PLOCKSTAT_MUTEX_SPIN(NULL
);
149 PLOCKSTAT_MUTEX_SPUN(NULL
, 0, 0);
154 * Initialize a mutex variable, possibly with additional attributes.
155 * Public interface - so don't trust the lock - initialize it first.
158 pthread_mutex_init(pthread_mutex_t
*mutex
, const pthread_mutexattr_t
*attr
)
161 /* conformance tests depend on not having this behavior */
162 /* The test for this behavior is optional */
163 if (mutex
->sig
== _PTHREAD_MUTEX_SIG
)
166 LOCK_INIT(mutex
->lock
);
167 return (_pthread_mutex_init(mutex
, attr
, 0x7));
171 * Fetch the priority ceiling value from a mutex variable.
172 * Note: written as a 'helper' function to hide implementation details.
175 pthread_mutex_getprioceiling(const pthread_mutex_t
*mutex
,
181 if (mutex
->sig
== _PTHREAD_MUTEX_SIG
)
183 *prioceiling
= mutex
->prioceiling
;
186 res
= EINVAL
; /* Not an initialized 'attribute' structure */
192 * Set the priority ceiling for a mutex.
193 * Note: written as a 'helper' function to hide implementation details.
196 pthread_mutex_setprioceiling(pthread_mutex_t
*mutex
,
198 int *old_prioceiling
)
203 if (mutex
->sig
== _PTHREAD_MUTEX_SIG
)
205 if ((prioceiling
>= -999) ||
206 (prioceiling
<= 999))
208 *old_prioceiling
= mutex
->prioceiling
;
209 mutex
->prioceiling
= prioceiling
;
212 res
= EINVAL
; /* Invalid parameter */
214 res
= EINVAL
; /* Not an initialized 'attribute' structure */
220 * Get the priority ceiling value from a mutex attribute structure.
221 * Note: written as a 'helper' function to hide implementation details.
224 pthread_mutexattr_getprioceiling(const pthread_mutexattr_t
*attr
,
227 if (attr
->sig
== _PTHREAD_MUTEX_ATTR_SIG
)
229 *prioceiling
= attr
->prioceiling
;
233 return (EINVAL
); /* Not an initialized 'attribute' structure */
238 * Get the mutex 'protocol' value from a mutex attribute structure.
239 * Note: written as a 'helper' function to hide implementation details.
242 pthread_mutexattr_getprotocol(const pthread_mutexattr_t
*attr
,
245 if (attr
->sig
== _PTHREAD_MUTEX_ATTR_SIG
)
247 *protocol
= attr
->protocol
;
251 return (EINVAL
); /* Not an initialized 'attribute' structure */
255 * Get the mutex 'type' value from a mutex attribute structure.
256 * Note: written as a 'helper' function to hide implementation details.
259 pthread_mutexattr_gettype(const pthread_mutexattr_t
*attr
,
262 if (attr
->sig
== _PTHREAD_MUTEX_ATTR_SIG
)
268 return (EINVAL
); /* Not an initialized 'attribute' structure */
276 pthread_mutexattr_getpshared(const pthread_mutexattr_t
*attr
, int *pshared
)
278 if (attr
->sig
== _PTHREAD_MUTEX_ATTR_SIG
)
280 *pshared
= (int)attr
->pshared
;
284 return (EINVAL
); /* Not an initialized 'attribute' structure */
289 * Initialize a mutex attribute structure to system defaults.
292 pthread_mutexattr_init(pthread_mutexattr_t
*attr
)
294 attr
->prioceiling
= _PTHREAD_DEFAULT_PRIOCEILING
;
295 attr
->protocol
= _PTHREAD_DEFAULT_PROTOCOL
;
296 attr
->policy
= _PTHREAD_MUTEX_POLICY_FAIRSHARE
;
297 attr
->type
= PTHREAD_MUTEX_DEFAULT
;
298 attr
->sig
= _PTHREAD_MUTEX_ATTR_SIG
;
299 attr
->pshared
= _PTHREAD_DEFAULT_PSHARED
;
304 * Set the priority ceiling value in a mutex attribute structure.
305 * Note: written as a 'helper' function to hide implementation details.
308 pthread_mutexattr_setprioceiling(pthread_mutexattr_t
*attr
,
311 if (attr
->sig
== _PTHREAD_MUTEX_ATTR_SIG
)
313 if ((prioceiling
>= -999) ||
314 (prioceiling
<= 999))
316 attr
->prioceiling
= prioceiling
;
320 return (EINVAL
); /* Invalid parameter */
324 return (EINVAL
); /* Not an initialized 'attribute' structure */
329 * Set the mutex 'protocol' value in a mutex attribute structure.
330 * Note: written as a 'helper' function to hide implementation details.
333 pthread_mutexattr_setprotocol(pthread_mutexattr_t
*attr
,
336 if (attr
->sig
== _PTHREAD_MUTEX_ATTR_SIG
)
338 if ((protocol
== PTHREAD_PRIO_NONE
) ||
339 (protocol
== PTHREAD_PRIO_INHERIT
) ||
340 (protocol
== PTHREAD_PRIO_PROTECT
))
342 attr
->protocol
= protocol
;
346 return (EINVAL
); /* Invalid parameter */
350 return (EINVAL
); /* Not an initialized 'attribute' structure */
355 pthread_mutexattr_setpolicy_np(pthread_mutexattr_t
*attr
,
358 if (attr
->sig
== _PTHREAD_MUTEX_ATTR_SIG
)
361 (policy
== _PTHREAD_MUTEX_POLICY_FAIRSHARE
) ||
362 (policy
== _PTHREAD_MUTEX_POLICY_FIRSTFIT
)
365 (policy
== _PTHREAD_MUTEX_POLICY_REALTIME
) ||
366 (policy
== _PTHREAD_MUTEX_POLICY_ADAPTIVE
) ||
367 (policy
== _PTHREAD_MUTEX_POLICY_PRIPROTECT
) ||
368 (policy
== _PTHREAD_MUTEX_POLICY_PRIINHERIT
)
372 attr
->policy
= policy
;
376 return (EINVAL
); /* Invalid parameter */
380 return (EINVAL
); /* Not an initialized 'attribute' structure */
385 * Set the mutex 'type' value in a mutex attribute structure.
386 * Note: written as a 'helper' function to hide implementation details.
389 pthread_mutexattr_settype(pthread_mutexattr_t
*attr
,
392 if (attr
->sig
== _PTHREAD_MUTEX_ATTR_SIG
)
394 if ((type
== PTHREAD_MUTEX_NORMAL
) ||
395 (type
== PTHREAD_MUTEX_ERRORCHECK
) ||
396 (type
== PTHREAD_MUTEX_RECURSIVE
) ||
397 (type
== PTHREAD_MUTEX_DEFAULT
))
403 return (EINVAL
); /* Invalid parameter */
407 return (EINVAL
); /* Not an initialized 'attribute' structure */
412 int mutex_try_lock(int *x
) {
413 return _spin_lock_try((pthread_lock_t
*)x
);
416 void mutex_wait_lock(int *x
) {
418 if( _spin_lock_try((pthread_lock_t
*)x
)) {
432 pthread_yield_np (void)
439 * Temp: till pshared is fixed correctly
442 pthread_mutexattr_setpshared(pthread_mutexattr_t
*attr
, int pshared
)
445 if (__unix_conforming
== 0)
446 __unix_conforming
= 1;
447 #endif /* __DARWIN_UNIX03 */
449 if (attr
->sig
== _PTHREAD_MUTEX_ATTR_SIG
)
452 if (( pshared
== PTHREAD_PROCESS_PRIVATE
) || (pshared
== PTHREAD_PROCESS_SHARED
))
453 #else /* __DARWIN_UNIX03 */
454 if ( pshared
== PTHREAD_PROCESS_PRIVATE
)
455 #endif /* __DARWIN_UNIX03 */
457 attr
->pshared
= pshared
;
460 return (EINVAL
); /* Invalid parameter */
464 return (EINVAL
); /* Not an initialized 'attribute' structure */
469 * Drop the mutex unlock references(from cond wait or mutex_unlock().
472 __private_extern__
int
473 __mtx_droplock(npthread_mutex_t
* mutex
, uint32_t diffgen
, uint32_t * flagsp
, uint32_t ** pmtxp
, uint32_t * mgenp
, uint32_t * ugenp
)
476 uint64_t selfid
, resettid
;
477 int firstfit
= (mutex
->mtxopts
.options
.policy
== _PTHREAD_MUTEX_POLICY_FIRSTFIT
);
478 uint32_t lgenval
, ugenval
, nlval
, ulval
, morewaiters
=0, flags
;
479 volatile uint32_t * lseqaddr
, *useqaddr
;
480 uint64_t oldval64
, newval64
;
481 int numwaiters
=0, clearprepost
= 0;
484 (void)__kdebug_trace(_KSYN_TRACE_UM_MDROP
| DBG_FUNC_START
, (uint32_t)mutex
, diffgen
, 0, 0, 0);
486 MUTEX_GETSEQ_ADDR(mutex
, lseqaddr
, useqaddr
);
489 flags
= mutex
->mtxopts
.value
;
490 flags
&= ~_PTHREAD_MTX_OPT_NOTIFY
; /* no notification by default */
493 if (mutex
->mtxopts
.options
.type
!= PTHREAD_MUTEX_NORMAL
)
495 self
= pthread_self();
496 (void) pthread_threadid_np(self
, &selfid
);
498 if (mutex
->m_tid
!= selfid
)
500 //LIBC_ABORT("dropping recur or error mutex not owned by the thread\n");
501 PLOCKSTAT_MUTEX_ERROR((pthread_mutex_t
*)mutex
, EPERM
);
503 } else if (mutex
->mtxopts
.options
.type
== PTHREAD_MUTEX_RECURSIVE
&&
504 --mutex
->mtxopts
.options
.lock_count
)
506 PLOCKSTAT_MUTEX_RELEASE((pthread_mutex_t
*)mutex
, 1);
516 numwaiters
= diff_genseq((lgenval
& PTHRW_COUNT_MASK
),(ugenval
& PTHRW_COUNT_MASK
)); /* pendig waiters */
518 if (numwaiters
== 0) {
519 /* spurious unlocks, do not touch tid */
520 oldval64
= (((uint64_t)ugenval
) << 32);
522 if ((firstfit
!= 0) && ((lgenval
& PTH_RWL_PBIT
) != 0)) {
524 lgenval
&= ~PTH_RWL_PBIT
;
525 newval64
= (((uint64_t)ugenval
) << 32);
529 if (OSAtomicCompareAndSwap64(oldval64
, newval64
, (volatile int64_t *)lseqaddr
) != TRUE
)
531 /* validated L & U to be same, this is spurious unlock */
532 flags
&= ~_PTHREAD_MTX_OPT_NOTIFY
;
533 if (clearprepost
== 1)
534 __psynch_cvclrprepost(mutex
, lgenval
, ugenval
, 0, 0, lgenval
, (flags
| _PTHREAD_MTX_OPT_MUTEX
));
539 if (numwaiters
< diffgen
) {
541 (void)__kdebug_trace(_KSYN_TRACE_UM_MDROP
| DBG_FUNC_NONE
, (uint32_t)mutex
, numwaiters
, lgenval
, ugenval
, 0);
543 /* cannot drop more than existing number of waiters */
544 diffgen
= numwaiters
;
547 oldval64
= (((uint64_t)ugenval
) << 32);
549 ulval
= ugenval
+ diffgen
;
552 if ((lgenval
& PTHRW_COUNT_MASK
) == (ulval
& PTHRW_COUNT_MASK
)) {
553 /* do not reset Ibit, just K&E */
554 nlval
&= ~(PTH_RWL_KBIT
| PTH_RWL_EBIT
);
555 flags
&= ~_PTHREAD_MTX_OPT_NOTIFY
;
556 if ((firstfit
!= 0) && ((lgenval
& PTH_RWL_PBIT
) != 0)) {
558 nlval
&= ~PTH_RWL_PBIT
;
561 /* need to signal others waiting for mutex */
563 flags
|= _PTHREAD_MTX_OPT_NOTIFY
;
566 if (((nlval
& PTH_RWL_EBIT
) != 0) && (firstfit
!= 0)) {
567 nlval
&= ~PTH_RWL_EBIT
; /* reset Ebit so another can acquire meanwhile */
570 newval64
= (((uint64_t)ulval
) << 32);
573 resettid
= mutex
->m_tid
;
575 if ((lgenval
& PTHRW_COUNT_MASK
) == (ulval
& PTHRW_COUNT_MASK
))
577 else if (firstfit
== 0)
578 mutex
->m_tid
= PTHREAD_MTX_TID_SWITCHING
;
580 if (OSAtomicCompareAndSwap64(oldval64
, newval64
, (volatile int64_t *)lseqaddr
) != TRUE
) {
581 mutex
->m_tid
= resettid
;
587 (void)__kdebug_trace(_KSYN_TRACE_UM_MDROP
| DBG_FUNC_NONE
, (uint32_t)mutex
, 2, lgenval
, ugenval
, 0);
588 (void)__kdebug_trace(_KSYN_TRACE_UM_MDROP
| DBG_FUNC_NONE
, (uint32_t)mutex
, 2, nlval
, ulval
, 0);
591 if (clearprepost
!= 0) {
592 __psynch_cvclrprepost(mutex
, nlval
, ulval
, 0, 0, nlval
, (flags
| _PTHREAD_MTX_OPT_MUTEX
));
604 *pmtxp
= (uint32_t *)mutex
;
612 (void)__kdebug_trace(_KSYN_TRACE_UM_MDROP
| DBG_FUNC_END
, (uint32_t)mutex
, flags
, 0, 0, 0);
618 __mtx_updatebits(npthread_mutex_t
*mutex
, uint32_t oupdateval
, int firstfit
, int fromcond
, uint64_t selfid
)
620 uint32_t updateval
= oupdateval
;
622 pthread_mutex_t
* omutex
= (pthread_mutex_t
*)mutex
;
625 uint32_t lgenval
, ugenval
, nval
, uval
, bits
;
626 volatile uint32_t * lseqaddr
, *useqaddr
;
627 uint64_t oldval64
, newval64
;
629 MUTEX_GETSEQ_ADDR(mutex
, lseqaddr
, useqaddr
);
632 (void)__kdebug_trace(_KSYN_TRACE_UM_MUBITS
| DBG_FUNC_START
, (uint32_t)mutex
, oupdateval
, firstfit
, fromcond
, 0);
638 bits
= updateval
& PTHRW_BIT_MASK
;
641 (void)__kdebug_trace(_KSYN_TRACE_UM_MUBITS
| DBG_FUNC_NONE
, (uint32_t)mutex
, 1, lgenval
, ugenval
, 0);
645 if ((updateval
& PTH_RWL_MTX_WAIT
) != 0) {
646 lgenval
= (updateval
& PTHRW_COUNT_MASK
) | (lgenval
& PTHRW_BIT_MASK
);
648 /* if from mutex_lock(), it will handle the rewind */
651 /* go block in the kernel with same lgenval as returned */
654 /* firsfit might not have EBIT */
656 if ((lgenval
& PTH_RWL_EBIT
) != 0)
660 } else if ((lgenval
& (PTH_RWL_KBIT
|PTH_RWL_EBIT
)) == (PTH_RWL_KBIT
|PTH_RWL_EBIT
)) {
661 /* fairshare mutex and the bits are already set, just update tid */
666 /* either firstfist or no E bit set */
667 /* update the bits */
668 oldval64
= (((uint64_t)ugenval
) << 32);
671 nval
= lgenval
| (PTH_RWL_KBIT
|PTH_RWL_EBIT
);
672 newval64
= (((uint64_t)uval
) << 32);
675 /* set s and b bit */
676 if (OSAtomicCompareAndSwap64(oldval64
, newval64
, (volatile int64_t *)lseqaddr
) == TRUE
) {
678 (void)__kdebug_trace(_KSYN_TRACE_UM_MUBITS
| DBG_FUNC_NONE
, (uint32_t)mutex
, 2, nval
, uval
, 0);
680 if ((firstfit
!= 0) && (isebit
!= 0))
692 (void)__kdebug_trace(_KSYN_TRACE_UM_MUBITS
| DBG_FUNC_NONE
, (uint32_t)mutex
, 4, nval
, uval
, 0);
696 /* succesful bits updation */
697 mutex
->m_tid
= selfid
;
699 (void)__kdebug_trace(_KSYN_TRACE_UM_MUBITS
| DBG_FUNC_END
, (uint32_t)mutex
, 0, 0, 0, 0);
704 /* firstfit failure */
707 if ((lgenval
& PTH_RWL_EBIT
) == 0)
713 /* called from condition variable code block again */
715 #if USE_COMPAGE /* [ */
716 updateval
= __psynch_mutexwait((pthread_mutex_t
*)lseqaddr
, lgenval
| PTH_RWL_RETRYBIT
, ugenval
, mutex
->m_tid
,
717 mutex
->mtxopts
.value
);
718 #else /* USECOMPAGE ][ */
719 updateval
= __psynch_mutexwait(omutex
, lgenval
| PTH_RWL_RETRYBIT
, ugenval
, mutex
->m_tid
,
720 mutex
->mtxopts
.value
);
721 #endif /* USE_COMPAGE ] */
722 if (updateval
== (uint32_t)-1) {
726 /* now update the bits */
735 __mtx_markprepost(npthread_mutex_t
*mutex
, uint32_t oupdateval
, int firstfit
)
737 uint32_t updateval
= oupdateval
;
738 int clearprepost
= 0;
739 uint32_t lgenval
, ugenval
,flags
;
740 volatile uint32_t * lseqaddr
, *useqaddr
;
741 uint64_t oldval64
, newval64
;
743 MUTEX_GETSEQ_ADDR(mutex
, lseqaddr
, useqaddr
);
746 (void)__kdebug_trace(_KSYN_TRACE_UM_MARKPP
| DBG_FUNC_START
, (uint32_t)mutex
, oupdateval
, firstfit
, 0, 0);
753 if ((firstfit
!= 0) && ((updateval
& PTH_RWL_PBIT
) != 0)) {
754 flags
= mutex
->mtxopts
.value
;
760 (void)__kdebug_trace(_KSYN_TRACE_UM_MARKPP
| DBG_FUNC_NONE
, (uint32_t)mutex
, 1, lgenval
, ugenval
, 0);
762 /* update the bits */
763 oldval64
= (((uint64_t)ugenval
) << 32);
766 if ((lgenval
& PTHRW_COUNT_MASK
) == (ugenval
& PTHRW_COUNT_MASK
)) {
768 lgenval
&= ~PTH_RWL_PBIT
;
771 lgenval
|= PTH_RWL_PBIT
;
773 newval64
= (((uint64_t)ugenval
) << 32);
776 if (OSAtomicCompareAndSwap64(oldval64
, newval64
, (volatile int64_t *)lseqaddr
) == TRUE
) {
778 (void)__kdebug_trace(_KSYN_TRACE_UM_MARKPP
| DBG_FUNC_NONE
, (uint32_t)mutex
, 2, lgenval
, ugenval
, 0);
781 if (clearprepost
!= 0)
782 __psynch_cvclrprepost(mutex
, lgenval
, ugenval
, 0, 0, lgenval
, (flags
| _PTHREAD_MTX_OPT_MUTEX
));
789 (void)__kdebug_trace(_KSYN_TRACE_UM_MARKPP
| DBG_FUNC_END
, (uint32_t)mutex
, 0, 0, 0, 0);
796 * For the new style mutex, interlocks are not held all the time.
797 * We needed the signature to be set in the end. And we need
798 * to protect against the code getting reorganized by compiler.
801 __pthread_mutex_set_signature(npthread_mutex_t
* mutex
)
803 mutex
->sig
= _PTHREAD_MUTEX_SIG
;
807 pthread_mutex_lock(pthread_mutex_t
*omutex
)
811 npthread_mutex_t
* mutex
= (npthread_mutex_t
*)omutex
;
812 int sig
= mutex
->sig
;
813 #if NEVERINCOMPAGE || !USE_COMPAGE
814 //uint32_t oldval, newval;
817 int gotlock
= 0, firstfit
= 0;
818 uint32_t updateval
, lgenval
, ugenval
, nval
, uval
;
819 volatile uint32_t * lseqaddr
, *useqaddr
;
820 uint64_t oldval64
, newval64
;
828 /* To provide backwards compat for apps using mutex incorrectly */
829 if ((sig
!= _PTHREAD_MUTEX_SIG
) && ((sig
& _PTHREAD_MUTEX_SIG_init_MASK
) != _PTHREAD_MUTEX_SIG_CMP
)) {
830 PLOCKSTAT_MUTEX_ERROR(omutex
, EINVAL
);
833 if (mutex
->sig
!= _PTHREAD_MUTEX_SIG
) {
835 if ((mutex
->sig
& _PTHREAD_MUTEX_SIG_init_MASK
) == _PTHREAD_MUTEX_SIG_CMP
) {
836 /* static initializer, init the mutex */
837 if(retval
= _pthread_mutex_init(omutex
, NULL
, (mutex
->sig
& 0xf)) != 0){
839 PLOCKSTAT_MUTEX_ERROR(omutex
, retval
);
842 } else if (mutex
->sig
!= _PTHREAD_MUTEX_SIG
) {
844 PLOCKSTAT_MUTEX_ERROR(omutex
, EINVAL
);
851 (void)__kdebug_trace(_KSYN_TRACE_UM_LOCK
| DBG_FUNC_START
, (uint32_t)mutex
, 0, 0, 0, 0);
853 MUTEX_GETSEQ_ADDR(mutex
, lseqaddr
, useqaddr
);
855 self
= pthread_self();
856 (void) pthread_threadid_np(self
, &selfid
);
858 if (mutex
->mtxopts
.options
.type
!= PTHREAD_MUTEX_NORMAL
) {
859 if (mutex
->m_tid
== selfid
) {
860 if (mutex
->mtxopts
.options
.type
== PTHREAD_MUTEX_RECURSIVE
)
862 if (mutex
->mtxopts
.options
.lock_count
< USHRT_MAX
)
864 mutex
->mtxopts
.options
.lock_count
++;
865 PLOCKSTAT_MUTEX_ACQUIRE(omutex
, 1, 0);
869 PLOCKSTAT_MUTEX_ERROR(omutex
, retval
);
871 } else { /* PTHREAD_MUTEX_ERRORCHECK */
873 PLOCKSTAT_MUTEX_ERROR(omutex
, retval
);
880 (void)__kdebug_trace(_KSYN_TRACE_UM_LOCK
| DBG_FUNC_NONE
, (uint32_t)mutex
, 1, 0, 0, 0);
883 #if USE_COMPAGE /* [ */
887 retval
= _commpage_pthread_mutex_lock(lseqaddr
, mutex
->mtxopts
.value
, selfid
, mask
, &mutex
->m_tid
, &sysret
);
890 } else if (retval
== 1) {
893 /* returns 0 on succesful update */
894 if (__mtx_updatebits( mutex
, updateval
, firstfit
, 0, selfid
) == 1) {
895 /* could not acquire, may be locked in ffit case */
897 LIBC_ABORT("comapge implementatin looping in libc \n");
903 else if (retval
== 3) {
904 cthread_set_errno_self(sysret
);
907 newval
= oldval
+ PTHRW_INC
;
909 /* to block in the kerenl again */
913 LIBC_ABORT("comapge implementation bombed \n");
917 #else /* USECOMPAGE ][ */
923 (void)__kdebug_trace(_KSYN_TRACE_UM_LOCK
| DBG_FUNC_NONE
, (uint32_t)mutex
, 2, lgenval
, ugenval
, 0);
924 #endif /* _KSYN_TRACE_ */
926 if((lgenval
& PTH_RWL_EBIT
) == 0) {
932 oldval64
= (((uint64_t)ugenval
) << 32);
935 nval
= (lgenval
+ PTHRW_INC
) | (PTH_RWL_EBIT
|PTH_RWL_KBIT
);
936 newval64
= (((uint64_t)uval
) << 32);
939 if (OSAtomicCompareAndSwap64(oldval64
, newval64
, (volatile int64_t *)lseqaddr
) == TRUE
) {
941 (void)__kdebug_trace(_KSYN_TRACE_UM_LOCK
| DBG_FUNC_NONE
, (uint32_t)mutex
, 2, nval
, uval
, 0);
944 mutex
->m_tid
= selfid
;
954 (void)__kdebug_trace(_KSYN_TRACE_UM_LOCK
| DBG_FUNC_NONE
, (uint32_t)mutex
, 3, nval
, uval
, 0);
956 firstfit
= (mutex
->mtxopts
.options
.policy
== _PTHREAD_MUTEX_POLICY_FIRSTFIT
);
958 updateval
= __psynch_mutexwait(omutex
, nval
| retrybit
, uval
, mutex
->m_tid
,
959 mutex
->mtxopts
.value
);
962 (void)__kdebug_trace(_KSYN_TRACE_UM_LOCK
| DBG_FUNC_NONE
, (uint32_t)mutex
, 4, updateval
, 0, 0);
964 if (updateval
== (uint32_t)-1) {
968 /* returns 0 on succesful update; in firstfit it may fail with 1 */
969 if (__mtx_updatebits( mutex
, PTHRW_INC
| (PTH_RWL_KBIT
| PTH_RWL_EBIT
), firstfit
, 0, selfid
) == 1) {
970 /* could not acquire, may be locked in ffit case */
971 retrybit
= PTH_RWL_RETRYBIT
;
973 LIBC_ABORT("comapge implementatin looping in libc \n");
979 #endif /* USE_COMPAGE ] */
982 if (mutex
->mtxopts
.options
.type
== PTHREAD_MUTEX_RECURSIVE
)
983 mutex
->mtxopts
.options
.lock_count
= 1;
986 (void)__kdebug_trace(_KSYN_TRACE_UM_LOCK
| DBG_FUNC_END
, (uint32_t)mutex
, 0, 0, 0, 0);
992 * Attempt to lock a mutex, but don't block if this isn't possible.
995 pthread_mutex_trylock(pthread_mutex_t
*omutex
)
997 npthread_mutex_t
* mutex
= (npthread_mutex_t
*)omutex
;
998 int sig
= mutex
->sig
;
1003 uint32_t lgenval
, ugenval
, nval
, uval
;
1004 volatile uint32_t * lseqaddr
, *useqaddr
;
1005 uint64_t oldval64
, newval64
;
1007 /* To provide backwards compat for apps using mutex incorrectly */
1008 if ((sig
!= _PTHREAD_MUTEX_SIG
) && ((sig
& _PTHREAD_MUTEX_SIG_init_MASK
) != _PTHREAD_MUTEX_SIG_CMP
)) {
1009 PLOCKSTAT_MUTEX_ERROR(omutex
, EINVAL
);
1013 if ((mutex
->sig
& _PTHREAD_MUTEX_SIG_init_MASK
) == _PTHREAD_MUTEX_SIG_CMP
) {
1015 if (mutex
->sig
== _PTHREAD_MUTEX_SIG_init
) {
1016 /* static initializer, init the mutex */
1017 if((error
= _pthread_mutex_init(omutex
, NULL
, (mutex
->sig
& 0xf))) != 0){
1018 UNLOCK(mutex
->lock
);
1019 PLOCKSTAT_MUTEX_ERROR(omutex
, error
);
1022 } else if (mutex
->sig
!= _PTHREAD_MUTEX_SIG
) {
1023 UNLOCK(mutex
->lock
);
1024 PLOCKSTAT_MUTEX_ERROR(omutex
, EINVAL
);
1027 UNLOCK(mutex
->lock
);
1030 MUTEX_GETSEQ_ADDR(mutex
, lseqaddr
, useqaddr
);
1032 self
= pthread_self();
1033 (void) pthread_threadid_np(self
, &selfid
);
1035 if (mutex
->mtxopts
.options
.type
!= PTHREAD_MUTEX_NORMAL
) {
1036 if (mutex
->m_tid
== selfid
) {
1037 if (mutex
->mtxopts
.options
.type
== PTHREAD_MUTEX_RECURSIVE
)
1039 if (mutex
->mtxopts
.options
.lock_count
< USHRT_MAX
)
1041 mutex
->mtxopts
.options
.lock_count
++;
1042 PLOCKSTAT_MUTEX_ACQUIRE(omutex
, 1, 0);
1046 PLOCKSTAT_MUTEX_ERROR(omutex
, error
);
1048 } else { /* PTHREAD_MUTEX_ERRORCHECK */
1050 PLOCKSTAT_MUTEX_ERROR(omutex
, error
);
1056 lgenval
= *lseqaddr
;
1057 ugenval
= *useqaddr
;
1060 (void)__kdebug_trace(_KSYN_TRACE_UM_LOCK
| DBG_FUNC_NONE
, (uint32_t)mutex
, 2, lgenval
, ugenval
, 0);
1061 #endif /* _KSYN_TRACE_ */
1064 oldval64
= (((uint64_t)ugenval
) << 32);
1065 oldval64
|= lgenval
;
1068 /* if we can acquire go ahead otherwise ensure it is still busy */
1069 if((lgenval
& PTH_RWL_EBIT
) == 0) {
1071 nval
= (lgenval
+ PTHRW_INC
) | (PTH_RWL_EBIT
|PTH_RWL_KBIT
);
1073 nval
= (lgenval
| PTH_RWL_TRYLKBIT
);
1077 newval64
= (((uint64_t)uval
) << 32);
1080 /* set s and b bit */
1081 if (OSAtomicCompareAndSwap64(oldval64
, newval64
, (volatile int64_t *)lseqaddr
) == TRUE
) {
1083 (void)__kdebug_trace(_KSYN_TRACE_UM_LOCK
| DBG_FUNC_NONE
, (uint32_t)mutex
, 2, nval
, uval
, 0);
1086 mutex
->m_tid
= selfid
;
1087 if (mutex
->mtxopts
.options
.type
== PTHREAD_MUTEX_RECURSIVE
)
1088 mutex
->mtxopts
.options
.lock_count
= 1;
1089 PLOCKSTAT_MUTEX_ACQUIRE(omutex
, 1, 0);
1092 PLOCKSTAT_MUTEX_ERROR(omutex
, error
);
1099 (void)__kdebug_trace(_KSYN_TRACE_UM_LOCK
| DBG_FUNC_END
, (uint32_t)mutex
, 0xfafafafa, 0, error
, 0);
1106 * TODO: Priority inheritance stuff
1109 pthread_mutex_unlock(pthread_mutex_t
*omutex
)
1111 npthread_mutex_t
* mutex
= (npthread_mutex_t
*)omutex
;
1113 uint32_t mtxgen
, mtxugen
, flags
, notify
, updateval
;
1114 int sig
= mutex
->sig
;
1117 volatile uint32_t * lseqaddr
, *useqaddr
;
1120 /* To provide backwards compat for apps using mutex incorrectly */
1123 (void)__kdebug_trace(_KSYN_TRACE_UM_UNLOCK
| DBG_FUNC_START
, (uint32_t)mutex
, 0, 0, 0, 0);
1125 if ((sig
!= _PTHREAD_MUTEX_SIG
) && ((sig
& _PTHREAD_MUTEX_SIG_init_MASK
) != _PTHREAD_MUTEX_SIG_CMP
)) {
1126 PLOCKSTAT_MUTEX_ERROR(omutex
, EINVAL
);
1130 if (mutex
->sig
!= _PTHREAD_MUTEX_SIG
) {
1132 if ((mutex
->sig
& _PTHREAD_MUTEX_SIG_init_MASK
) == _PTHREAD_MUTEX_SIG_CMP
) {
1133 /* static initializer, init the mutex */
1134 if((retval
= _pthread_mutex_init(omutex
, NULL
, (mutex
->sig
& 0xf))) != 0){
1135 UNLOCK(mutex
->lock
);
1136 PLOCKSTAT_MUTEX_ERROR(omutex
, retval
);
1139 } else if (mutex
->sig
!= _PTHREAD_MUTEX_SIG
) {
1140 UNLOCK(mutex
->lock
);
1141 PLOCKSTAT_MUTEX_ERROR(omutex
, EINVAL
);
1144 UNLOCK(mutex
->lock
);
1147 MUTEX_GETSEQ_ADDR(mutex
, lseqaddr
, useqaddr
);
1150 retval
= __mtx_droplock(mutex
, PTHRW_INC
, &flags
, NULL
, &mtxgen
, &mtxugen
);
1154 if ((flags
& _PTHREAD_MTX_OPT_NOTIFY
) != 0) {
1155 firstfit
= (mutex
->mtxopts
.options
.policy
== _PTHREAD_MUTEX_POLICY_FIRSTFIT
);
1157 self
= pthread_self();
1158 (void) pthread_threadid_np(self
, &selfid
);
1161 (void)__kdebug_trace(_KSYN_TRACE_UM_UNLOCK
| DBG_FUNC_NONE
, (uint32_t)mutex
, 1, mtxgen
, mtxugen
, 0);
1163 #if USE_COMPAGE /* [ */
1164 if ((updateval
= __psynch_mutexdrop((pthread_mutex_t
*)lseqaddr
, mtxgen
, mtxugen
, mutex
->m_tid
, flags
)) == (uint32_t)-1)
1165 #else /* USECOMPAGE ][ */
1166 if ((updateval
= __psynch_mutexdrop(omutex
, mtxgen
, mtxugen
, mutex
->m_tid
, flags
))== (uint32_t)-1)
1167 #endif /* USE_COMPAGE ] */
1171 (void)__kdebug_trace(_KSYN_TRACE_UM_UNLOCK
| DBG_FUNC_END
, (uint32_t)mutex
, retval
, 0, 0, 0);
1175 else if (errno
== EINTR
)
1178 LIBC_ABORT("__p_mutexdrop failed with error %d\n", retval
);
1181 } else if (firstfit
== 1) {
1182 if ((updateval
& PTH_RWL_PBIT
) != 0) {
1183 __mtx_markprepost(mutex
, updateval
, firstfit
);
1188 (void)__kdebug_trace(_KSYN_TRACE_UM_UNLOCK
| DBG_FUNC_END
, (uint32_t)mutex
, 0, 0, 0, 0);
1195 * Initialize a mutex variable, possibly with additional attributes.
1198 _pthread_mutex_init(pthread_mutex_t
*omutex
, const pthread_mutexattr_t
*attr
, uint32_t static_type
)
1200 npthread_mutex_t
* mutex
= (npthread_mutex_t
*)omutex
;
1204 if (attr
->sig
!= _PTHREAD_MUTEX_ATTR_SIG
)
1206 mutex
->prioceiling
= attr
->prioceiling
;
1207 mutex
->mtxopts
.options
.protocol
= attr
->protocol
;
1208 mutex
->mtxopts
.options
.policy
= attr
->policy
;
1209 mutex
->mtxopts
.options
.type
= attr
->type
;
1210 mutex
->mtxopts
.options
.pshared
= attr
->pshared
;
1212 switch(static_type
) {
1214 mutex
->mtxopts
.options
.type
= PTHREAD_MUTEX_ERRORCHECK
;
1217 mutex
->mtxopts
.options
.type
= PTHREAD_MUTEX_RECURSIVE
;
1220 /* firstfit fall thru */
1222 mutex
->mtxopts
.options
.type
= PTHREAD_MUTEX_DEFAULT
;
1228 mutex
->prioceiling
= _PTHREAD_DEFAULT_PRIOCEILING
;
1229 mutex
->mtxopts
.options
.protocol
= _PTHREAD_DEFAULT_PROTOCOL
;
1230 if (static_type
!= 3)
1231 mutex
->mtxopts
.options
.policy
= _PTHREAD_MUTEX_POLICY_FAIRSHARE
;
1233 mutex
->mtxopts
.options
.policy
= _PTHREAD_MUTEX_POLICY_FIRSTFIT
;
1234 mutex
->mtxopts
.options
.pshared
= _PTHREAD_DEFAULT_PSHARED
;
1237 mutex
->mtxopts
.options
.notify
= 0;
1238 mutex
->mtxopts
.options
.rfu
= 0;
1239 mutex
->mtxopts
.options
.hold
= 0;
1240 mutex
->mtxopts
.options
.mutex
= 1;
1241 mutex
->mtxopts
.options
.lock_count
= 0;
1242 /* address 8byte aligned? */
1243 if (((uintptr_t)mutex
& 0x07) != 0) {
1245 mutex
->mtxopts
.options
.misalign
= 1;
1246 #if defined(__LP64__)
1247 mutex
->m_lseqaddr
= &mutex
->m_seq
[0];
1248 mutex
->m_useqaddr
= &mutex
->m_seq
[1];
1249 #else /* __LP64__ */
1250 mutex
->m_lseqaddr
= &mutex
->m_seq
[1];
1251 mutex
->m_useqaddr
= &mutex
->m_seq
[2];
1252 #endif /* __LP64__ */
1255 mutex
->mtxopts
.options
.misalign
= 0;
1256 #if defined(__LP64__)
1257 mutex
->m_lseqaddr
= &mutex
->m_seq
[1];
1258 mutex
->m_useqaddr
= &mutex
->m_seq
[2];
1259 #else /* __LP64__ */
1260 mutex
->m_lseqaddr
= &mutex
->m_seq
[0];
1261 mutex
->m_useqaddr
= &mutex
->m_seq
[1];
1262 #endif /* __LP64__ */
1265 mutex
->m_seq
[0] = 0;
1266 mutex
->m_seq
[1] = 0;
1267 mutex
->m_seq
[2] = 0;
1268 mutex
->prioceiling
= 0;
1269 mutex
->priority
= 0;
1271 * For the new style mutex, interlocks are not held all the time.
1272 * We needed the signature to be set in the end. And we need
1273 * to protect against the code getting reorganized by compiler.
1274 * mutex->sig = _PTHREAD_MUTEX_SIG;
1276 __pthread_mutex_set_signature(mutex
);
1282 * Destroy a mutex variable.
1285 pthread_mutex_destroy(pthread_mutex_t
*omutex
)
1288 npthread_mutex_t
* mutex
= (npthread_mutex_t
*)omutex
;
1291 res
= _pthread_mutex_destroy_locked(omutex
);
1292 UNLOCK(mutex
->lock
);
1299 _pthread_mutex_destroy_locked(pthread_mutex_t
*omutex
)
1302 npthread_mutex_t
* mutex
= (npthread_mutex_t
*)omutex
;
1303 uint32_t lgenval
, ugenval
;
1304 volatile uint32_t * lseqaddr
, *useqaddr
;
1307 if (mutex
->sig
== _PTHREAD_MUTEX_SIG
)
1309 MUTEX_GETSEQ_ADDR(mutex
, lseqaddr
, useqaddr
);
1311 lgenval
= *(lseqaddr
);
1312 ugenval
= *(useqaddr
);
1313 if ((mutex
->m_tid
== (uint64_t)0) &&
1314 ((lgenval
& PTHRW_COUNT_MASK
) == (ugenval
& PTHRW_COUNT_MASK
)))
1316 mutex
->sig
= _PTHREAD_NO_SIG
;
1321 } else if((mutex
->sig
& _PTHREAD_MUTEX_SIG_init_MASK
)== _PTHREAD_MUTEX_SIG_CMP
) {
1322 mutex
->sig
= _PTHREAD_NO_SIG
;
1331 #endif /* !BUILDING_VARIANT ] */
1334 * Destroy a mutex attribute structure.
1337 pthread_mutexattr_destroy(pthread_mutexattr_t
*attr
)
1340 if (__unix_conforming
== 0)
1341 __unix_conforming
= 1;
1342 if (attr
->sig
!= _PTHREAD_MUTEX_ATTR_SIG
)
1344 #endif /* __DARWIN_UNIX03 */
1346 attr
->sig
= _PTHREAD_NO_SIG
; /* Uninitialized */