]> git.saurik.com Git - apple/libpthread.git/blame - src/pthread_mutex.c
libpthread-301.30.1.tar.gz
[apple/libpthread.git] / src / pthread_mutex.c
CommitLineData
f1a1da6c
A
1/*
2 * Copyright (c) 2000-2003, 2007, 2008 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
a0619f9c 5 *
f1a1da6c
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.
a0619f9c 12 *
f1a1da6c
A
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.
a0619f9c 20 *
f1a1da6c
A
21 * @APPLE_LICENSE_HEADER_END@
22 */
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
964d3577 53#include "resolver.h"
f1a1da6c
A
54#include "internal.h"
55#include "kern/kern_trace.h"
a0619f9c
A
56
57extern int __unix_conforming;
58
59#ifndef BUILDING_VARIANT /* [ */
f1a1da6c
A
60
61#ifdef PLOCKSTAT
62#include "plockstat.h"
a0619f9c
A
63/* This function is never called and exists to provide never-fired dtrace
64 * probes so that user d scripts don't get errors.
65 */
66PTHREAD_NOEXPORT PTHREAD_USED
67void
68_plockstat_never_fired(void)
69{
70 PLOCKSTAT_MUTEX_SPIN(NULL);
71 PLOCKSTAT_MUTEX_SPUN(NULL, 0, 0);
72}
f1a1da6c
A
73#else /* !PLOCKSTAT */
74#define PLOCKSTAT_MUTEX_SPIN(x)
75#define PLOCKSTAT_MUTEX_SPUN(x, y, z)
76#define PLOCKSTAT_MUTEX_ERROR(x, y)
77#define PLOCKSTAT_MUTEX_BLOCK(x)
78#define PLOCKSTAT_MUTEX_BLOCKED(x, y)
79#define PLOCKSTAT_MUTEX_ACQUIRE(x, y, z)
80#define PLOCKSTAT_MUTEX_RELEASE(x, y)
81#endif /* PLOCKSTAT */
82
a0619f9c
A
83#define BLOCK_FAIL_PLOCKSTAT 0
84#define BLOCK_SUCCESS_PLOCKSTAT 1
3a6437e6 85
a0619f9c 86#define PTHREAD_MUTEX_INIT_UNUSED 1
f1a1da6c 87
a0619f9c
A
88PTHREAD_NOEXPORT PTHREAD_WEAK // prevent inlining of return value into callers
89int _pthread_mutex_lock_slow(pthread_mutex_t *omutex, bool trylock);
964d3577
A
90
91PTHREAD_NOEXPORT PTHREAD_WEAK // prevent inlining of return value into callers
a0619f9c 92int _pthread_mutex_unlock_slow(pthread_mutex_t *omutex);
964d3577
A
93
94PTHREAD_NOEXPORT PTHREAD_WEAK // prevent inlining of return value into callers
a0619f9c 95int _pthread_mutex_corruption_abort(_pthread_mutex *mutex);
964d3577 96
964d3577 97
a0619f9c
A
98PTHREAD_ALWAYS_INLINE
99static inline int _pthread_mutex_init(_pthread_mutex *mutex,
100 const pthread_mutexattr_t *attr, uint32_t static_type);
f1a1da6c
A
101
102#define DEBUG_TRACE_POINTS 0
103
104#if DEBUG_TRACE_POINTS
a0619f9c
A
105#include <sys/kdebug.h>
106#define DEBUG_TRACE(x, a, b, c, d) kdebug_trace(TRACE_##x, a, b, c, d)
f1a1da6c
A
107#else
108#define DEBUG_TRACE(x, a, b, c, d) do { } while(0)
109#endif
110
a0619f9c
A
111typedef union mutex_seq {
112 uint32_t seq[2];
113 struct { uint32_t lgenval; uint32_t ugenval; };
114 struct { uint32_t mgen; uint32_t ugen; };
115 uint64_t seq_LU;
116 uint64_t _Atomic atomic_seq_LU;
117} mutex_seq;
f1a1da6c 118
a0619f9c
A
119_Static_assert(sizeof(mutex_seq) == 2 * sizeof(uint32_t),
120 "Incorrect mutex_seq size");
f1a1da6c
A
121
122#if !__LITTLE_ENDIAN__
123#error MUTEX_GETSEQ_ADDR assumes little endian layout of 2 32-bit sequence words
124#endif
125
964d3577
A
126PTHREAD_ALWAYS_INLINE
127static inline void
a0619f9c 128MUTEX_GETSEQ_ADDR(_pthread_mutex *mutex, mutex_seq **seqaddr)
f1a1da6c 129{
3a6437e6
A
130 // 64-bit aligned address inside m_seq array (&m_seq[0] for aligned mutex)
131 // We don't require more than byte alignment on OS X. rdar://22278325
a0619f9c 132 *seqaddr = (void *)(((uintptr_t)mutex->m_seq + 0x7ul) & ~0x7ul);
f1a1da6c
A
133}
134
964d3577
A
135PTHREAD_ALWAYS_INLINE
136static inline void
a0619f9c 137MUTEX_GETTID_ADDR(_pthread_mutex *mutex, uint64_t **tidaddr)
f1a1da6c 138{
3a6437e6
A
139 // 64-bit aligned address inside m_tid array (&m_tid[0] for aligned mutex)
140 // We don't require more than byte alignment on OS X. rdar://22278325
a0619f9c 141 *tidaddr = (void*)(((uintptr_t)mutex->m_tid + 0x7ul) & ~0x7ul);
f1a1da6c
A
142}
143
a0619f9c
A
144PTHREAD_ALWAYS_INLINE
145static inline void
146mutex_seq_load(mutex_seq *seqaddr, mutex_seq *oldseqval)
147{
148 oldseqval->seq_LU = seqaddr->seq_LU;
149}
f1a1da6c 150
a0619f9c
A
151PTHREAD_ALWAYS_INLINE
152static inline void
153mutex_seq_atomic_load_relaxed(mutex_seq *seqaddr, mutex_seq *oldseqval)
154{
155 oldseqval->seq_LU = os_atomic_load(&seqaddr->atomic_seq_LU, relaxed);
156}
f1a1da6c 157
a0619f9c
A
158#define mutex_seq_atomic_load(seqaddr, oldseqval, m) \
159 mutex_seq_atomic_load_##m(seqaddr, oldseqval)
160
161PTHREAD_ALWAYS_INLINE
162static inline bool
163mutex_seq_atomic_cmpxchgv_relaxed(mutex_seq *seqaddr, mutex_seq *oldseqval,
164 mutex_seq *newseqval)
f1a1da6c 165{
a0619f9c
A
166 return os_atomic_cmpxchgv(&seqaddr->atomic_seq_LU, oldseqval->seq_LU,
167 newseqval->seq_LU, &oldseqval->seq_LU, relaxed);
168}
169
170PTHREAD_ALWAYS_INLINE
171static inline bool
172mutex_seq_atomic_cmpxchgv_acquire(mutex_seq *seqaddr, mutex_seq *oldseqval,
173 mutex_seq *newseqval)
174{
175 return os_atomic_cmpxchgv(&seqaddr->atomic_seq_LU, oldseqval->seq_LU,
176 newseqval->seq_LU, &oldseqval->seq_LU, acquire);
177}
178
179PTHREAD_ALWAYS_INLINE
180static inline bool
181mutex_seq_atomic_cmpxchgv_release(mutex_seq *seqaddr, mutex_seq *oldseqval,
182 mutex_seq *newseqval)
183{
184 return os_atomic_cmpxchgv(&seqaddr->atomic_seq_LU, oldseqval->seq_LU,
185 newseqval->seq_LU, &oldseqval->seq_LU, release);
f1a1da6c 186}
a0619f9c
A
187
188#define mutex_seq_atomic_cmpxchgv(seqaddr, oldseqval, newseqval, m)\
189 mutex_seq_atomic_cmpxchgv_##m(seqaddr, oldseqval, newseqval)
f1a1da6c
A
190
191/*
192 * Initialize a mutex variable, possibly with additional attributes.
193 * Public interface - so don't trust the lock - initialize it first.
194 */
a0619f9c 195PTHREAD_NOEXPORT_VARIANT
f1a1da6c
A
196int
197pthread_mutex_init(pthread_mutex_t *omutex, const pthread_mutexattr_t *attr)
198{
199#if 0
200 /* conformance tests depend on not having this behavior */
201 /* The test for this behavior is optional */
964d3577 202 if (_pthread_mutex_check_signature(mutex))
f1a1da6c
A
203 return EBUSY;
204#endif
205 _pthread_mutex *mutex = (_pthread_mutex *)omutex;
2546420a 206 _PTHREAD_LOCK_INIT(mutex->lock);
f1a1da6c
A
207 return (_pthread_mutex_init(mutex, attr, 0x7));
208}
209
a0619f9c 210PTHREAD_NOEXPORT_VARIANT
f1a1da6c
A
211int
212pthread_mutex_getprioceiling(const pthread_mutex_t *omutex, int *prioceiling)
213{
214 int res = EINVAL;
215 _pthread_mutex *mutex = (_pthread_mutex *)omutex;
964d3577 216 if (_pthread_mutex_check_signature(mutex)) {
2546420a 217 _PTHREAD_LOCK(mutex->lock);
f1a1da6c
A
218 *prioceiling = mutex->prioceiling;
219 res = 0;
2546420a 220 _PTHREAD_UNLOCK(mutex->lock);
f1a1da6c
A
221 }
222 return res;
223}
224
a0619f9c 225PTHREAD_NOEXPORT_VARIANT
f1a1da6c 226int
a0619f9c
A
227pthread_mutex_setprioceiling(pthread_mutex_t *omutex, int prioceiling,
228 int *old_prioceiling)
f1a1da6c
A
229{
230 int res = EINVAL;
231 _pthread_mutex *mutex = (_pthread_mutex *)omutex;
964d3577 232 if (_pthread_mutex_check_signature(mutex)) {
2546420a 233 _PTHREAD_LOCK(mutex->lock);
a0619f9c 234 if (prioceiling >= -999 && prioceiling <= 999) {
f1a1da6c 235 *old_prioceiling = mutex->prioceiling;
a0619f9c 236 mutex->prioceiling = (int16_t)prioceiling;
f1a1da6c
A
237 res = 0;
238 }
2546420a 239 _PTHREAD_UNLOCK(mutex->lock);
f1a1da6c
A
240 }
241 return res;
242}
243
a0619f9c 244
f1a1da6c 245int
a0619f9c
A
246pthread_mutexattr_getprioceiling(const pthread_mutexattr_t *attr,
247 int *prioceiling)
f1a1da6c
A
248{
249 int res = EINVAL;
250 if (attr->sig == _PTHREAD_MUTEX_ATTR_SIG) {
251 *prioceiling = attr->prioceiling;
252 res = 0;
253 }
254 return res;
255}
256
257int
258pthread_mutexattr_getprotocol(const pthread_mutexattr_t *attr, int *protocol)
259{
260 int res = EINVAL;
261 if (attr->sig == _PTHREAD_MUTEX_ATTR_SIG) {
262 *protocol = attr->protocol;
263 res = 0;
264 }
265 return res;
266}
267
268int
269pthread_mutexattr_gettype(const pthread_mutexattr_t *attr, int *type)
270{
271 int res = EINVAL;
272 if (attr->sig == _PTHREAD_MUTEX_ATTR_SIG) {
273 *type = attr->type;
274 res = 0;
275 }
276 return res;
277}
278
279int
280pthread_mutexattr_getpshared(const pthread_mutexattr_t *attr, int *pshared)
281{
282 int res = EINVAL;
283 if (attr->sig == _PTHREAD_MUTEX_ATTR_SIG) {
284 *pshared = (int)attr->pshared;
285 res = 0;
286 }
287 return res;
288}
289
290int
291pthread_mutexattr_init(pthread_mutexattr_t *attr)
292{
293 attr->prioceiling = _PTHREAD_DEFAULT_PRIOCEILING;
294 attr->protocol = _PTHREAD_DEFAULT_PROTOCOL;
295 attr->policy = _PTHREAD_MUTEX_POLICY_FAIRSHARE;
296 attr->type = PTHREAD_MUTEX_DEFAULT;
297 attr->sig = _PTHREAD_MUTEX_ATTR_SIG;
298 attr->pshared = _PTHREAD_DEFAULT_PSHARED;
299 return 0;
300}
301
302int
303pthread_mutexattr_setprioceiling(pthread_mutexattr_t *attr, int prioceiling)
304{
305 int res = EINVAL;
306 if (attr->sig == _PTHREAD_MUTEX_ATTR_SIG) {
a0619f9c 307 if (prioceiling >= -999 && prioceiling <= 999) {
f1a1da6c
A
308 attr->prioceiling = prioceiling;
309 res = 0;
310 }
311 }
312 return res;
313}
314
315int
316pthread_mutexattr_setprotocol(pthread_mutexattr_t *attr, int protocol)
317{
318 int res = EINVAL;
319 if (attr->sig == _PTHREAD_MUTEX_ATTR_SIG) {
320 switch (protocol) {
321 case PTHREAD_PRIO_NONE:
322 case PTHREAD_PRIO_INHERIT:
323 case PTHREAD_PRIO_PROTECT:
324 attr->protocol = protocol;
325 res = 0;
326 break;
327 }
328 }
329 return res;
330}
331
332int
333pthread_mutexattr_setpolicy_np(pthread_mutexattr_t *attr, int policy)
334{
335 int res = EINVAL;
336 if (attr->sig == _PTHREAD_MUTEX_ATTR_SIG) {
337 switch (policy) {
338 case _PTHREAD_MUTEX_POLICY_FAIRSHARE:
339 case _PTHREAD_MUTEX_POLICY_FIRSTFIT:
340 attr->policy = policy;
341 res = 0;
342 break;
343 }
344 }
345 return res;
346}
347
348int
349pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type)
350{
351 int res = EINVAL;
352 if (attr->sig == _PTHREAD_MUTEX_ATTR_SIG) {
353 switch (type) {
354 case PTHREAD_MUTEX_NORMAL:
355 case PTHREAD_MUTEX_ERRORCHECK:
356 case PTHREAD_MUTEX_RECURSIVE:
357 //case PTHREAD_MUTEX_DEFAULT:
358 attr->type = type;
359 res = 0;
360 break;
361 }
362 }
363 return res;
364}
365
f1a1da6c
A
366int
367pthread_mutexattr_setpshared(pthread_mutexattr_t *attr, int pshared)
368{
369 int res = EINVAL;
370#if __DARWIN_UNIX03
371 if (__unix_conforming == 0) {
372 __unix_conforming = 1;
373 }
374#endif /* __DARWIN_UNIX03 */
375
376 if (attr->sig == _PTHREAD_MUTEX_ATTR_SIG) {
377#if __DARWIN_UNIX03
a0619f9c
A
378 if (( pshared == PTHREAD_PROCESS_PRIVATE) ||
379 (pshared == PTHREAD_PROCESS_SHARED))
f1a1da6c
A
380#else /* __DARWIN_UNIX03 */
381 if ( pshared == PTHREAD_PROCESS_PRIVATE)
382#endif /* __DARWIN_UNIX03 */
383 {
a0619f9c 384 attr->pshared = pshared;
f1a1da6c
A
385 res = 0;
386 }
387 }
388 return res;
389}
390
a0619f9c 391PTHREAD_NOEXPORT PTHREAD_NOINLINE PTHREAD_NORETURN
964d3577
A
392int
393_pthread_mutex_corruption_abort(_pthread_mutex *mutex)
394{
a0619f9c
A
395 PTHREAD_ABORT("pthread_mutex corruption: mutex owner changed in the "
396 "middle of lock/unlock");
964d3577
A
397}
398
a0619f9c 399
f1a1da6c
A
400/*
401 * Sequence numbers and TID:
402 *
403 * In steady (and uncontended) state, an unlocked mutex will
404 * look like A=[L4 U4 TID0]. When it is being locked, it transitions
405 * to B=[L5+KE U4 TID0] and then C=[L5+KE U4 TID940]. For an uncontended mutex,
406 * the unlock path will then transition to D=[L5 U4 TID0] and then finally
407 * E=[L5 U5 TID0].
408 *
a0619f9c
A
409 * If a contender comes in after B, the mutex will instead transition to
410 * E=[L6+KE U4 TID0] and then F=[L6+KE U4 TID940]. If a contender comes in after
411 * C, it will transition to F=[L6+KE U4 TID940] directly. In both cases, the
412 * contender will enter the kernel with either mutexwait(U4, TID0) or
413 * mutexwait(U4, TID940). The first owner will unlock the mutex by first
414 * updating the owner to G=[L6+KE U4 TID-1] and then doing the actual unlock to
415 * H=[L6+KE U5 TID=-1] before entering the kernel with mutexdrop(U5, -1) to
416 * signal the next waiter (potentially as a prepost). When the waiter comes out
417 * of the kernel, it will update the owner to I=[L6+KE U5 TID941]. An unlock at
418 * this point is simply J=[L6 U5 TID0] and then K=[L6 U6 TID0].
f1a1da6c 419 *
a0619f9c
A
420 * At various points along these timelines, since the sequence words and TID are
421 * written independently, a thread may get preempted and another thread might
422 * see inconsistent data. In the worst case, another thread may see the TID in
423 * the SWITCHING (-1) state or unlocked (0) state for longer because the owning
424 * thread was preempted.
964d3577 425 */
f1a1da6c
A
426
427/*
a0619f9c 428 * Drop the mutex unlock references from cond_wait or mutex_unlock.
f1a1da6c 429 */
964d3577
A
430PTHREAD_ALWAYS_INLINE
431static inline int
a0619f9c
A
432_pthread_mutex_unlock_updatebits(_pthread_mutex *mutex, uint32_t *flagsp,
433 uint32_t **pmtxp, uint32_t *mgenp, uint32_t *ugenp)
f1a1da6c 434{
a0619f9c
A
435 bool firstfit = (mutex->mtxopts.options.policy ==
436 _PTHREAD_MUTEX_POLICY_FIRSTFIT);
437 uint32_t flags = mutex->mtxopts.value;
f1a1da6c
A
438 flags &= ~_PTHREAD_MTX_OPT_NOTIFY; // no notification by default
439
a0619f9c
A
440 mutex_seq *seqaddr;
441 MUTEX_GETSEQ_ADDR(mutex, &seqaddr);
442
443 mutex_seq oldseq, newseq;
444 mutex_seq_load(seqaddr, &oldseq);
445
446 uint64_t *tidaddr;
447 MUTEX_GETTID_ADDR(mutex, &tidaddr);
448 uint64_t oldtid, newtid;
449
f1a1da6c
A
450 if (mutex->mtxopts.options.type != PTHREAD_MUTEX_NORMAL) {
451 uint64_t selfid = _pthread_selfid_direct();
a0619f9c 452 if (os_atomic_load(tidaddr, relaxed) != selfid) {
f1a1da6c
A
453 PLOCKSTAT_MUTEX_ERROR((pthread_mutex_t *)mutex, EPERM);
454 return EPERM;
455 } else if (mutex->mtxopts.options.type == PTHREAD_MUTEX_RECURSIVE &&
456 --mutex->mtxopts.options.lock_count) {
457 PLOCKSTAT_MUTEX_RELEASE((pthread_mutex_t *)mutex, 1);
458 if (flagsp != NULL) {
459 *flagsp = flags;
460 }
461 return 0;
462 }
463 }
464
f1a1da6c
A
465 bool clearprepost, clearnotify, spurious;
466 do {
a0619f9c
A
467 newseq = oldseq;
468 oldtid = os_atomic_load(tidaddr, relaxed);
f1a1da6c
A
469
470 clearprepost = false;
471 clearnotify = false;
472 spurious = false;
473
a0619f9c
A
474 // pending waiters
475 int numwaiters = diff_genseq(oldseq.lgenval, oldseq.ugenval);
f1a1da6c 476 if (numwaiters == 0) {
a0619f9c 477 // spurious unlock (unlock of unlocked lock)
f1a1da6c
A
478 spurious = true;
479 } else {
a0619f9c 480 newseq.ugenval += PTHRW_INC;
f1a1da6c 481
a0619f9c
A
482 if ((oldseq.lgenval & PTHRW_COUNT_MASK) ==
483 (newseq.ugenval & PTHRW_COUNT_MASK)) {
484 // our unlock sequence matches to lock sequence, so if the
485 // CAS is successful, the mutex is unlocked
f1a1da6c
A
486
487 /* do not reset Ibit, just K&E */
a0619f9c 488 newseq.lgenval &= ~(PTH_RWL_KBIT | PTH_RWL_EBIT);
f1a1da6c
A
489 clearnotify = true;
490 newtid = 0; // clear owner
491 } else {
492 if (firstfit) {
a0619f9c
A
493 // reset E bit so another can acquire meanwhile
494 newseq.lgenval &= ~PTH_RWL_EBIT;
f1a1da6c
A
495 newtid = 0;
496 } else {
497 newtid = PTHREAD_MTX_TID_SWITCHING;
498 }
499 // need to signal others waiting for mutex
500 flags |= _PTHREAD_MTX_OPT_NOTIFY;
501 }
a0619f9c 502
f1a1da6c 503 if (newtid != oldtid) {
a0619f9c
A
504 // We're giving up the mutex one way or the other, so go ahead
505 // and update the owner to 0 so that once the CAS below
506 // succeeds, there is no stale ownership information. If the
507 // CAS of the seqaddr fails, we may loop, but it's still valid
508 // for the owner to be SWITCHING/0
964d3577 509 if (!os_atomic_cmpxchg(tidaddr, oldtid, newtid, relaxed)) {
f1a1da6c 510 // we own this mutex, nobody should be updating it except us
964d3577 511 return _pthread_mutex_corruption_abort(mutex);
f1a1da6c
A
512 }
513 }
514 }
515
516 if (clearnotify || spurious) {
517 flags &= ~_PTHREAD_MTX_OPT_NOTIFY;
a0619f9c 518 if (firstfit && (newseq.lgenval & PTH_RWL_PBIT)) {
f1a1da6c 519 clearprepost = true;
a0619f9c 520 newseq.lgenval &= ~PTH_RWL_PBIT;
f1a1da6c
A
521 }
522 }
a0619f9c 523 } while (!mutex_seq_atomic_cmpxchgv(seqaddr, &oldseq, &newseq, release));
f1a1da6c
A
524
525 if (clearprepost) {
a0619f9c
A
526 __psynch_cvclrprepost(mutex, newseq.lgenval, newseq.ugenval, 0, 0,
527 newseq.lgenval, flags | _PTHREAD_MTX_OPT_MUTEX);
f1a1da6c
A
528 }
529
530 if (mgenp != NULL) {
a0619f9c 531 *mgenp = newseq.lgenval;
f1a1da6c
A
532 }
533 if (ugenp != NULL) {
a0619f9c 534 *ugenp = newseq.ugenval;
f1a1da6c
A
535 }
536 if (pmtxp != NULL) {
537 *pmtxp = (uint32_t *)mutex;
538 }
539 if (flagsp != NULL) {
540 *flagsp = flags;
541 }
542
543 return 0;
544}
545
a0619f9c 546PTHREAD_NOEXPORT PTHREAD_NOINLINE
964d3577 547int
a0619f9c
A
548_pthread_mutex_droplock(_pthread_mutex *mutex, uint32_t *flagsp,
549 uint32_t **pmtxp, uint32_t *mgenp, uint32_t *ugenp)
964d3577
A
550{
551 return _pthread_mutex_unlock_updatebits(mutex, flagsp, pmtxp, mgenp, ugenp);
552}
553
554PTHREAD_ALWAYS_INLINE
555static inline int
556_pthread_mutex_lock_updatebits(_pthread_mutex *mutex, uint64_t selfid)
f1a1da6c
A
557{
558 int res = 0;
a0619f9c
A
559 bool firstfit = (mutex->mtxopts.options.policy ==
560 _PTHREAD_MUTEX_POLICY_FIRSTFIT);
561 bool isebit = false, updated = false;
f1a1da6c 562
a0619f9c 563 mutex_seq *seqaddr;
f1a1da6c 564 MUTEX_GETSEQ_ADDR(mutex, &seqaddr);
a0619f9c
A
565
566 mutex_seq oldseq, newseq;
567 mutex_seq_load(seqaddr, &oldseq);
568
569 uint64_t *tidaddr;
f1a1da6c 570 MUTEX_GETTID_ADDR(mutex, &tidaddr);
a0619f9c 571 uint64_t oldtid;
f1a1da6c
A
572
573 do {
a0619f9c
A
574 if (firstfit && isebit && updated) {
575 mutex_seq_atomic_load(seqaddr, &oldseq, relaxed);
576 }
577 newseq = oldseq;
578 oldtid = os_atomic_load(tidaddr, relaxed);
f1a1da6c 579
a0619f9c 580 if (isebit && !(oldseq.lgenval & PTH_RWL_EBIT)) {
f1a1da6c
A
581 // E bit was set on first pass through the loop but is no longer
582 // set. Apparently we spin until it arrives.
583 // XXX: verify this is desired behavior.
a0619f9c
A
584 continue;
585 }
f1a1da6c
A
586
587 if (isebit) {
588 // first fit mutex now has the E bit set. Return 1.
589 res = 1;
590 break;
591 }
592
593 if (firstfit) {
a0619f9c
A
594 isebit = (oldseq.lgenval & PTH_RWL_EBIT);
595 } else if ((oldseq.lgenval & (PTH_RWL_KBIT|PTH_RWL_EBIT)) ==
596 (PTH_RWL_KBIT|PTH_RWL_EBIT)) {
f1a1da6c
A
597 // fairshare mutex and the bits are already set, just update tid
598 break;
599 }
600
601 // either first fit or no E bit set
602 // update the bits
a0619f9c 603 newseq.lgenval |= PTH_RWL_KBIT | PTH_RWL_EBIT;
f1a1da6c 604
a0619f9c
A
605 // Retry if CAS fails, or if it succeeds with firstfit and E bit
606 // already set
607 } while (!(updated = mutex_seq_atomic_cmpxchgv(seqaddr, &oldseq, &newseq,
608 relaxed)) || (firstfit && isebit));
f1a1da6c
A
609
610 if (res == 0) {
964d3577 611 if (!os_atomic_cmpxchg(tidaddr, oldtid, selfid, relaxed)) {
f1a1da6c 612 // we own this mutex, nobody should be updating it except us
964d3577 613 return _pthread_mutex_corruption_abort(mutex);
f1a1da6c
A
614 }
615 }
616
617 return res;
618}
619
964d3577
A
620PTHREAD_NOINLINE
621static int
a0619f9c 622_pthread_mutex_markprepost(_pthread_mutex *mutex, uint32_t updateval)
f1a1da6c 623{
a0619f9c 624 mutex_seq *seqaddr;
f1a1da6c
A
625 MUTEX_GETSEQ_ADDR(mutex, &seqaddr);
626
a0619f9c
A
627 mutex_seq oldseq, newseq;
628 mutex_seq_load(seqaddr, &oldseq);
f1a1da6c 629
a0619f9c
A
630 bool clearprepost;
631 do {
632 clearprepost = false;
633 newseq = oldseq;
f1a1da6c 634
a0619f9c
A
635 /* update the bits */
636 if ((oldseq.lgenval & PTHRW_COUNT_MASK) ==
637 (oldseq.ugenval & PTHRW_COUNT_MASK)) {
638 clearprepost = true;
639 newseq.lgenval &= ~PTH_RWL_PBIT;
640 } else {
641 newseq.lgenval |= PTH_RWL_PBIT;
f1a1da6c 642 }
a0619f9c
A
643 } while (!mutex_seq_atomic_cmpxchgv(seqaddr, &oldseq, &newseq, relaxed));
644
645 if (clearprepost) {
646 __psynch_cvclrprepost(mutex, newseq.lgenval, newseq.ugenval, 0, 0,
647 newseq.lgenval, mutex->mtxopts.value | _PTHREAD_MTX_OPT_MUTEX);
f1a1da6c 648 }
a0619f9c 649
f1a1da6c
A
650 return 0;
651}
652
964d3577
A
653PTHREAD_NOINLINE
654static int
655_pthread_mutex_check_init_slow(pthread_mutex_t *omutex)
f1a1da6c 656{
964d3577
A
657 int res = EINVAL;
658 _pthread_mutex *mutex = (_pthread_mutex *)omutex;
659
660 if (_pthread_mutex_check_signature_init(mutex)) {
2546420a 661 _PTHREAD_LOCK(mutex->lock);
964d3577
A
662 if (_pthread_mutex_check_signature_init(mutex)) {
663 // initialize a statically initialized mutex to provide
664 // compatibility for misbehaving applications.
665 // (unlock should not be the first operation on a mutex)
666 res = _pthread_mutex_init(mutex, NULL, (mutex->sig & 0xf));
667 } else if (_pthread_mutex_check_signature(mutex)) {
668 res = 0;
669 }
2546420a 670 _PTHREAD_UNLOCK(mutex->lock);
964d3577
A
671 } else if (_pthread_mutex_check_signature(mutex)) {
672 res = 0;
673 }
674 if (res != 0) {
675 PLOCKSTAT_MUTEX_ERROR(omutex, res);
676 }
677 return res;
f1a1da6c
A
678}
679
964d3577
A
680PTHREAD_ALWAYS_INLINE
681static inline int
f1a1da6c
A
682_pthread_mutex_check_init(pthread_mutex_t *omutex)
683{
684 int res = 0;
685 _pthread_mutex *mutex = (_pthread_mutex *)omutex;
a0619f9c 686
964d3577
A
687 if (!_pthread_mutex_check_signature(mutex)) {
688 return _pthread_mutex_check_init_slow(omutex);
f1a1da6c
A
689 }
690 return res;
691}
692
964d3577 693PTHREAD_NOINLINE
a0619f9c
A
694static int
695_pthread_mutex_lock_wait(pthread_mutex_t *omutex, mutex_seq newseq,
696 uint64_t oldtid)
964d3577
A
697{
698 _pthread_mutex *mutex = (_pthread_mutex *)omutex;
964d3577 699
a0619f9c 700 uint64_t *tidaddr;
964d3577
A
701 MUTEX_GETTID_ADDR(mutex, &tidaddr);
702 uint64_t selfid = _pthread_selfid_direct();
703
704 PLOCKSTAT_MUTEX_BLOCK(omutex);
705 do {
706 uint32_t updateval;
707 do {
a0619f9c
A
708 updateval = __psynch_mutexwait(omutex, newseq.lgenval,
709 newseq.ugenval, oldtid, mutex->mtxopts.value);
710 oldtid = os_atomic_load(tidaddr, relaxed);
964d3577
A
711 } while (updateval == (uint32_t)-1);
712
713 // returns 0 on succesful update; in firstfit it may fail with 1
714 } while (_pthread_mutex_lock_updatebits(mutex, selfid) == 1);
715 PLOCKSTAT_MUTEX_BLOCKED(omutex, BLOCK_SUCCESS_PLOCKSTAT);
716
717 return 0;
718}
719
a0619f9c 720PTHREAD_NOEXPORT PTHREAD_NOINLINE
964d3577
A
721int
722_pthread_mutex_lock_slow(pthread_mutex_t *omutex, bool trylock)
f1a1da6c 723{
a0619f9c 724 int res, recursive = 0;
f1a1da6c
A
725 _pthread_mutex *mutex = (_pthread_mutex *)omutex;
726
964d3577 727 res = _pthread_mutex_check_init(omutex);
a0619f9c 728 if (res != 0) return res;
f1a1da6c 729
a0619f9c
A
730 mutex_seq *seqaddr;
731 MUTEX_GETSEQ_ADDR(mutex, &seqaddr);
732
733 mutex_seq oldseq, newseq;
734 mutex_seq_load(seqaddr, &oldseq);
735
736 uint64_t *tidaddr;
f1a1da6c 737 MUTEX_GETTID_ADDR(mutex, &tidaddr);
a0619f9c 738 uint64_t oldtid, selfid = _pthread_selfid_direct();
f1a1da6c
A
739
740 if (mutex->mtxopts.options.type != PTHREAD_MUTEX_NORMAL) {
a0619f9c 741 if (os_atomic_load(tidaddr, relaxed) == selfid) {
f1a1da6c
A
742 if (mutex->mtxopts.options.type == PTHREAD_MUTEX_RECURSIVE) {
743 if (mutex->mtxopts.options.lock_count < USHRT_MAX) {
744 mutex->mtxopts.options.lock_count++;
a0619f9c 745 recursive = 1;
f1a1da6c
A
746 res = 0;
747 } else {
748 res = EAGAIN;
f1a1da6c
A
749 }
750 } else if (trylock) { /* PTHREAD_MUTEX_ERRORCHECK */
751 // <rdar://problem/16261552> as per OpenGroup, trylock cannot
752 // return EDEADLK on a deadlock, it should return EBUSY.
753 res = EBUSY;
f1a1da6c
A
754 } else { /* PTHREAD_MUTEX_ERRORCHECK */
755 res = EDEADLK;
f1a1da6c 756 }
a0619f9c 757 goto out;
f1a1da6c
A
758 }
759 }
760
a0619f9c 761 bool gotlock;
f1a1da6c 762 do {
a0619f9c
A
763 newseq = oldseq;
764 oldtid = os_atomic_load(tidaddr, relaxed);
f1a1da6c 765
a0619f9c 766 gotlock = ((oldseq.lgenval & PTH_RWL_EBIT) == 0);
f1a1da6c
A
767
768 if (trylock && !gotlock) {
769 // A trylock on a held lock will fail immediately. But since
770 // we did not load the sequence words atomically, perform a
771 // no-op CAS64 to ensure that nobody has unlocked concurrently.
772 } else {
773 // Increment the lock sequence number and force the lock into E+K
774 // mode, whether "gotlock" is true or not.
a0619f9c
A
775 newseq.lgenval += PTHRW_INC;
776 newseq.lgenval |= PTH_RWL_EBIT | PTH_RWL_KBIT;
f1a1da6c 777 }
a0619f9c 778 } while (!mutex_seq_atomic_cmpxchgv(seqaddr, &oldseq, &newseq, acquire));
f1a1da6c
A
779
780 if (gotlock) {
964d3577 781 os_atomic_store(tidaddr, selfid, relaxed);
f1a1da6c
A
782 res = 0;
783 DEBUG_TRACE(psynch_mutex_ulock, omutex, lgenval, ugenval, selfid);
f1a1da6c
A
784 } else if (trylock) {
785 res = EBUSY;
a0619f9c
A
786 DEBUG_TRACE(psynch_mutex_utrylock_failed, omutex, lgenval, ugenval,
787 oldtid);
f1a1da6c 788 } else {
a0619f9c 789 res = _pthread_mutex_lock_wait(omutex, newseq, oldtid);
f1a1da6c
A
790 }
791
792 if (res == 0 && mutex->mtxopts.options.type == PTHREAD_MUTEX_RECURSIVE) {
793 mutex->mtxopts.options.lock_count = 1;
794 }
795
a0619f9c
A
796out:
797#if PLOCKSTAT
798 if (res == 0) {
799 PLOCKSTAT_MUTEX_ACQUIRE(omutex, recursive, 0);
800 } else {
801 PLOCKSTAT_MUTEX_ERROR(omutex, res);
802 }
803#endif
f1a1da6c
A
804
805 return res;
806}
807
964d3577
A
808PTHREAD_ALWAYS_INLINE
809static inline int
810_pthread_mutex_lock(pthread_mutex_t *omutex, bool trylock)
811{
812#if PLOCKSTAT || DEBUG_TRACE_POINTS
813 if (PLOCKSTAT_MUTEX_ACQUIRE_ENABLED() || PLOCKSTAT_MUTEX_ERROR_ENABLED() ||
814 DEBUG_TRACE_POINTS) {
815 return _pthread_mutex_lock_slow(omutex, trylock);
816 }
817#endif
818 _pthread_mutex *mutex = (_pthread_mutex *)omutex;
a0619f9c 819 if (os_unlikely(!_pthread_mutex_check_signature_fast(mutex))) {
964d3577
A
820 return _pthread_mutex_lock_slow(omutex, trylock);
821 }
822
a0619f9c 823 uint64_t *tidaddr;
964d3577
A
824 MUTEX_GETTID_ADDR(mutex, &tidaddr);
825 uint64_t selfid = _pthread_selfid_direct();
826
a0619f9c 827 mutex_seq *seqaddr;
964d3577
A
828 MUTEX_GETSEQ_ADDR(mutex, &seqaddr);
829
a0619f9c
A
830 mutex_seq oldseq, newseq;
831 mutex_seq_load(seqaddr, &oldseq);
832
833 if (os_unlikely(oldseq.lgenval & PTH_RWL_EBIT)) {
834 return _pthread_mutex_lock_slow(omutex, trylock);
835 }
964d3577 836
a0619f9c 837 bool gotlock;
964d3577 838 do {
a0619f9c 839 newseq = oldseq;
964d3577 840
a0619f9c 841 gotlock = ((oldseq.lgenval & PTH_RWL_EBIT) == 0);
964d3577
A
842
843 if (trylock && !gotlock) {
844 // A trylock on a held lock will fail immediately. But since
845 // we did not load the sequence words atomically, perform a
846 // no-op CAS64 to ensure that nobody has unlocked concurrently.
a0619f9c 847 } else if (os_likely(gotlock)) {
964d3577
A
848 // Increment the lock sequence number and force the lock into E+K
849 // mode, whether "gotlock" is true or not.
a0619f9c
A
850 newseq.lgenval += PTHRW_INC;
851 newseq.lgenval |= PTH_RWL_EBIT | PTH_RWL_KBIT;
852 } else {
853 return _pthread_mutex_lock_slow(omutex, trylock);
964d3577 854 }
a0619f9c
A
855 } while (os_unlikely(!mutex_seq_atomic_cmpxchgv(seqaddr, &oldseq, &newseq,
856 acquire)));
964d3577 857
a0619f9c 858 if (os_likely(gotlock)) {
964d3577
A
859 os_atomic_store(tidaddr, selfid, relaxed);
860 return 0;
861 } else if (trylock) {
862 return EBUSY;
863 } else {
a0619f9c 864 __builtin_trap();
964d3577
A
865 }
866}
867
868PTHREAD_NOEXPORT_VARIANT
f1a1da6c
A
869int
870pthread_mutex_lock(pthread_mutex_t *mutex)
871{
872 return _pthread_mutex_lock(mutex, false);
873}
874
964d3577 875PTHREAD_NOEXPORT_VARIANT
f1a1da6c
A
876int
877pthread_mutex_trylock(pthread_mutex_t *mutex)
878{
879 return _pthread_mutex_lock(mutex, true);
880}
881
882/*
883 * Unlock a mutex.
884 * TODO: Priority inheritance stuff
885 */
964d3577
A
886
887PTHREAD_NOINLINE
888static int
a0619f9c
A
889_pthread_mutex_unlock_drop(pthread_mutex_t *omutex, mutex_seq newseq,
890 uint32_t flags)
964d3577
A
891{
892 int res;
893 _pthread_mutex *mutex = (_pthread_mutex *)omutex;
964d3577
A
894
895 uint32_t updateval;
a0619f9c
A
896
897 uint64_t *tidaddr;
964d3577
A
898 MUTEX_GETTID_ADDR(mutex, &tidaddr);
899
a0619f9c
A
900 updateval = __psynch_mutexdrop(omutex, newseq.lgenval, newseq.ugenval,
901 os_atomic_load(tidaddr, relaxed), flags);
964d3577
A
902
903 if (updateval == (uint32_t)-1) {
904 res = errno;
905
906 if (res == EINTR) {
907 res = 0;
908 }
909 if (res != 0) {
a0619f9c 910 PTHREAD_ABORT("__psynch_mutexdrop failed with error %d", res);
964d3577
A
911 }
912 return res;
a0619f9c
A
913 } else if ((mutex->mtxopts.options.policy == _PTHREAD_MUTEX_POLICY_FIRSTFIT)
914 && (updateval & PTH_RWL_PBIT)) {
915 return _pthread_mutex_markprepost(mutex, updateval);
964d3577
A
916 }
917
918 return 0;
919}
920
a0619f9c 921PTHREAD_NOEXPORT PTHREAD_NOINLINE
f1a1da6c 922int
964d3577 923_pthread_mutex_unlock_slow(pthread_mutex_t *omutex)
f1a1da6c
A
924{
925 int res;
926 _pthread_mutex *mutex = (_pthread_mutex *)omutex;
a0619f9c
A
927 mutex_seq newseq;
928 uint32_t flags;
f1a1da6c
A
929
930 // Initialize static mutexes for compatibility with misbehaving
931 // applications (unlock should not be the first operation on a mutex).
964d3577 932 res = _pthread_mutex_check_init(omutex);
a0619f9c 933 if (res != 0) return res;
f1a1da6c 934
a0619f9c
A
935 res = _pthread_mutex_unlock_updatebits(mutex, &flags, NULL, &newseq.lgenval,
936 &newseq.ugenval);
937 if (res != 0) return res;
f1a1da6c
A
938
939 if ((flags & _PTHREAD_MTX_OPT_NOTIFY) != 0) {
a0619f9c 940 return _pthread_mutex_unlock_drop(omutex, newseq, flags);
964d3577 941 } else {
a0619f9c 942 uint64_t *tidaddr;
f1a1da6c 943 MUTEX_GETTID_ADDR(mutex, &tidaddr);
a0619f9c
A
944 DEBUG_TRACE(psynch_mutex_uunlock, omutex, mtxgen, mtxugen,
945 os_atomic_load(tidaddr, relaxed));
964d3577 946 }
f1a1da6c 947
964d3577
A
948 return 0;
949}
f1a1da6c 950
964d3577
A
951PTHREAD_NOEXPORT_VARIANT
952int
953pthread_mutex_unlock(pthread_mutex_t *omutex)
954{
955#if PLOCKSTAT || DEBUG_TRACE_POINTS
956 if (PLOCKSTAT_MUTEX_RELEASE_ENABLED() || PLOCKSTAT_MUTEX_ERROR_ENABLED() ||
957 DEBUG_TRACE_POINTS) {
958 return _pthread_mutex_unlock_slow(omutex);
959 }
960#endif
961 _pthread_mutex *mutex = (_pthread_mutex *)omutex;
a0619f9c 962 if (os_unlikely(!_pthread_mutex_check_signature_fast(mutex))) {
964d3577
A
963 return _pthread_mutex_unlock_slow(omutex);
964 }
965
a0619f9c 966 uint64_t *tidaddr;
964d3577
A
967 MUTEX_GETTID_ADDR(mutex, &tidaddr);
968
a0619f9c 969 mutex_seq *seqaddr;
964d3577
A
970 MUTEX_GETSEQ_ADDR(mutex, &seqaddr);
971
a0619f9c
A
972 mutex_seq oldseq, newseq;
973 mutex_seq_load(seqaddr, &oldseq);
964d3577 974
a0619f9c
A
975 int numwaiters = diff_genseq(oldseq.lgenval, oldseq.ugenval);
976 if (os_unlikely(numwaiters == 0)) {
977 // spurious unlock (unlock of unlocked lock)
978 return 0;
979 }
964d3577 980
a0619f9c
A
981 // We're giving up the mutex one way or the other, so go ahead and
982 // update the owner to 0 so that once the CAS below succeeds, there
983 // is no stale ownership information. If the CAS of the seqaddr
984 // fails, we may loop, but it's still valid for the owner to be
985 // SWITCHING/0
986 os_atomic_store(tidaddr, 0, relaxed);
964d3577 987
a0619f9c
A
988 do {
989 newseq = oldseq;
990 newseq.ugenval += PTHRW_INC;
964d3577 991
a0619f9c
A
992 if (os_likely((oldseq.lgenval & PTHRW_COUNT_MASK) ==
993 (newseq.ugenval & PTHRW_COUNT_MASK))) {
994 // our unlock sequence matches to lock sequence, so if the
995 // CAS is successful, the mutex is unlocked
964d3577 996
a0619f9c
A
997 // do not reset Ibit, just K&E
998 newseq.lgenval &= ~(PTH_RWL_KBIT | PTH_RWL_EBIT);
999 } else {
1000 return _pthread_mutex_unlock_slow(omutex);
f1a1da6c 1001 }
a0619f9c
A
1002 } while (os_unlikely(!mutex_seq_atomic_cmpxchgv(seqaddr, &oldseq, &newseq,
1003 release)));
f1a1da6c
A
1004
1005 return 0;
1006}
1007
964d3577 1008
a0619f9c 1009PTHREAD_ALWAYS_INLINE
964d3577 1010static inline int
3a6437e6
A
1011_pthread_mutex_init(_pthread_mutex *mutex, const pthread_mutexattr_t *attr,
1012 uint32_t static_type)
f1a1da6c 1013{
3a6437e6
A
1014 mutex->mtxopts.value = 0;
1015 mutex->mtxopts.options.mutex = 1;
f1a1da6c
A
1016 if (attr) {
1017 if (attr->sig != _PTHREAD_MUTEX_ATTR_SIG) {
1018 return EINVAL;
1019 }
a0619f9c 1020 mutex->prioceiling = (int16_t)attr->prioceiling;
f1a1da6c
A
1021 mutex->mtxopts.options.protocol = attr->protocol;
1022 mutex->mtxopts.options.policy = attr->policy;
1023 mutex->mtxopts.options.type = attr->type;
1024 mutex->mtxopts.options.pshared = attr->pshared;
1025 } else {
1026 switch (static_type) {
1027 case 1:
1028 mutex->mtxopts.options.type = PTHREAD_MUTEX_ERRORCHECK;
1029 break;
1030 case 2:
1031 mutex->mtxopts.options.type = PTHREAD_MUTEX_RECURSIVE;
1032 break;
1033 case 3:
1034 /* firstfit fall thru */
1035 case 7:
1036 mutex->mtxopts.options.type = PTHREAD_MUTEX_DEFAULT;
1037 break;
1038 default:
1039 return EINVAL;
1040 }
1041
1042 mutex->prioceiling = _PTHREAD_DEFAULT_PRIOCEILING;
1043 mutex->mtxopts.options.protocol = _PTHREAD_DEFAULT_PROTOCOL;
1044 if (static_type != 3) {
1045 mutex->mtxopts.options.policy = _PTHREAD_MUTEX_POLICY_FAIRSHARE;
1046 } else {
1047 mutex->mtxopts.options.policy = _PTHREAD_MUTEX_POLICY_FIRSTFIT;
1048 }
1049 mutex->mtxopts.options.pshared = _PTHREAD_DEFAULT_PSHARED;
1050 }
f1a1da6c
A
1051 mutex->priority = 0;
1052
a0619f9c 1053 mutex_seq *seqaddr;
3a6437e6 1054 MUTEX_GETSEQ_ADDR(mutex, &seqaddr);
a0619f9c
A
1055
1056 uint64_t *tidaddr;
3a6437e6 1057 MUTEX_GETTID_ADDR(mutex, &tidaddr);
a0619f9c 1058
3a6437e6
A
1059#if PTHREAD_MUTEX_INIT_UNUSED
1060 if ((uint32_t*)tidaddr != mutex->m_tid) {
1061 mutex->mtxopts.options.misalign = 1;
1062 __builtin_memset(mutex->m_tid, 0xff, sizeof(mutex->m_tid));
964d3577 1063 }
3a6437e6
A
1064 __builtin_memset(mutex->m_mis, 0xff, sizeof(mutex->m_mis));
1065#endif // PTHREAD_MUTEX_INIT_UNUSED
1066 *tidaddr = 0;
a0619f9c 1067 *seqaddr = (mutex_seq){ };
964d3577
A
1068
1069 long sig = _PTHREAD_MUTEX_SIG;
1070 if (mutex->mtxopts.options.type == PTHREAD_MUTEX_NORMAL &&
1071 mutex->mtxopts.options.policy == _PTHREAD_MUTEX_POLICY_FAIRSHARE) {
1072 // rdar://18148854 _pthread_mutex_lock & pthread_mutex_unlock fastpath
1073 sig = _PTHREAD_MUTEX_SIG_fast;
1074 }
f1a1da6c 1075
3a6437e6
A
1076#if PTHREAD_MUTEX_INIT_UNUSED
1077 // For detecting copied mutexes and smashes during debugging
1078 uint32_t sig32 = (uint32_t)sig;
1079#if defined(__LP64__)
a0619f9c 1080 uintptr_t guard = ~(uintptr_t)mutex; // use ~ to hide from leaks
3a6437e6
A
1081 __builtin_memcpy(mutex->_reserved, &guard, sizeof(guard));
1082 mutex->_reserved[2] = sig32;
1083 mutex->_reserved[3] = sig32;
1084 mutex->_pad = sig32;
1085#else
1086 mutex->_reserved[0] = sig32;
1087#endif
1088#endif // PTHREAD_MUTEX_INIT_UNUSED
964d3577
A
1089
1090 // Ensure all contents are properly set before setting signature.
1091#if defined(__LP64__)
1092 // For binary compatibility reasons we cannot require natural alignment of
1093 // the 64bit 'sig' long value in the struct. rdar://problem/21610439
1094 uint32_t *sig32_ptr = (uint32_t*)&mutex->sig;
1095 uint32_t *sig32_val = (uint32_t*)&sig;
a0619f9c 1096 *(sig32_ptr + 1) = *(sig32_val + 1);
964d3577
A
1097 os_atomic_store(sig32_ptr, *sig32_val, release);
1098#else
1099 os_atomic_store2o(mutex, sig, sig, release);
1100#endif
f1a1da6c
A
1101
1102 return 0;
1103}
1104
a0619f9c 1105PTHREAD_NOEXPORT_VARIANT
f1a1da6c
A
1106int
1107pthread_mutex_destroy(pthread_mutex_t *omutex)
1108{
1109 _pthread_mutex *mutex = (_pthread_mutex *)omutex;
1110
1111 int res = EINVAL;
1112
2546420a 1113 _PTHREAD_LOCK(mutex->lock);
964d3577 1114 if (_pthread_mutex_check_signature(mutex)) {
a0619f9c 1115 mutex_seq *seqaddr;
f1a1da6c 1116 MUTEX_GETSEQ_ADDR(mutex, &seqaddr);
a0619f9c
A
1117
1118 mutex_seq seq;
1119 mutex_seq_load(seqaddr, &seq);
1120
1121 uint64_t *tidaddr;
f1a1da6c
A
1122 MUTEX_GETTID_ADDR(mutex, &tidaddr);
1123
a0619f9c
A
1124 if ((os_atomic_load(tidaddr, relaxed) == 0) &&
1125 (seq.lgenval & PTHRW_COUNT_MASK) ==
1126 (seq.ugenval & PTHRW_COUNT_MASK)) {
f1a1da6c
A
1127 mutex->sig = _PTHREAD_NO_SIG;
1128 res = 0;
1129 } else {
1130 res = EBUSY;
1131 }
964d3577 1132 } else if (_pthread_mutex_check_signature_init(mutex)) {
f1a1da6c
A
1133 mutex->sig = _PTHREAD_NO_SIG;
1134 res = 0;
1135 }
2546420a 1136 _PTHREAD_UNLOCK(mutex->lock);
f1a1da6c 1137
a0619f9c
A
1138 return res;
1139}
964d3577 1140
f1a1da6c
A
1141#endif /* !BUILDING_VARIANT ] */
1142
1143/*
1144 * Destroy a mutex attribute structure.
1145 */
1146int
1147pthread_mutexattr_destroy(pthread_mutexattr_t *attr)
1148{
1149#if __DARWIN_UNIX03
1150 if (__unix_conforming == 0) {
1151 __unix_conforming = 1;
1152 }
1153 if (attr->sig != _PTHREAD_MUTEX_ATTR_SIG) {
1154 return EINVAL;
1155 }
1156#endif /* __DARWIN_UNIX03 */
1157
1158 attr->sig = _PTHREAD_NO_SIG;
1159 return 0;
1160}
1161