]> git.saurik.com Git - apple/libc.git/blame - pthreads/pthread_mutex.c
Libc-763.13.tar.gz
[apple/libc.git] / pthreads / pthread_mutex.c
CommitLineData
9385eb3d 1/*
b5d655f7 2 * Copyright (c) 2000-2003, 2007, 2008 Apple Inc. All rights reserved.
9385eb3d
A
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
9385eb3d
A
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
e9ce8d39
A
23/*
24 * Copyright 1996 1995 by Open Software Foundation, Inc. 1997 1996 1995 1994 1993 1992 1991
25 * All Rights Reserved
26 *
27 * Permission to use, copy, modify, and distribute this software and
28 * its documentation for any purpose and without fee is hereby granted,
29 * provided that the above copyright notice appears in all copies and
30 * that both the copyright notice and this permission notice appear in
31 * supporting documentation.
32 *
33 * OSF DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
34 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
35 * FOR A PARTICULAR PURPOSE.
36 *
37 * IN NO EVENT SHALL OSF BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
38 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
39 * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
40 * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
41 * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
42 *
43 */
44/*
45 * MkLinux
46 */
47
48/*
49 * POSIX Pthread Library
50 * -- Mutex variable support
51 */
52
53#include "pthread_internals.h"
54
b5d655f7 55#ifdef PLOCKSTAT
224c7076 56#include "plockstat.h"
b5d655f7
A
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 */
224c7076
A
66
67extern int __unix_conforming;
34e8f829 68extern int __unix_conforming;
34e8f829 69
1f2f436a
A
70#ifndef BUILDING_VARIANT
71__private_extern__ int usenew_mtximpl = 1;
72static void __pthread_mutex_set_signature(npthread_mutex_t * mutex);
73int __mtx_markprepost(npthread_mutex_t *mutex, uint32_t oupdateval, int firstfit);
74static int _pthread_mutex_destroy_locked(pthread_mutex_t *omutex);
75#else /* BUILDING_VARIANT */
76extern int usenew_mtximpl;
77#endif /* BUILDING_VARIANT */
78
79
80#ifdef NOTNEEDED
34e8f829 81#define USE_COMPAGE 1
1f2f436a
A
82extern int _commpage_pthread_mutex_lock(uint32_t * lvalp, int flags, uint64_t mtid, uint32_t mask, uint64_t * tidp, int *sysret);
83#endif
34e8f829
A
84
85#include <machine/cpu_capabilities.h>
86
1f2f436a 87int _pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr, uint32_t static_type);
34e8f829 88
34e8f829
A
89
90#if defined(__LP64__)
91#define MUTEX_GETSEQ_ADDR(mutex, lseqaddr, useqaddr) \
92{ \
93 if (mutex->mtxopts.options.misalign != 0) { \
94 lseqaddr = &mutex->m_seq[0]; \
95 useqaddr = &mutex->m_seq[1]; \
96 } else { \
97 lseqaddr = &mutex->m_seq[1]; \
98 useqaddr = &mutex->m_seq[2]; \
99 } \
100}
101#else /* __LP64__ */
102#define MUTEX_GETSEQ_ADDR(mutex, lseqaddr, useqaddr) \
103{ \
104 if (mutex->mtxopts.options.misalign != 0) { \
105 lseqaddr = &mutex->m_seq[1]; \
106 useqaddr = &mutex->m_seq[2]; \
107 }else { \
108 lseqaddr = &mutex->m_seq[0]; \
109 useqaddr = &mutex->m_seq[1]; \
110 } \
111}
112#endif /* __LP64__ */
113
114#define _KSYN_TRACE_ 0
115
116#if _KSYN_TRACE_
117/* The Function qualifiers */
118#define DBG_FUNC_START 1
119#define DBG_FUNC_END 2
120#define DBG_FUNC_NONE 0
121
122int __kdebug_trace(uint32_t, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t);
123
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
1f2f436a 129#define _KSYN_TRACE_UM_MARKPP 0x90000a8
34e8f829
A
130
131#endif /* _KSYN_TRACE_ */
132
224c7076
A
133#ifndef BUILDING_VARIANT /* [ */
134
135#define BLOCK_FAIL_PLOCKSTAT 0
136#define BLOCK_SUCCESS_PLOCKSTAT 1
137
34e8f829
A
138#ifdef PR_5243343
139/* 5243343 - temporary hack to detect if we are running the conformance test */
140extern int PR_5243343_flag;
141#endif /* PR_5243343 */
142
224c7076
A
143/* This function is never called and exists to provide never-fired dtrace
144 * probes so that user d scripts don't get errors.
145 */
146__private_extern__ void _plockstat_never_fired(void)
147{
148 PLOCKSTAT_MUTEX_SPIN(NULL);
149 PLOCKSTAT_MUTEX_SPUN(NULL, 0, 0);
150}
151
e9ce8d39
A
152
153/*
154 * Initialize a mutex variable, possibly with additional attributes.
9385eb3d 155 * Public interface - so don't trust the lock - initialize it first.
e9ce8d39
A
156 */
157int
158pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr)
159{
224c7076
A
160#if 0
161 /* conformance tests depend on not having this behavior */
162 /* The test for this behavior is optional */
163 if (mutex->sig == _PTHREAD_MUTEX_SIG)
164 return EBUSY;
165#endif
9385eb3d 166 LOCK_INIT(mutex->lock);
1f2f436a 167 return (_pthread_mutex_init(mutex, attr, 0x7));
e9ce8d39
A
168}
169
170/*
171 * Fetch the priority ceiling value from a mutex variable.
172 * Note: written as a 'helper' function to hide implementation details.
173 */
174int
175pthread_mutex_getprioceiling(const pthread_mutex_t *mutex,
176 int *prioceiling)
177{
9385eb3d
A
178 int res;
179
180 LOCK(mutex->lock);
e9ce8d39
A
181 if (mutex->sig == _PTHREAD_MUTEX_SIG)
182 {
183 *prioceiling = mutex->prioceiling;
224c7076 184 res = 0;
e9ce8d39 185 } else
9385eb3d
A
186 res = EINVAL; /* Not an initialized 'attribute' structure */
187 UNLOCK(mutex->lock);
188 return (res);
e9ce8d39
A
189}
190
191/*
192 * Set the priority ceiling for a mutex.
193 * Note: written as a 'helper' function to hide implementation details.
194 */
195int
196pthread_mutex_setprioceiling(pthread_mutex_t *mutex,
197 int prioceiling,
198 int *old_prioceiling)
199{
9385eb3d
A
200 int res;
201
202 LOCK(mutex->lock);
e9ce8d39
A
203 if (mutex->sig == _PTHREAD_MUTEX_SIG)
204 {
205 if ((prioceiling >= -999) ||
206 (prioceiling <= 999))
207 {
208 *old_prioceiling = mutex->prioceiling;
209 mutex->prioceiling = prioceiling;
224c7076 210 res = 0;
e9ce8d39 211 } else
9385eb3d 212 res = EINVAL; /* Invalid parameter */
e9ce8d39 213 } else
9385eb3d
A
214 res = EINVAL; /* Not an initialized 'attribute' structure */
215 UNLOCK(mutex->lock);
216 return (res);
e9ce8d39
A
217}
218
e9ce8d39
A
219/*
220 * Get the priority ceiling value from a mutex attribute structure.
221 * Note: written as a 'helper' function to hide implementation details.
222 */
223int
224pthread_mutexattr_getprioceiling(const pthread_mutexattr_t *attr,
225 int *prioceiling)
226{
227 if (attr->sig == _PTHREAD_MUTEX_ATTR_SIG)
228 {
229 *prioceiling = attr->prioceiling;
224c7076 230 return (0);
e9ce8d39
A
231 } else
232 {
233 return (EINVAL); /* Not an initialized 'attribute' structure */
234 }
235}
236
237/*
238 * Get the mutex 'protocol' value from a mutex attribute structure.
239 * Note: written as a 'helper' function to hide implementation details.
240 */
241int
242pthread_mutexattr_getprotocol(const pthread_mutexattr_t *attr,
243 int *protocol)
244{
245 if (attr->sig == _PTHREAD_MUTEX_ATTR_SIG)
246 {
247 *protocol = attr->protocol;
224c7076 248 return (0);
e9ce8d39
A
249 } else
250 {
251 return (EINVAL); /* Not an initialized 'attribute' structure */
252 }
253}
5b2abdfb
A
254/*
255 * Get the mutex 'type' value from a mutex attribute structure.
256 * Note: written as a 'helper' function to hide implementation details.
257 */
258int
259pthread_mutexattr_gettype(const pthread_mutexattr_t *attr,
260 int *type)
261{
262 if (attr->sig == _PTHREAD_MUTEX_ATTR_SIG)
263 {
264 *type = attr->type;
224c7076 265 return (0);
5b2abdfb
A
266 } else
267 {
268 return (EINVAL); /* Not an initialized 'attribute' structure */
269 }
270}
271
272/*
273 *
274 */
275int
276pthread_mutexattr_getpshared(const pthread_mutexattr_t *attr, int *pshared)
277{
278 if (attr->sig == _PTHREAD_MUTEX_ATTR_SIG)
279 {
224c7076
A
280 *pshared = (int)attr->pshared;
281 return (0);
5b2abdfb
A
282 } else
283 {
284 return (EINVAL); /* Not an initialized 'attribute' structure */
285 }
286}
e9ce8d39
A
287
288/*
289 * Initialize a mutex attribute structure to system defaults.
290 */
291int
292pthread_mutexattr_init(pthread_mutexattr_t *attr)
293{
294 attr->prioceiling = _PTHREAD_DEFAULT_PRIOCEILING;
295 attr->protocol = _PTHREAD_DEFAULT_PROTOCOL;
34e8f829 296 attr->policy = _PTHREAD_MUTEX_POLICY_FAIRSHARE;
5b2abdfb 297 attr->type = PTHREAD_MUTEX_DEFAULT;
e9ce8d39 298 attr->sig = _PTHREAD_MUTEX_ATTR_SIG;
224c7076
A
299 attr->pshared = _PTHREAD_DEFAULT_PSHARED;
300 return (0);
e9ce8d39
A
301}
302
303/*
304 * Set the priority ceiling value in a mutex attribute structure.
305 * Note: written as a 'helper' function to hide implementation details.
306 */
307int
308pthread_mutexattr_setprioceiling(pthread_mutexattr_t *attr,
309 int prioceiling)
310{
311 if (attr->sig == _PTHREAD_MUTEX_ATTR_SIG)
312 {
313 if ((prioceiling >= -999) ||
314 (prioceiling <= 999))
315 {
316 attr->prioceiling = prioceiling;
224c7076 317 return (0);
e9ce8d39
A
318 } else
319 {
320 return (EINVAL); /* Invalid parameter */
321 }
322 } else
323 {
324 return (EINVAL); /* Not an initialized 'attribute' structure */
325 }
326}
327
328/*
329 * Set the mutex 'protocol' value in a mutex attribute structure.
330 * Note: written as a 'helper' function to hide implementation details.
331 */
332int
333pthread_mutexattr_setprotocol(pthread_mutexattr_t *attr,
334 int protocol)
335{
336 if (attr->sig == _PTHREAD_MUTEX_ATTR_SIG)
337 {
338 if ((protocol == PTHREAD_PRIO_NONE) ||
339 (protocol == PTHREAD_PRIO_INHERIT) ||
340 (protocol == PTHREAD_PRIO_PROTECT))
341 {
342 attr->protocol = protocol;
224c7076 343 return (0);
e9ce8d39
A
344 } else
345 {
346 return (EINVAL); /* Invalid parameter */
347 }
348 } else
349 {
350 return (EINVAL); /* Not an initialized 'attribute' structure */
351 }
352}
34e8f829 353
34e8f829
A
354int
355pthread_mutexattr_setpolicy_np(pthread_mutexattr_t *attr,
356 int policy)
357{
358 if (attr->sig == _PTHREAD_MUTEX_ATTR_SIG)
359 {
1f2f436a
A
360 if (
361 (policy == _PTHREAD_MUTEX_POLICY_FAIRSHARE) ||
362 (policy == _PTHREAD_MUTEX_POLICY_FIRSTFIT)
363#if NOTYET
364 ||
34e8f829
A
365 (policy == _PTHREAD_MUTEX_POLICY_REALTIME) ||
366 (policy == _PTHREAD_MUTEX_POLICY_ADAPTIVE) ||
367 (policy == _PTHREAD_MUTEX_POLICY_PRIPROTECT) ||
1f2f436a
A
368 (policy == _PTHREAD_MUTEX_POLICY_PRIINHERIT)
369#endif /* NOTYET */
370 )
34e8f829
A
371 {
372 attr->policy = policy;
373 return (0);
374 } else
375 {
376 return (EINVAL); /* Invalid parameter */
377 }
378 } else
379 {
380 return (EINVAL); /* Not an initialized 'attribute' structure */
381 }
382}
34e8f829 383
5b2abdfb
A
384/*
385 * Set the mutex 'type' value in a mutex attribute structure.
386 * Note: written as a 'helper' function to hide implementation details.
387 */
388int
389pthread_mutexattr_settype(pthread_mutexattr_t *attr,
390 int type)
391{
392 if (attr->sig == _PTHREAD_MUTEX_ATTR_SIG)
393 {
394 if ((type == PTHREAD_MUTEX_NORMAL) ||
395 (type == PTHREAD_MUTEX_ERRORCHECK) ||
396 (type == PTHREAD_MUTEX_RECURSIVE) ||
397 (type == PTHREAD_MUTEX_DEFAULT))
398 {
399 attr->type = type;
224c7076 400 return (0);
5b2abdfb
A
401 } else
402 {
403 return (EINVAL); /* Invalid parameter */
404 }
405 } else
406 {
407 return (EINVAL); /* Not an initialized 'attribute' structure */
408 }
409}
410
e9ce8d39
A
411
412int mutex_try_lock(int *x) {
413 return _spin_lock_try((pthread_lock_t *)x);
414}
415
416void mutex_wait_lock(int *x) {
417 for (;;) {
418 if( _spin_lock_try((pthread_lock_t *)x)) {
419 return;
420 }
421 swtch_pri(0);
422 }
423}
424
5b2abdfb
A
425void
426cthread_yield(void)
427{
428 sched_yield();
429}
430
431void
432pthread_yield_np (void)
433{
e9ce8d39
A
434 sched_yield();
435}
436
224c7076
A
437
438/*
439 * Temp: till pshared is fixed correctly
440 */
441int
442pthread_mutexattr_setpshared(pthread_mutexattr_t *attr, int pshared)
443{
444#if __DARWIN_UNIX03
445 if (__unix_conforming == 0)
446 __unix_conforming = 1;
447#endif /* __DARWIN_UNIX03 */
448
449 if (attr->sig == _PTHREAD_MUTEX_ATTR_SIG)
450 {
451#if __DARWIN_UNIX03
224c7076 452 if (( pshared == PTHREAD_PROCESS_PRIVATE) || (pshared == PTHREAD_PROCESS_SHARED))
224c7076
A
453#else /* __DARWIN_UNIX03 */
454 if ( pshared == PTHREAD_PROCESS_PRIVATE)
455#endif /* __DARWIN_UNIX03 */
1f2f436a 456 {
224c7076
A
457 attr->pshared = pshared;
458 return (0);
1f2f436a 459 } else {
224c7076
A
460 return (EINVAL); /* Invalid parameter */
461 }
462 } else
463 {
464 return (EINVAL); /* Not an initialized 'attribute' structure */
465 }
466}
467
34e8f829
A
468/*
469 * Drop the mutex unlock references(from cond wait or mutex_unlock().
34e8f829
A
470 *
471 */
472__private_extern__ int
1f2f436a 473__mtx_droplock(npthread_mutex_t * mutex, uint32_t diffgen, uint32_t * flagsp, uint32_t ** pmtxp, uint32_t * mgenp, uint32_t * ugenp)
34e8f829 474{
1f2f436a
A
475 pthread_t self;
476 uint64_t selfid, resettid;
34e8f829 477 int firstfit = (mutex->mtxopts.options.policy == _PTHREAD_MUTEX_POLICY_FIRSTFIT);
1f2f436a
A
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;
34e8f829
A
482
483#if _KSYN_TRACE_
1f2f436a 484 (void)__kdebug_trace(_KSYN_TRACE_UM_MDROP | DBG_FUNC_START, (uint32_t)mutex, diffgen, 0, 0, 0);
34e8f829 485#endif
1f2f436a 486 MUTEX_GETSEQ_ADDR(mutex, lseqaddr, useqaddr);
34e8f829 487
1f2f436a
A
488
489 flags = mutex->mtxopts.value;
490 flags &= ~_PTHREAD_MTX_OPT_NOTIFY; /* no notification by default */
491
492
34e8f829
A
493 if (mutex->mtxopts.options.type != PTHREAD_MUTEX_NORMAL)
494 {
1f2f436a
A
495 self = pthread_self();
496 (void) pthread_threadid_np(self, &selfid);
497
498 if (mutex->m_tid != selfid)
34e8f829 499 {
1f2f436a 500 //LIBC_ABORT("dropping recur or error mutex not owned by the thread\n");
34e8f829
A
501 PLOCKSTAT_MUTEX_ERROR((pthread_mutex_t *)mutex, EPERM);
502 return(EPERM);
503 } else if (mutex->mtxopts.options.type == PTHREAD_MUTEX_RECURSIVE &&
504 --mutex->mtxopts.options.lock_count)
505 {
506 PLOCKSTAT_MUTEX_RELEASE((pthread_mutex_t *)mutex, 1);
507 goto out;
508 }
509 }
510
511
1f2f436a
A
512retry:
513 lgenval = *lseqaddr;
514 ugenval = *useqaddr;
515
516 numwaiters = diff_genseq((lgenval & PTHRW_COUNT_MASK),(ugenval & PTHRW_COUNT_MASK)); /* pendig waiters */
517
518 if (numwaiters == 0) {
519 /* spurious unlocks, do not touch tid */
520 oldval64 = (((uint64_t)ugenval) << 32);
521 oldval64 |= lgenval;
522 if ((firstfit != 0) && ((lgenval & PTH_RWL_PBIT) != 0)) {
523 clearprepost = 1;
524 lgenval &= ~PTH_RWL_PBIT;
525 newval64 = (((uint64_t)ugenval) << 32);
526 newval64 |= lgenval;
527 } else
528 newval64 = oldval64;
529 if (OSAtomicCompareAndSwap64(oldval64, newval64, (volatile int64_t *)lseqaddr) != TRUE)
530 goto retry;
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));
535
536 goto out;
537 }
34e8f829 538
1f2f436a 539 if (numwaiters < diffgen) {
34e8f829 540#if _KSYN_TRACE_
1f2f436a 541 (void)__kdebug_trace(_KSYN_TRACE_UM_MDROP | DBG_FUNC_NONE, (uint32_t)mutex, numwaiters, lgenval, ugenval, 0);
34e8f829 542#endif
1f2f436a
A
543 /* cannot drop more than existing number of waiters */
544 diffgen = numwaiters;
545 }
34e8f829 546
1f2f436a
A
547 oldval64 = (((uint64_t)ugenval) << 32);
548 oldval64 |= lgenval;
549 ulval = ugenval + diffgen;
550 nlval = lgenval;
551
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)) {
557 clearprepost = 1;
558 nlval &= ~PTH_RWL_PBIT;
34e8f829 559 }
1f2f436a
A
560 } else {
561 /* need to signal others waiting for mutex */
562 morewaiters = 1;
563 flags |= _PTHREAD_MTX_OPT_NOTIFY;
564 }
34e8f829 565
1f2f436a
A
566 if (((nlval & PTH_RWL_EBIT) != 0) && (firstfit != 0)) {
567 nlval &= ~PTH_RWL_EBIT; /* reset Ebit so another can acquire meanwhile */
568 }
34e8f829 569
1f2f436a
A
570 newval64 = (((uint64_t)ulval) << 32);
571 newval64 |= nlval;
34e8f829 572
1f2f436a
A
573 resettid = mutex->m_tid;
574
575 if ((lgenval & PTHRW_COUNT_MASK) == (ulval & PTHRW_COUNT_MASK))
576 mutex->m_tid = 0;
577 else if (firstfit == 0)
578 mutex->m_tid = PTHREAD_MTX_TID_SWITCHING;
579
580 if (OSAtomicCompareAndSwap64(oldval64, newval64, (volatile int64_t *)lseqaddr) != TRUE) {
581 mutex->m_tid = resettid;
582 goto retry;
583 }
34e8f829 584
34e8f829
A
585
586#if _KSYN_TRACE_
1f2f436a
A
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);
34e8f829 589#endif
34e8f829 590
1f2f436a
A
591 if (clearprepost != 0) {
592 __psynch_cvclrprepost(mutex, nlval, ulval, 0, 0, nlval, (flags | _PTHREAD_MTX_OPT_MUTEX));
34e8f829 593 }
1f2f436a
A
594
595 if (mgenp != NULL)
596 *mgenp = nlval;
597 if (ugenp != NULL)
598 *ugenp = ulval;
599#if USE_COMPAGE
600 if (pmtxp != NULL)
601 *pmtxp = lseqaddr;
602#else
603 if (pmtxp != NULL)
604 *pmtxp = (uint32_t *)mutex;
605#endif
606
34e8f829 607out:
1f2f436a
A
608 if (flagsp != NULL)
609 *flagsp = flags;
610
34e8f829 611#if _KSYN_TRACE_
1f2f436a 612 (void)__kdebug_trace(_KSYN_TRACE_UM_MDROP | DBG_FUNC_END, (uint32_t)mutex, flags, 0, 0, 0);
34e8f829
A
613#endif
614 return(0);
615}
616
617int
1f2f436a 618__mtx_updatebits(npthread_mutex_t *mutex, uint32_t oupdateval, int firstfit, int fromcond, uint64_t selfid)
34e8f829 619{
34e8f829 620 uint32_t updateval = oupdateval;
1f2f436a 621#if !USE_COMPAGE
34e8f829 622 pthread_mutex_t * omutex = (pthread_mutex_t *)mutex;
1f2f436a
A
623#endif
624 int isebit = 0;
625 uint32_t lgenval, ugenval, nval, uval, bits;
626 volatile uint32_t * lseqaddr, *useqaddr;
627 uint64_t oldval64, newval64;
628
629 MUTEX_GETSEQ_ADDR(mutex, lseqaddr, useqaddr);
34e8f829 630
34e8f829
A
631#if _KSYN_TRACE_
632 (void)__kdebug_trace(_KSYN_TRACE_UM_MUBITS | DBG_FUNC_START, (uint32_t)mutex, oupdateval, firstfit, fromcond, 0);
633#endif
634
635retry:
636 lgenval = *lseqaddr;
1f2f436a 637 ugenval = *useqaddr;
34e8f829
A
638 bits = updateval & PTHRW_BIT_MASK;
639
34e8f829 640#if _KSYN_TRACE_
1f2f436a 641 (void)__kdebug_trace(_KSYN_TRACE_UM_MUBITS | DBG_FUNC_NONE, (uint32_t)mutex, 1, lgenval, ugenval, 0);
34e8f829 642#endif
34e8f829 643
1f2f436a
A
644
645 if ((updateval & PTH_RWL_MTX_WAIT) != 0) {
646 lgenval = (updateval & PTHRW_COUNT_MASK) | (lgenval & PTHRW_BIT_MASK);
647 if (fromcond == 0) {
648 /* if from mutex_lock(), it will handle the rewind */
649 return(1);
650 }
651 /* go block in the kernel with same lgenval as returned */
652 goto ml1;
653 } else {
654 /* firsfit might not have EBIT */
655 if (firstfit != 0) {
656 if ((lgenval & PTH_RWL_EBIT) != 0)
657 isebit = 1;
658 else
659 isebit = 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 */
662 goto out;
663 }
34e8f829
A
664 }
665
1f2f436a
A
666 /* either firstfist or no E bit set */
667 /* update the bits */
668 oldval64 = (((uint64_t)ugenval) << 32);
669 oldval64 |= lgenval;
670 uval = ugenval;
671 nval = lgenval | (PTH_RWL_KBIT|PTH_RWL_EBIT);
672 newval64 = (((uint64_t)uval) << 32);
673 newval64 |= nval;
674
675 /* set s and b bit */
676 if (OSAtomicCompareAndSwap64(oldval64, newval64, (volatile int64_t *)lseqaddr) == TRUE) {
34e8f829 677#if _KSYN_TRACE_
1f2f436a 678 (void)__kdebug_trace(_KSYN_TRACE_UM_MUBITS | DBG_FUNC_NONE, (uint32_t)mutex, 2, nval, uval, 0);
34e8f829 679#endif
1f2f436a 680 if ((firstfit != 0) && (isebit != 0))
34e8f829 681 goto handleffit;
34e8f829 682
1f2f436a
A
683 goto out;
684 } else {
685 if (firstfit == 0)
686 goto retry;
687 else
688 goto handleffit;
34e8f829 689 }
1f2f436a 690
34e8f829 691#if _KSYN_TRACE_
1f2f436a 692 (void)__kdebug_trace(_KSYN_TRACE_UM_MUBITS | DBG_FUNC_NONE, (uint32_t)mutex, 4, nval, uval, 0);
34e8f829 693#endif
1f2f436a 694
34e8f829
A
695out:
696 /* succesful bits updation */
1f2f436a 697 mutex->m_tid = selfid;
34e8f829
A
698#if _KSYN_TRACE_
699 (void)__kdebug_trace(_KSYN_TRACE_UM_MUBITS | DBG_FUNC_END, (uint32_t)mutex, 0, 0, 0, 0);
700#endif
701 return(0);
702
703handleffit:
704 /* firstfit failure */
1f2f436a
A
705 lgenval = *lseqaddr;
706 ugenval = *useqaddr;
707 if ((lgenval & PTH_RWL_EBIT) == 0)
34e8f829 708 goto retry;
1f2f436a
A
709
710 if (fromcond == 0)
711 return(1);
712 else {
713 /* called from condition variable code block again */
34e8f829
A
714ml1:
715#if USE_COMPAGE /* [ */
1f2f436a
A
716 updateval = __psynch_mutexwait((pthread_mutex_t *)lseqaddr, lgenval | PTH_RWL_RETRYBIT, ugenval, mutex->m_tid,
717 mutex->mtxopts.value);
34e8f829 718#else /* USECOMPAGE ][ */
1f2f436a
A
719 updateval = __psynch_mutexwait(omutex, lgenval | PTH_RWL_RETRYBIT, ugenval, mutex->m_tid,
720 mutex->mtxopts.value);
34e8f829 721#endif /* USE_COMPAGE ] */
1f2f436a
A
722 if (updateval == (uint32_t)-1) {
723 goto ml1;
34e8f829 724 }
1f2f436a
A
725
726 /* now update the bits */
727 goto retry;
34e8f829 728 }
1f2f436a 729 /* cannot reach */
34e8f829
A
730 goto retry;
731}
732
1f2f436a 733
34e8f829 734int
1f2f436a
A
735__mtx_markprepost(npthread_mutex_t *mutex, uint32_t oupdateval, int firstfit)
736{
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;
742
743 MUTEX_GETSEQ_ADDR(mutex, lseqaddr, useqaddr);
744
745#if _KSYN_TRACE_
746 (void)__kdebug_trace(_KSYN_TRACE_UM_MARKPP | DBG_FUNC_START, (uint32_t)mutex, oupdateval, firstfit, 0, 0);
747#endif
748
749retry:
750
751
752
753 if ((firstfit != 0) && ((updateval & PTH_RWL_PBIT) != 0)) {
754 flags = mutex->mtxopts.value;
755
756 lgenval = *lseqaddr;
757 ugenval = *useqaddr;
758
759#if _KSYN_TRACE_
760 (void)__kdebug_trace(_KSYN_TRACE_UM_MARKPP | DBG_FUNC_NONE, (uint32_t)mutex, 1, lgenval, ugenval, 0);
761#endif
762 /* update the bits */
763 oldval64 = (((uint64_t)ugenval) << 32);
764 oldval64 |= lgenval;
765
766 if ((lgenval & PTHRW_COUNT_MASK) == (ugenval & PTHRW_COUNT_MASK)) {
767 clearprepost = 1;
768 lgenval &= ~PTH_RWL_PBIT;
769
770 } else {
771 lgenval |= PTH_RWL_PBIT;
772 }
773 newval64 = (((uint64_t)ugenval) << 32);
774 newval64 |= lgenval;
775
776 if (OSAtomicCompareAndSwap64(oldval64, newval64, (volatile int64_t *)lseqaddr) == TRUE) {
777#if _KSYN_TRACE_
778 (void)__kdebug_trace(_KSYN_TRACE_UM_MARKPP | DBG_FUNC_NONE, (uint32_t)mutex, 2, lgenval, ugenval, 0);
779#endif
780
781 if (clearprepost != 0)
782 __psynch_cvclrprepost(mutex, lgenval, ugenval, 0, 0, lgenval, (flags | _PTHREAD_MTX_OPT_MUTEX));
783
784 } else {
785 goto retry;
786 }
787
788#if _KSYN_TRACE_
789 (void)__kdebug_trace(_KSYN_TRACE_UM_MARKPP | DBG_FUNC_END, (uint32_t)mutex, 0, 0, 0, 0);
790#endif
791 }
792 return(0);
793}
794
795/*
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.
799 */
800static void
801__pthread_mutex_set_signature(npthread_mutex_t * mutex)
802{
803 mutex->sig = _PTHREAD_MUTEX_SIG;
804}
805
806int
807pthread_mutex_lock(pthread_mutex_t *omutex)
34e8f829
A
808{
809 pthread_t self;
1f2f436a 810 uint64_t selfid;
34e8f829
A
811 npthread_mutex_t * mutex = (npthread_mutex_t *)omutex;
812 int sig = mutex->sig;
1f2f436a
A
813#if NEVERINCOMPAGE || !USE_COMPAGE
814 //uint32_t oldval, newval;
815#endif
34e8f829 816 int retval;
1f2f436a
A
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;
34e8f829 821#if USE_COMPAGE
34e8f829
A
822 int sysret = 0;
823 uint32_t mask;
824#else
1f2f436a 825 int retrybit = 0;
34e8f829
A
826#endif
827
828 /* To provide backwards compat for apps using mutex incorrectly */
1f2f436a 829 if ((sig != _PTHREAD_MUTEX_SIG) && ((sig & _PTHREAD_MUTEX_SIG_init_MASK) != _PTHREAD_MUTEX_SIG_CMP)) {
34e8f829
A
830 PLOCKSTAT_MUTEX_ERROR(omutex, EINVAL);
831 return(EINVAL);
832 }
1f2f436a 833 if (mutex->sig != _PTHREAD_MUTEX_SIG) {
34e8f829 834 LOCK(mutex->lock);
1f2f436a
A
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){
838 UNLOCK(mutex->lock);
839 PLOCKSTAT_MUTEX_ERROR(omutex, retval);
840 return(retval);
841 }
842 } else if (mutex->sig != _PTHREAD_MUTEX_SIG) {
34e8f829
A
843 UNLOCK(mutex->lock);
844 PLOCKSTAT_MUTEX_ERROR(omutex, EINVAL);
845 return(EINVAL);
846 }
847 UNLOCK(mutex->lock);
848 }
849
850#if _KSYN_TRACE_
851 (void)__kdebug_trace(_KSYN_TRACE_UM_LOCK | DBG_FUNC_START, (uint32_t)mutex, 0, 0, 0, 0);
852#endif
1f2f436a 853 MUTEX_GETSEQ_ADDR(mutex, lseqaddr, useqaddr);
34e8f829
A
854
855 self = pthread_self();
1f2f436a
A
856 (void) pthread_threadid_np(self, &selfid);
857
34e8f829 858 if (mutex->mtxopts.options.type != PTHREAD_MUTEX_NORMAL) {
1f2f436a 859 if (mutex->m_tid == selfid) {
34e8f829
A
860 if (mutex->mtxopts.options.type == PTHREAD_MUTEX_RECURSIVE)
861 {
862 if (mutex->mtxopts.options.lock_count < USHRT_MAX)
863 {
864 mutex->mtxopts.options.lock_count++;
865 PLOCKSTAT_MUTEX_ACQUIRE(omutex, 1, 0);
866 retval = 0;
867 } else {
868 retval = EAGAIN;
869 PLOCKSTAT_MUTEX_ERROR(omutex, retval);
870 }
871 } else { /* PTHREAD_MUTEX_ERRORCHECK */
872 retval = EDEADLK;
873 PLOCKSTAT_MUTEX_ERROR(omutex, retval);
874 }
875 return (retval);
876 }
877 }
1f2f436a 878
34e8f829
A
879#if _KSYN_TRACE_
880 (void)__kdebug_trace(_KSYN_TRACE_UM_LOCK | DBG_FUNC_NONE, (uint32_t)mutex, 1, 0, 0, 0);
881#endif
34e8f829 882
1f2f436a 883#if USE_COMPAGE /* [ */
34e8f829
A
884
885ml0:
1f2f436a
A
886 mask = PTH_RWL_EBIT;
887 retval = _commpage_pthread_mutex_lock(lseqaddr, mutex->mtxopts.value, selfid, mask, &mutex->m_tid, &sysret);
34e8f829
A
888 if (retval == 0) {
889 gotlock = 1;
890 } else if (retval == 1) {
891 gotlock = 1;
892 updateval = sysret;
893 /* returns 0 on succesful update */
1f2f436a 894 if (__mtx_updatebits( mutex, updateval, firstfit, 0, selfid) == 1) {
34e8f829
A
895 /* could not acquire, may be locked in ffit case */
896#if USE_COMPAGE
897 LIBC_ABORT("comapge implementatin looping in libc \n");
898#endif
899 goto ml0;
900 }
901 }
902#if NEVERINCOMPAGE
903 else if (retval == 3) {
904 cthread_set_errno_self(sysret);
905 oldval = *lseqaddr;
906 uval = *useqaddr;
907 newval = oldval + PTHRW_INC;
908 gotlock = 0;
909 /* to block in the kerenl again */
910 }
911#endif
912 else {
1f2f436a 913 LIBC_ABORT("comapge implementation bombed \n");
34e8f829
A
914 }
915
916
917#else /* USECOMPAGE ][ */
1f2f436a
A
918retry:
919 lgenval = *lseqaddr;
920 ugenval = *useqaddr;
34e8f829 921
1f2f436a
A
922#if _KSYN_TRACE_
923 (void)__kdebug_trace(_KSYN_TRACE_UM_LOCK | DBG_FUNC_NONE, (uint32_t)mutex, 2, lgenval, ugenval, 0);
924#endif /* _KSYN_TRACE_ */
34e8f829 925
1f2f436a 926 if((lgenval & PTH_RWL_EBIT) == 0) {
34e8f829 927 gotlock = 1;
34e8f829
A
928 } else {
929 gotlock = 0;
34e8f829 930 }
1f2f436a
A
931
932 oldval64 = (((uint64_t)ugenval) << 32);
933 oldval64 |= lgenval;
934 uval = ugenval;
935 nval = (lgenval + PTHRW_INC) | (PTH_RWL_EBIT|PTH_RWL_KBIT);
936 newval64 = (((uint64_t)uval) << 32);
937 newval64 |= nval;
938
939 if (OSAtomicCompareAndSwap64(oldval64, newval64, (volatile int64_t *)lseqaddr) == TRUE) {
34e8f829 940#if _KSYN_TRACE_
1f2f436a 941 (void)__kdebug_trace(_KSYN_TRACE_UM_LOCK | DBG_FUNC_NONE, (uint32_t)mutex, 2, nval, uval, 0);
34e8f829 942#endif
1f2f436a
A
943 if (gotlock != 0) {
944 mutex->m_tid = selfid;
945 goto out;
946 }
34e8f829 947 } else
1f2f436a 948 goto retry;
34e8f829
A
949
950
951 retrybit = 0;
952 if (gotlock == 0) {
953#if _KSYN_TRACE_
1f2f436a 954 (void)__kdebug_trace(_KSYN_TRACE_UM_LOCK | DBG_FUNC_NONE, (uint32_t)mutex, 3, nval, uval, 0);
34e8f829
A
955#endif
956 firstfit = (mutex->mtxopts.options.policy == _PTHREAD_MUTEX_POLICY_FIRSTFIT);
957ml1:
1f2f436a 958 updateval = __psynch_mutexwait(omutex, nval | retrybit, uval, mutex->m_tid,
34e8f829
A
959 mutex->mtxopts.value);
960
1f2f436a
A
961#if _KSYN_TRACE_
962 (void)__kdebug_trace(_KSYN_TRACE_UM_LOCK | DBG_FUNC_NONE, (uint32_t)mutex, 4, updateval, 0, 0);
963#endif
34e8f829 964 if (updateval == (uint32_t)-1) {
34e8f829
A
965 goto ml1;
966 }
967
1f2f436a
A
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) {
34e8f829 970 /* could not acquire, may be locked in ffit case */
1f2f436a 971 retrybit = PTH_RWL_RETRYBIT;
34e8f829
A
972#if USE_COMPAGE
973 LIBC_ABORT("comapge implementatin looping in libc \n");
974
975#endif
976 goto ml1;
977 }
978 }
979#endif /* USE_COMPAGE ] */
980
1f2f436a 981out:
34e8f829 982 if (mutex->mtxopts.options.type == PTHREAD_MUTEX_RECURSIVE)
1f2f436a 983 mutex->mtxopts.options.lock_count = 1;
34e8f829
A
984
985#if _KSYN_TRACE_
986 (void)__kdebug_trace(_KSYN_TRACE_UM_LOCK | DBG_FUNC_END, (uint32_t)mutex, 0, 0, 0, 0);
987#endif
988 return (0);
989}
990
991/*
992 * Attempt to lock a mutex, but don't block if this isn't possible.
993 */
994int
1f2f436a 995pthread_mutex_trylock(pthread_mutex_t *omutex)
34e8f829
A
996{
997 npthread_mutex_t * mutex = (npthread_mutex_t *)omutex;
998 int sig = mutex->sig;
34e8f829
A
999 int error = 0;
1000 pthread_t self;
1f2f436a
A
1001 uint64_t selfid;
1002 int gotlock = 0;
1003 uint32_t lgenval, ugenval, nval, uval;
1004 volatile uint32_t * lseqaddr, *useqaddr;
1005 uint64_t oldval64, newval64;
34e8f829
A
1006
1007 /* To provide backwards compat for apps using mutex incorrectly */
1f2f436a 1008 if ((sig != _PTHREAD_MUTEX_SIG) && ((sig & _PTHREAD_MUTEX_SIG_init_MASK) != _PTHREAD_MUTEX_SIG_CMP)) {
34e8f829
A
1009 PLOCKSTAT_MUTEX_ERROR(omutex, EINVAL);
1010 return(EINVAL);
1011 }
1012
1f2f436a 1013 if ((mutex->sig & _PTHREAD_MUTEX_SIG_init_MASK) == _PTHREAD_MUTEX_SIG_CMP) {
34e8f829 1014 LOCK(mutex->lock);
1f2f436a 1015 if (mutex->sig == _PTHREAD_MUTEX_SIG_init) {
34e8f829 1016 /* static initializer, init the mutex */
1f2f436a
A
1017 if((error = _pthread_mutex_init(omutex, NULL, (mutex->sig & 0xf))) != 0){
1018 UNLOCK(mutex->lock);
1019 PLOCKSTAT_MUTEX_ERROR(omutex, error);
1020 return(error);
1021 }
1022 } else if (mutex->sig != _PTHREAD_MUTEX_SIG) {
34e8f829
A
1023 UNLOCK(mutex->lock);
1024 PLOCKSTAT_MUTEX_ERROR(omutex, EINVAL);
1025 return(EINVAL);
1026 }
1027 UNLOCK(mutex->lock);
1028 }
1029
1f2f436a 1030 MUTEX_GETSEQ_ADDR(mutex, lseqaddr, useqaddr);
34e8f829
A
1031
1032 self = pthread_self();
1f2f436a
A
1033 (void) pthread_threadid_np(self, &selfid);
1034
34e8f829 1035 if (mutex->mtxopts.options.type != PTHREAD_MUTEX_NORMAL) {
1f2f436a 1036 if (mutex->m_tid == selfid) {
34e8f829
A
1037 if (mutex->mtxopts.options.type == PTHREAD_MUTEX_RECURSIVE)
1038 {
1039 if (mutex->mtxopts.options.lock_count < USHRT_MAX)
1040 {
1041 mutex->mtxopts.options.lock_count++;
1042 PLOCKSTAT_MUTEX_ACQUIRE(omutex, 1, 0);
1043 error = 0;
1044 } else {
1045 error = EAGAIN;
1046 PLOCKSTAT_MUTEX_ERROR(omutex, error);
1047 }
1048 } else { /* PTHREAD_MUTEX_ERRORCHECK */
1049 error = EDEADLK;
1050 PLOCKSTAT_MUTEX_ERROR(omutex, error);
1051 }
1052 return (error);
1053 }
1054 }
1f2f436a
A
1055retry:
1056 lgenval = *lseqaddr;
1057 ugenval = *useqaddr;
1058
1059#if _KSYN_TRACE_
1060 (void)__kdebug_trace(_KSYN_TRACE_UM_LOCK | DBG_FUNC_NONE, (uint32_t)mutex, 2, lgenval, ugenval, 0);
1061#endif /* _KSYN_TRACE_ */
1062
34e8f829 1063
1f2f436a
A
1064 oldval64 = (((uint64_t)ugenval) << 32);
1065 oldval64 |= lgenval;
1066 uval = ugenval;
1067
1068 /* if we can acquire go ahead otherwise ensure it is still busy */
1069 if((lgenval & PTH_RWL_EBIT) == 0) {
1070 gotlock = 1;
1071 nval = (lgenval + PTHRW_INC) | (PTH_RWL_EBIT|PTH_RWL_KBIT);
34e8f829 1072 } else {
1f2f436a
A
1073 nval = (lgenval | PTH_RWL_TRYLKBIT);
1074 gotlock = 0;
34e8f829 1075 }
1f2f436a
A
1076
1077 newval64 = (((uint64_t)uval) << 32);
1078 newval64 |= nval;
1079
1080 /* set s and b bit */
1081 if (OSAtomicCompareAndSwap64(oldval64, newval64, (volatile int64_t *)lseqaddr) == TRUE) {
1082#if _KSYN_TRACE_
1083 (void)__kdebug_trace(_KSYN_TRACE_UM_LOCK | DBG_FUNC_NONE, (uint32_t)mutex, 2, nval, uval, 0);
1084#endif
1085 if (gotlock != 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);
1090 } else {
1091 error = EBUSY;
1092 PLOCKSTAT_MUTEX_ERROR(omutex, error);
1093 }
1094 } else
1095 goto retry;
34e8f829 1096
1f2f436a
A
1097
1098#if _KSYN_TRACE_
1099 (void)__kdebug_trace(_KSYN_TRACE_UM_LOCK | DBG_FUNC_END, (uint32_t)mutex, 0xfafafafa, 0, error, 0);
1100#endif
1101 return (error);
34e8f829
A
1102}
1103
1104/*
1105 * Unlock a mutex.
1106 * TODO: Priority inheritance stuff
1107 */
1108int
1f2f436a 1109pthread_mutex_unlock(pthread_mutex_t *omutex)
34e8f829
A
1110{
1111 npthread_mutex_t * mutex = (npthread_mutex_t *)omutex;
1112 int retval;
1f2f436a 1113 uint32_t mtxgen, mtxugen, flags, notify, updateval;
34e8f829 1114 int sig = mutex->sig;
1f2f436a
A
1115 pthread_t self;
1116 uint64_t selfid;
1117 volatile uint32_t * lseqaddr, *useqaddr;
1118 int firstfit = 0;
34e8f829
A
1119
1120 /* To provide backwards compat for apps using mutex incorrectly */
1121
1122#if _KSYN_TRACE_
1123 (void)__kdebug_trace(_KSYN_TRACE_UM_UNLOCK | DBG_FUNC_START, (uint32_t)mutex, 0, 0, 0, 0);
1124#endif
1f2f436a 1125 if ((sig != _PTHREAD_MUTEX_SIG) && ((sig & _PTHREAD_MUTEX_SIG_init_MASK) != _PTHREAD_MUTEX_SIG_CMP)) {
34e8f829
A
1126 PLOCKSTAT_MUTEX_ERROR(omutex, EINVAL);
1127 return(EINVAL);
1128 }
1f2f436a
A
1129
1130 if (mutex->sig != _PTHREAD_MUTEX_SIG) {
34e8f829 1131 LOCK(mutex->lock);
1f2f436a 1132 if ((mutex->sig & _PTHREAD_MUTEX_SIG_init_MASK) == _PTHREAD_MUTEX_SIG_CMP) {
34e8f829 1133 /* static initializer, init the mutex */
1f2f436a
A
1134 if((retval = _pthread_mutex_init(omutex, NULL, (mutex->sig & 0xf))) != 0){
1135 UNLOCK(mutex->lock);
1136 PLOCKSTAT_MUTEX_ERROR(omutex, retval);
1137 return(retval);
1138 }
1139 } else if (mutex->sig != _PTHREAD_MUTEX_SIG) {
34e8f829
A
1140 UNLOCK(mutex->lock);
1141 PLOCKSTAT_MUTEX_ERROR(omutex, EINVAL);
1142 return(EINVAL);
1143 }
1144 UNLOCK(mutex->lock);
1145 }
1f2f436a
A
1146
1147 MUTEX_GETSEQ_ADDR(mutex, lseqaddr, useqaddr);
1148
34e8f829 1149 notify = 0;
1f2f436a 1150 retval = __mtx_droplock(mutex, PTHRW_INC, &flags, NULL, &mtxgen, &mtxugen);
34e8f829
A
1151 if (retval != 0)
1152 return(retval);
1153
1f2f436a
A
1154 if ((flags & _PTHREAD_MTX_OPT_NOTIFY) != 0) {
1155 firstfit = (mutex->mtxopts.options.policy == _PTHREAD_MUTEX_POLICY_FIRSTFIT);
1156
1157 self = pthread_self();
1158 (void) pthread_threadid_np(self, &selfid);
1159
34e8f829 1160#if _KSYN_TRACE_
1f2f436a 1161 (void)__kdebug_trace(_KSYN_TRACE_UM_UNLOCK | DBG_FUNC_NONE, (uint32_t)mutex, 1, mtxgen, mtxugen, 0);
34e8f829
A
1162#endif
1163#if USE_COMPAGE /* [ */
1f2f436a 1164 if ((updateval = __psynch_mutexdrop((pthread_mutex_t *)lseqaddr, mtxgen, mtxugen, mutex->m_tid, flags)) == (uint32_t)-1)
34e8f829 1165#else /* USECOMPAGE ][ */
1f2f436a 1166 if ((updateval = __psynch_mutexdrop(omutex, mtxgen, mtxugen, mutex->m_tid, flags))== (uint32_t)-1)
34e8f829
A
1167#endif /* USE_COMPAGE ] */
1168 {
1f2f436a
A
1169 retval = errno;
1170#if _KSYN_TRACE_
1171 (void)__kdebug_trace(_KSYN_TRACE_UM_UNLOCK | DBG_FUNC_END, (uint32_t)mutex, retval, 0, 0, 0);
1172#endif
1173 if (retval == 0)
34e8f829 1174 return(0);
1f2f436a
A
1175 else if (errno == EINTR)
1176 return(0);
1177 else {
1178 LIBC_ABORT("__p_mutexdrop failed with error %d\n", retval);
1179 return(retval);
1180 }
1181 } else if (firstfit == 1) {
1182 if ((updateval & PTH_RWL_PBIT) != 0) {
1183 __mtx_markprepost(mutex, updateval, firstfit);
1184 }
34e8f829
A
1185 }
1186 }
1187#if _KSYN_TRACE_
1188 (void)__kdebug_trace(_KSYN_TRACE_UM_UNLOCK | DBG_FUNC_END, (uint32_t)mutex, 0, 0, 0, 0);
1189#endif
1190 return(0);
1191}
1192
1193
1194/*
1195 * Initialize a mutex variable, possibly with additional attributes.
1196 */
1197int
1f2f436a 1198_pthread_mutex_init(pthread_mutex_t *omutex, const pthread_mutexattr_t *attr, uint32_t static_type)
34e8f829
A
1199{
1200 npthread_mutex_t * mutex = (npthread_mutex_t *)omutex;
1201
1202 if (attr)
1203 {
1204 if (attr->sig != _PTHREAD_MUTEX_ATTR_SIG)
1205 return (EINVAL);
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;
1211 } else {
1f2f436a
A
1212 switch(static_type) {
1213 case 1:
1214 mutex->mtxopts.options.type = PTHREAD_MUTEX_ERRORCHECK;
1215 break;
1216 case 2:
1217 mutex->mtxopts.options.type = PTHREAD_MUTEX_RECURSIVE;
1218 break;
1219 case 3:
1220 /* firstfit fall thru */
1221 case 7:
1222 mutex->mtxopts.options.type = PTHREAD_MUTEX_DEFAULT;
1223 break;
1224 default:
1225 return(EINVAL);
1226 }
1227
34e8f829
A
1228 mutex->prioceiling = _PTHREAD_DEFAULT_PRIOCEILING;
1229 mutex->mtxopts.options.protocol = _PTHREAD_DEFAULT_PROTOCOL;
1f2f436a
A
1230 if (static_type != 3)
1231 mutex->mtxopts.options.policy = _PTHREAD_MUTEX_POLICY_FAIRSHARE;
1232 else
1233 mutex->mtxopts.options.policy = _PTHREAD_MUTEX_POLICY_FIRSTFIT;
34e8f829
A
1234 mutex->mtxopts.options.pshared = _PTHREAD_DEFAULT_PSHARED;
1235 }
1236
1f2f436a
A
1237 mutex->mtxopts.options.notify = 0;
1238 mutex->mtxopts.options.rfu = 0;
1239 mutex->mtxopts.options.hold = 0;
1240 mutex->mtxopts.options.mutex = 1;
34e8f829
A
1241 mutex->mtxopts.options.lock_count = 0;
1242 /* address 8byte aligned? */
1243 if (((uintptr_t)mutex & 0x07) != 0) {
1244 /* 4byte alinged */
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__ */
1253 } else {
1254 /* 8byte alinged */
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__ */
1263 }
1264 mutex->m_tid = 0;
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;
1f2f436a
A
1270 /*
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;
1275 */
1276 __pthread_mutex_set_signature(mutex);
34e8f829
A
1277 return (0);
1278}
1279
1280
34e8f829
A
1281/*
1282 * Destroy a mutex variable.
1283 */
1284int
1f2f436a 1285pthread_mutex_destroy(pthread_mutex_t *omutex)
34e8f829
A
1286{
1287 int res;
1288 npthread_mutex_t * mutex = (npthread_mutex_t *)omutex;
1289
1290 LOCK(mutex->lock);
1f2f436a 1291 res = _pthread_mutex_destroy_locked(omutex);
34e8f829
A
1292 UNLOCK(mutex->lock);
1293
1294 return(res);
1295}
1296
1297
1f2f436a
A
1298static int
1299_pthread_mutex_destroy_locked(pthread_mutex_t *omutex)
34e8f829
A
1300{
1301 int res;
1302 npthread_mutex_t * mutex = (npthread_mutex_t *)omutex;
1f2f436a
A
1303 uint32_t lgenval, ugenval;
1304 volatile uint32_t * lseqaddr, *useqaddr;
34e8f829
A
1305
1306
1307 if (mutex->sig == _PTHREAD_MUTEX_SIG)
1308 {
1f2f436a 1309 MUTEX_GETSEQ_ADDR(mutex, lseqaddr, useqaddr);
34e8f829
A
1310
1311 lgenval = *(lseqaddr);
1f2f436a 1312 ugenval = *(useqaddr);
34e8f829 1313 if ((mutex->m_tid == (uint64_t)0) &&
1f2f436a 1314 ((lgenval & PTHRW_COUNT_MASK) == (ugenval & PTHRW_COUNT_MASK)))
34e8f829
A
1315 {
1316 mutex->sig = _PTHREAD_NO_SIG;
1317 res = 0;
1318 }
1319 else
1320 res = EBUSY;
1f2f436a
A
1321 } else if((mutex->sig & _PTHREAD_MUTEX_SIG_init_MASK )== _PTHREAD_MUTEX_SIG_CMP) {
1322 mutex->sig = _PTHREAD_NO_SIG;
1323 res = 0;
1324 } else
34e8f829
A
1325 res = EINVAL;
1326
1327 return (res);
1328}
1329
224c7076
A
1330
1331#endif /* !BUILDING_VARIANT ] */
1332
1333/*
1334 * Destroy a mutex attribute structure.
1335 */
1336int
1337pthread_mutexattr_destroy(pthread_mutexattr_t *attr)
1338{
1339#if __DARWIN_UNIX03
1340 if (__unix_conforming == 0)
1341 __unix_conforming = 1;
1342 if (attr->sig != _PTHREAD_MUTEX_ATTR_SIG)
1343 return (EINVAL);
1344#endif /* __DARWIN_UNIX03 */
1345
1346 attr->sig = _PTHREAD_NO_SIG; /* Uninitialized */
1347 return (0);
1348}
1349
1350