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.
48 * POSIX Pthread Library
51 #include "pthread_internals.h"
52 #include <sys/time.h> /* For struct timespec and getclock(). */
56 #include "plockstat.h"
57 #else /* !PLOCKSTAT */
58 #define PLOCKSTAT_MUTEX_RELEASE(x, y)
59 #endif /* PLOCKSTAT */
62 extern int __semwait_signal(int, int, int, int, int64_t, int32_t);
63 extern int _pthread_cond_init(pthread_cond_t
*, const pthread_condattr_t
*, int);
64 extern int __unix_conforming
;
67 /* 5243343 - temporary hack to detect if we are running the conformance test */
68 extern int PR_5243343_flag
;
69 #endif /* PR_5243343 */
71 #if defined(__i386__) || defined(__x86_64__)
72 __private_extern__
int __new_pthread_cond_wait(pthread_cond_t
*cond
, pthread_mutex_t
*mutex
, const struct timespec
*abstime
, int isRelative
, int isconforming
);
73 extern int _new_pthread_cond_init(pthread_cond_t
*, const pthread_condattr_t
*, int);
74 extern int _new_pthread_cond_destroy(pthread_cond_t
*);
75 extern int _new_pthread_cond_destroy_locked(pthread_cond_t
*);
76 int _new_pthread_cond_broadcast(pthread_cond_t
*cond
);
77 int _new_pthread_cond_signal_thread_np(pthread_cond_t
*cond
, pthread_t thread
);
78 int _new_pthread_cond_signal(pthread_cond_t
*cond
);
79 int _new_pthread_cond_timedwait_relative_np(pthread_cond_t
*cond
, pthread_mutex_t
*mutex
, const struct timespec
*abstime
);
80 int _new_pthread_cond_wait(pthread_cond_t
*cond
, pthread_mutex_t
*mutex
);
81 int _new_pthread_cond_timedwait(pthread_cond_t
*cond
, pthread_mutex_t
*mutex
, const struct timespec
*abstime
);
82 static void _new_cond_cleanup(void *arg
);
83 static void _new_cond_dropwait(npthread_cond_t
* cond
);
87 #define COND_GETSEQ_ADDR(cond, c_lseqcnt, c_useqcnt) \
89 if (cond->misalign != 0) { \
90 c_lseqcnt = &cond->c_seq[1]; \
91 c_useqcnt = &cond->c_seq[2]; \
94 c_lseqcnt = &cond->c_seq[0]; \
95 c_useqcnt = &cond->c_seq[1]; \
99 #define COND_GETSEQ_ADDR(cond, c_lseqcnt, c_useqcnt) \
101 if (cond->misalign != 0) { \
102 c_lseqcnt = &cond->c_seq[1]; \
103 c_useqcnt = &cond->c_seq[2]; \
106 c_lseqcnt = &cond->c_seq[0]; \
107 c_useqcnt = &cond->c_seq[1]; \
110 #endif /* __LP64__ */
113 #define _KSYN_TRACE_ 0
116 /* The Function qualifiers */
117 #define DBG_FUNC_START 1
118 #define DBG_FUNC_END 2
119 #define DBG_FUNC_NONE 0
121 int __kdebug_trace(uint32_t, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t);
123 #define _KSYN_TRACE_UM_LOCK 0x9000060
124 #define _KSYN_TRACE_UM_UNLOCK 0x9000064
125 #define _KSYN_TRACE_UM_MHOLD 0x9000068
126 #define _KSYN_TRACE_UM_MDROP 0x900006c
127 #define _KSYN_TRACE_UM_CVWAIT 0x9000070
128 #define _KSYN_TRACE_UM_CVSIG 0x9000074
129 #define _KSYN_TRACE_UM_CVBRD 0x9000078
131 #endif /* _KSYN_TRACE_ */
132 #endif /* __i386__ || __x86_64__ */
135 #ifndef BUILDING_VARIANT /* [ */
138 * Destroy a condition variable.
141 pthread_cond_destroy(pthread_cond_t
*cond
)
146 /* to provide backwards compat for apps using united condtn vars */
147 if((sig
!= _PTHREAD_COND_SIG
) && (sig
!= _PTHREAD_COND_SIG_init
))
151 if (cond
->sig
== _PTHREAD_COND_SIG
)
153 #if defined(__i386__) || defined(__x86_64__)
154 if (cond
->pshared
== PTHREAD_PROCESS_SHARED
) {
155 ret
= _new_pthread_cond_destroy_locked(cond
);
159 #endif /* __i386__ || __x86_64__ */
160 if (cond
->busy
== (pthread_mutex_t
*)NULL
)
162 cond
->sig
= _PTHREAD_NO_SIG
;
167 ret
= EINVAL
; /* Not an initialized condition variable structure */
174 * Signal a condition variable, waking up all threads waiting for it.
177 pthread_cond_broadcast(pthread_cond_t
*cond
)
179 kern_return_t kern_res
;
183 /* to provide backwards compat for apps using united condtn vars */
184 if((sig
!= _PTHREAD_COND_SIG
) && (sig
!= _PTHREAD_COND_SIG_init
))
188 if (cond
->sig
!= _PTHREAD_COND_SIG
)
192 if (cond
->sig
== _PTHREAD_COND_SIG_init
)
194 _pthread_cond_init(cond
, NULL
, 0);
197 res
= EINVAL
; /* Not a condition variable */
201 #if defined(__i386__) || defined(__x86_64__)
202 else if (cond
->pshared
== PTHREAD_PROCESS_SHARED
) {
204 return(_new_pthread_cond_broadcast(cond
));
206 #endif /* __i386__ || __x86_64__ */
207 else if ((sem
= cond
->sem
) == SEMAPHORE_NULL
)
209 /* Avoid kernel call since there are no waiters... */
216 PTHREAD_MACH_CALL(semaphore_signal_all(sem
), kern_res
);
220 if (cond
->waiters
== 0 && cond
->sigspending
== 0)
222 cond
->sem
= SEMAPHORE_NULL
;
223 restore_sem_to_pool(sem
);
226 if (kern_res
!= KERN_SUCCESS
)
232 * Signal a condition variable, waking a specified thread.
235 pthread_cond_signal_thread_np(pthread_cond_t
*cond
, pthread_t thread
)
237 kern_return_t kern_res
;
241 /* to provide backwards compat for apps using united condtn vars */
243 if((sig
!= _PTHREAD_COND_SIG
) && (sig
!= _PTHREAD_COND_SIG_init
))
246 if (cond
->sig
!= _PTHREAD_COND_SIG
)
250 if (cond
->sig
== _PTHREAD_COND_SIG_init
)
252 _pthread_cond_init(cond
, NULL
, 0);
255 ret
= EINVAL
; /* Not a condition variable */
259 #if defined(__i386__) || defined(__x86_64__)
260 else if (cond
->pshared
== PTHREAD_PROCESS_SHARED
) {
262 return(_new_pthread_cond_signal_thread_np(cond
, thread
));
264 #endif /* __i386__ || __x86_64__ */
265 else if ((sem
= cond
->sem
) == SEMAPHORE_NULL
)
267 /* Avoid kernel call since there are not enough waiters... */
274 if (thread
== (pthread_t
)NULL
)
276 kern_res
= semaphore_signal_thread(sem
, THREAD_NULL
);
277 if (kern_res
== KERN_NOT_WAITING
)
278 kern_res
= KERN_SUCCESS
;
280 else if (thread
->sig
== _PTHREAD_SIG
)
282 PTHREAD_MACH_CALL(semaphore_signal_thread(
283 sem
, pthread_mach_thread_np(thread
)), kern_res
);
286 kern_res
= KERN_FAILURE
;
290 if (cond
->waiters
== 0 && cond
->sigspending
== 0)
292 cond
->sem
= SEMAPHORE_NULL
;
293 restore_sem_to_pool(sem
);
296 if (kern_res
!= KERN_SUCCESS
)
302 * Signal a condition variable, waking only one thread.
305 pthread_cond_signal(pthread_cond_t
*cond
)
307 return pthread_cond_signal_thread_np(cond
, NULL
);
311 * Manage a list of condition variables associated with a mutex
315 _pthread_cond_add(pthread_cond_t
*cond
, pthread_mutex_t
*mutex
)
319 if ((c
= mutex
->busy
) != (pthread_cond_t
*)NULL
)
324 cond
->prev
= (pthread_cond_t
*)NULL
;
327 if (cond
->sem
== SEMAPHORE_NULL
)
328 cond
->sem
= new_sem_from_pool();
332 _pthread_cond_remove(pthread_cond_t
*cond
, pthread_mutex_t
*mutex
)
334 pthread_cond_t
*n
, *p
;
337 if ((n
= cond
->next
) != (pthread_cond_t
*)NULL
)
339 n
->prev
= cond
->prev
;
341 if ((p
= cond
->prev
) != (pthread_cond_t
*)NULL
)
343 p
->next
= cond
->next
;
346 { /* This is the first in the list */
350 if (cond
->sigspending
== 0)
352 restore_sem_to_pool(cond
->sem
);
353 cond
->sem
= SEMAPHORE_NULL
;
358 cond_cleanup(void *arg
)
360 pthread_cond_t
*cond
= (pthread_cond_t
*)arg
;
361 pthread_mutex_t
*mutex
;
363 pthread_t thread
= pthread_self();
367 thcanceled
= (thread
->detached
& _PTHREAD_WASCANCEL
);
368 UNLOCK(thread
->lock
);
377 if (cond
->waiters
== 0) {
378 _pthread_cond_remove(cond
, mutex
);
379 cond
->busy
= (pthread_mutex_t
*)NULL
;
384 ** Can't do anything if this fails -- we're on the way out
386 (void)pthread_mutex_lock(mutex
);
390 * Suspend waiting for a condition variable.
391 * Note: we have to keep a list of condition variables which are using
392 * this same mutex variable so we can detect invalid 'destroy' sequences.
393 * If isconforming < 0, we skip the _pthread_testcancel(), but keep the
394 * remaining conforming behavior..
396 __private_extern__
int
397 _pthread_cond_wait(pthread_cond_t
*cond
,
398 pthread_mutex_t
*mutex
,
399 const struct timespec
*abstime
,
404 kern_return_t kern_res
= KERN_SUCCESS
;
406 pthread_mutex_t
*busy
;
407 mach_timespec_t then
= {0, 0};
408 struct timespec cthen
= {0,0};
410 int msig
= mutex
->sig
;
411 extern void _pthread_testcancel(pthread_t thread
, int isconforming
);
413 /* to provide backwards compat for apps using united condtn vars */
414 if((sig
!= _PTHREAD_COND_SIG
) && (sig
!= _PTHREAD_COND_SIG_init
))
418 if((msig
!= _PTHREAD_MUTEX_SIG
) && (msig
!= _PTHREAD_MUTEX_SIG_init
))
420 if (isconforming
> 0)
421 _pthread_testcancel(pthread_self(), 1);
424 if (cond
->sig
!= _PTHREAD_COND_SIG
)
426 if (cond
->sig
!= _PTHREAD_COND_SIG_init
)
429 return (EINVAL
); /* Not a condition variable */
431 _pthread_cond_init(cond
, NULL
, 0);
433 #if defined(__i386__) || defined(__x86_64__)
434 else if (cond
->pshared
== PTHREAD_PROCESS_SHARED
) {
436 return(__new_pthread_cond_wait(cond
, mutex
, abstime
, isRelative
, isconforming
));
438 #endif /* __i386__ || __x86_64__ */
443 if (isRelative
== 0) {
446 gettimeofday(&tv
, NULL
);
447 TIMEVAL_TO_TIMESPEC(&tv
, &now
);
449 /* Compute relative time to sleep */
450 then
.tv_nsec
= abstime
->tv_nsec
- now
.tv_nsec
;
451 then
.tv_sec
= abstime
->tv_sec
- now
.tv_sec
;
452 if (then
.tv_nsec
< 0)
454 then
.tv_nsec
+= NSEC_PER_SEC
;
457 if (((int)then
.tv_sec
< 0) ||
458 ((then
.tv_sec
== 0) && (then
.tv_nsec
== 0)))
464 then
.tv_sec
= abstime
->tv_sec
;
465 then
.tv_nsec
= abstime
->tv_nsec
;
467 if (then
.tv_nsec
>= NSEC_PER_SEC
) {
472 if (isRelative
== 0) {
473 /* preflight the checks for failures */
476 gettimeofday(&tv
, NULL
);
477 TIMEVAL_TO_TIMESPEC(&tv
, &now
);
479 /* Compute relative time to sleep */
480 then
.tv_nsec
= abstime
->tv_nsec
- now
.tv_nsec
;
481 then
.tv_sec
= abstime
->tv_sec
- now
.tv_sec
;
482 if (then
.tv_nsec
< 0)
484 then
.tv_nsec
+= NSEC_PER_SEC
;
487 if (((int)then
.tv_sec
< 0) ||
488 ((then
.tv_sec
== 0) && (then
.tv_nsec
== 0)))
493 if (then
.tv_nsec
>= NSEC_PER_SEC
) {
498 /* we can cleanup this code and pass the calculated time
499 * to the kernel. But kernel is going to do the same. TILL
500 * we change the kernel do this anyway
502 cthen
.tv_sec
= abstime
->tv_sec
;
503 cthen
.tv_nsec
= abstime
->tv_nsec
;
504 if ((cthen
.tv_sec
< 0) || (cthen
.tv_nsec
< 0)) {
508 if (cthen
.tv_nsec
>= NSEC_PER_SEC
) {
515 if (++cond
->waiters
== 1)
517 _pthread_cond_add(cond
, mutex
);
520 else if ((busy
= cond
->busy
) != mutex
)
522 /* Must always specify the same mutex! */
530 if (--mutex
->mtxopts
.options
.lock_count
== 0)
532 PLOCKSTAT_MUTEX_RELEASE(mutex
, (mutex
->mtxopts
.options
.type
== PTHREAD_MUTEX_RECURSIVE
)? 1:0);
534 if (mutex
->sem
== SEMAPHORE_NULL
)
535 mutex
->sem
= new_sem_from_pool();
536 mutex
->owner
= _PTHREAD_MUTEX_OWNER_SWITCHING
;
541 kern_res
= semaphore_timedwait_signal(cond
->sem
, mutex
->sem
, then
);
543 PTHREAD_MACH_CALL(semaphore_wait_signal(cond
->sem
, mutex
->sem
), kern_res
);
546 pthread_cleanup_push(cond_cleanup
, (void *)cond
);
547 wait_res
= __semwait_signal(cond
->sem
, mutex
->sem
, abstime
!= NULL
, isRelative
,
548 (int64_t)cthen
.tv_sec
, (int32_t)cthen
.tv_nsec
);
549 pthread_cleanup_pop(0);
552 PLOCKSTAT_MUTEX_RELEASE(mutex
, (mutex
->mtxopts
.options
.type
== PTHREAD_MUTEX_RECURSIVE
)? 1:0);
556 kern_res
= semaphore_timedwait(cond
->sem
, then
);
558 PTHREAD_MACH_CALL(semaphore_wait(cond
->sem
), kern_res
);
561 pthread_cleanup_push(cond_cleanup
, (void *)cond
);
562 wait_res
= __semwait_signal(cond
->sem
, 0, abstime
!= NULL
, isRelative
,
563 (int64_t)cthen
.tv_sec
, (int32_t)cthen
.tv_nsec
);
564 pthread_cleanup_pop(0);
571 if (cond
->waiters
== 0)
573 _pthread_cond_remove(cond
, mutex
);
574 cond
->busy
= (pthread_mutex_t
*)NULL
;
577 if ((res
= pthread_mutex_lock(mutex
)) != 0)
581 /* KERN_ABORTED can be treated as a spurious wakeup */
582 if ((kern_res
== KERN_SUCCESS
) || (kern_res
== KERN_ABORTED
))
584 else if (kern_res
== KERN_OPERATION_TIMED_OUT
)
589 if (errno
== ETIMEDOUT
) {
591 } else if (errno
== EINTR
) {
593 ** EINTR can be treated as a spurious wakeup unless we were canceled.
605 pthread_cond_timedwait_relative_np(pthread_cond_t
*cond
,
606 pthread_mutex_t
*mutex
,
607 const struct timespec
*abstime
)
609 return (_pthread_cond_wait(cond
, mutex
, abstime
, 1, 0));
613 pthread_condattr_init(pthread_condattr_t
*attr
)
615 attr
->sig
= _PTHREAD_COND_ATTR_SIG
;
616 attr
->pshared
= _PTHREAD_DEFAULT_PSHARED
;
621 pthread_condattr_destroy(pthread_condattr_t
*attr
)
623 attr
->sig
= _PTHREAD_NO_SIG
; /* Uninitialized */
628 pthread_condattr_getpshared(const pthread_condattr_t
*attr
,
631 if (attr
->sig
== _PTHREAD_COND_ATTR_SIG
)
633 *pshared
= (int)attr
->pshared
;
637 return (EINVAL
); /* Not an initialized 'attribute' structure */
642 __private_extern__
int
643 _pthread_cond_init(pthread_cond_t
*cond
,
644 const pthread_condattr_t
*attr
,
647 cond
->next
= (pthread_cond_t
*)NULL
;
648 cond
->prev
= (pthread_cond_t
*)NULL
;
649 cond
->busy
= (pthread_mutex_t
*)NULL
;
651 cond
->sigspending
= 0;
654 cond
->pshared
= attr
->pshared
;
656 cond
->pshared
= _PTHREAD_DEFAULT_PSHARED
;
658 cond
->pshared
= _PTHREAD_DEFAULT_PSHARED
;
659 cond
->sem
= SEMAPHORE_NULL
;
660 cond
->sig
= _PTHREAD_COND_SIG
;
665 /* temp home till pshared is fixed correctly */
667 pthread_condattr_setpshared(pthread_condattr_t
* attr
, int pshared
)
670 if (attr
->sig
== _PTHREAD_COND_ATTR_SIG
)
674 if (( pshared
== PTHREAD_PROCESS_PRIVATE
) || (pshared
== PTHREAD_PROCESS_SHARED
&& PR_5243343_flag
))
675 #else /* !PR_5243343 */
676 if (( pshared
== PTHREAD_PROCESS_PRIVATE
) || (pshared
== PTHREAD_PROCESS_SHARED
))
677 #endif /* PR_5243343 */
678 #else /* __DARWIN_UNIX03 */
679 if ( pshared
== PTHREAD_PROCESS_PRIVATE
)
680 #endif /* __DARWIN_UNIX03 */
682 attr
->pshared
= pshared
;
686 return (EINVAL
); /* Invalid parameter */
690 return (EINVAL
); /* Not an initialized 'attribute' structure */
695 #if defined(__i386__) || defined(__x86_64__)
697 __private_extern__
int
698 _new_pthread_cond_init(pthread_cond_t
*ocond
,
699 const pthread_condattr_t
*attr
,
702 npthread_cond_t
* cond
= (npthread_cond_t
*)ocond
;
704 cond
->busy
= (npthread_mutex_t
*)NULL
;
710 if (((uintptr_t)cond
& 0x07) != 0) {
717 cond
->pshared
= attr
->pshared
;
719 cond
->pshared
= _PTHREAD_DEFAULT_PSHARED
;
721 cond
->pshared
= _PTHREAD_DEFAULT_PSHARED
;
722 cond
->sig
= _PTHREAD_COND_SIG
;
727 _new_pthread_cond_destroy(pthread_cond_t
* ocond
)
729 npthread_cond_t
*cond
= (npthread_cond_t
*)ocond
;
733 ret
= _new_pthread_cond_destroy_locked(ocond
);
740 _new_pthread_cond_destroy_locked(pthread_cond_t
* ocond
)
742 npthread_cond_t
*cond
= (npthread_cond_t
*)ocond
;
745 uint32_t * c_lseqcnt
;
746 uint32_t * c_useqcnt
;
747 uint32_t lgenval
, ugenval
;
749 /* to provide backwards compat for apps using united condtn vars */
750 if((sig
!= _PTHREAD_COND_SIG
) && (sig
!= _PTHREAD_COND_SIG_init
))
753 if (cond
->sig
== _PTHREAD_COND_SIG
)
755 COND_GETSEQ_ADDR(cond
, c_lseqcnt
, c_useqcnt
);
757 lgenval
= *c_lseqcnt
;
758 ugenval
= *c_useqcnt
;
759 if (lgenval
== ugenval
)
761 cond
->sig
= _PTHREAD_NO_SIG
;
766 ret
= EINVAL
; /* Not an initialized condition variable structure */
771 * Signal a condition variable, waking up all threads waiting for it.
774 _new_pthread_cond_broadcast(pthread_cond_t
*ocond
)
776 npthread_cond_t
* cond
= (npthread_cond_t
*)ocond
;
778 npthread_mutex_t
* mutex
;
779 uint32_t lgenval
, ugenval
, mgen
, ugen
, flags
, mtxgen
, mtxugen
, notify
;
780 int diffgen
, retval
, dropcount
, mutexrefs
;
781 uint64_t oldval64
, newval64
;
782 uint32_t * c_lseqcnt
;
783 uint32_t * c_useqcnt
;
784 uint32_t * pmtx
= NULL
;
787 /* to provide backwards compat for apps using united condtn vars */
788 if((sig
!= _PTHREAD_COND_SIG
) && (sig
!= _PTHREAD_COND_SIG_init
))
791 if (sig
!= _PTHREAD_COND_SIG
)
796 if (cond
->sig
== _PTHREAD_COND_SIG_init
)
798 _new_pthread_cond_init(ocond
, NULL
, 0);
800 } else if (cond
->sig
!= _PTHREAD_COND_SIG
) {
801 res
= EINVAL
; /* Not a condition variable */
809 (void)__kdebug_trace(_KSYN_TRACE_UM_CVBRD
| DBG_FUNC_START
, (uint32_t)cond
, 0, 0, 0, 0);
812 COND_GETSEQ_ADDR(cond
, c_lseqcnt
, c_useqcnt
);
814 lgenval
= *c_lseqcnt
;
815 ugenval
= *c_useqcnt
;
816 diffgen
= lgenval
- ugenval
; /* pendig waiters */
821 (void)__kdebug_trace(_KSYN_TRACE_UM_CVBRD
| DBG_FUNC_END
, (uint32_t)cond
, 0, 0, 0, 0);
827 if (OSAtomicCompareAndSwap32(ugenval
, ugenval
+diffgen
, (volatile int *)c_useqcnt
) != TRUE
)
830 #ifdef COND_MTX_WAITQUEUEMOVE
832 if ((mutex
!= NULL
) && cond
->pshared
!= PTHREAD_PROCESS_SHARED
) {
834 (void)__kdebug_trace(_KSYN_TRACE_UM_CVBRD
| DBG_FUNC_NONE
, (uint32_t)cond
, 1, diffgen
, 0, 0);
836 (void)__mtx_holdlock(mutex
, diffgen
, &flags
, &pmtx
, &mgen
, &ugen
);
839 if (cond
->pshared
!= PTHREAD_PROCESS_SHARED
)
840 flags
= _PTHREAD_MTX_OPT_NOHOLD
;
842 flags
= _PTHREAD_MTX_OPT_NOHOLD
| _PTHREAD_MTX_OPT_PSHARED
;
847 #else /* COND_MTX_WAITQUEUEMOVE */
849 if (cond
->pshared
!= PTHREAD_PROCESS_SHARED
)
850 flags
= _PTHREAD_MTX_OPT_NOHOLD
;
852 flags
= _PTHREAD_MTX_OPT_NOHOLD
| _PTHREAD_MTX_OPT_PSHARED
;
856 #endif /* COND_MTX_WAITQUEUEMOVE */
859 (void)__kdebug_trace(_KSYN_TRACE_UM_CVBRD
| DBG_FUNC_NONE
, (uint32_t)cond
, 3, diffgen
, 0, 0);
861 retval
= __psynch_cvbroad(ocond
, lgenval
, diffgen
, (pthread_mutex_t
*)pmtx
, mgen
, ugen
, (uint64_t)0, flags
);
863 #ifdef COND_MTX_WAITQUEUEMOVE
864 if ((retval
!= -1) && (retval
!= 0)) {
865 if ((mutexrefs
!= 0) && (retval
<= PTHRW_MAX_READERS
/2)) {
866 dropcount
= (retval
);
868 (void)__kdebug_trace(_KSYN_TRACE_UM_CVBRD
| DBG_FUNC_NONE
, (uint32_t)cond
, 2, dropcount
, 0, 0);
870 retval
= __mtx_droplock(mutex
, dropcount
, &flags
, &pmtx
, &mtxgen
, &mtxugen
, ¬ify
);
873 #endif /* COND_MTX_WAITQUEUEMOVE */
875 oldval64
= (((uint64_t)(ugenval
+diffgen
)) << 32);
879 OSAtomicCompareAndSwap64(oldval64
, newval64
, (volatile int64_t *)c_lseqcnt
);
882 (void)__kdebug_trace(_KSYN_TRACE_UM_CVBRD
| DBG_FUNC_END
, (uint32_t)cond
, 0, 0, 0, 0);
889 * Signal a condition variable, waking a specified thread.
892 _new_pthread_cond_signal_thread_np(pthread_cond_t
*ocond
, pthread_t thread
)
894 npthread_cond_t
* cond
= (npthread_cond_t
*)ocond
;
896 npthread_mutex_t
* mutex
;
897 int retval
, dropcount
;
898 uint32_t lgenval
, ugenval
, diffgen
, mgen
, ugen
, flags
, mtxgen
, mtxugen
, notify
;
899 uint32_t * c_lseqcnt
;
900 uint32_t * c_useqcnt
;
901 uint64_t oldval64
, newval64
;
903 uint32_t * pmtx
= NULL
;
905 /* to provide backwards compat for apps using united condtn vars */
907 if((sig
!= _PTHREAD_COND_SIG
) && (sig
!= _PTHREAD_COND_SIG_init
))
909 if (cond
->sig
!= _PTHREAD_COND_SIG
) {
911 if (cond
->sig
!= _PTHREAD_COND_SIG
) {
912 if (cond
->sig
== _PTHREAD_COND_SIG_init
) {
913 _new_pthread_cond_init(ocond
, NULL
, 0);
923 (void)__kdebug_trace(_KSYN_TRACE_UM_CVSIG
| DBG_FUNC_START
, (uint32_t)cond
, 0, 0, 0, 0);
925 COND_GETSEQ_ADDR(cond
, c_lseqcnt
, c_useqcnt
);
927 lgenval
= *c_lseqcnt
;
928 ugenval
= *c_useqcnt
;
929 diffgen
= lgenval
- ugenval
; /* pendig waiters */
932 (void)__kdebug_trace(_KSYN_TRACE_UM_CVSIG
| DBG_FUNC_END
, (uint32_t)cond
, 0, 0, 0, 0);
939 if (OSAtomicCompareAndSwap32(ugenval
, ugenval
+1, (volatile int *)c_useqcnt
) != TRUE
)
942 #ifdef COND_MTX_WAITQUEUEMOVE
943 if ((mutex
!= NULL
) && (cond
->pshared
!= PTHREAD_PROCESS_SHARED
)) {
945 (void)__kdebug_trace(_KSYN_TRACE_UM_CVSIG
| DBG_FUNC_NONE
, (uint32_t)cond
, 1, 0, 0, 0);
947 (void)__mtx_holdlock(mutex
, 1, &flags
, &pmtx
, &mgen
, &ugen
);
950 if (cond
->pshared
!= PTHREAD_PROCESS_SHARED
)
951 flags
= _PTHREAD_MTX_OPT_NOHOLD
;
953 flags
= _PTHREAD_MTX_OPT_NOHOLD
| _PTHREAD_MTX_OPT_PSHARED
;
957 #else /* COND_MTX_WAITQUEUEMOVE */
958 if (cond
->pshared
!= PTHREAD_PROCESS_SHARED
)
959 flags
= _PTHREAD_MTX_OPT_NOHOLD
;
961 flags
= _PTHREAD_MTX_OPT_NOHOLD
| _PTHREAD_MTX_OPT_PSHARED
;
965 #endif /* COND_MTX_WAITQUEUEMOVE */
968 (void)__kdebug_trace(_KSYN_TRACE_UM_CVSIG
| DBG_FUNC_NONE
, (uint32_t)cond
, 3, lgenval
, ugenval
+1, 0);
970 retval
= __psynch_cvsignal(ocond
, lgenval
, ugenval
+1,(pthread_mutex_t
*)mutex
, mgen
, ugen
, pthread_mach_thread_np(thread
), flags
);
972 #ifdef COND_MTX_WAITQUEUEMOVE
973 if ((retval
!= -1) && (retval
!= 0) && (mutexrefs
!= 0)) {
976 (void)__kdebug_trace(_KSYN_TRACE_UM_CVSIG
| DBG_FUNC_NONE
, (uint32_t)cond
, 4, dropcount
, 0, 0);
978 retval
= __mtx_droplock(mutex
, dropcount
, &flags
, &pmtx
, &mtxgen
, &mtxugen
, ¬ify
);
980 #endif /* COND_MTX_WAITQUEUEMOVE */
982 if (lgenval
== ugenval
+1){
983 oldval64
= (((uint64_t)(ugenval
+1)) << 32);
986 OSAtomicCompareAndSwap64(oldval64
, newval64
, (volatile int64_t *)c_lseqcnt
);
988 (void)__kdebug_trace(_KSYN_TRACE_UM_CVSIG
| DBG_FUNC_NONE
, (uint32_t)cond
, 5, 0, 0, 0);
993 (void)__kdebug_trace(_KSYN_TRACE_UM_CVSIG
| DBG_FUNC_END
, (uint32_t)cond
, 0, 0, 0, 0);
999 * Signal a condition variable, waking only one thread.
1002 _new_pthread_cond_signal(pthread_cond_t
*cond
)
1004 return _new_pthread_cond_signal_thread_np(cond
, NULL
);
1008 * Manage a list of condition variables associated with a mutex
1013 * Suspend waiting for a condition variable.
1014 * Note: we have to keep a list of condition variables which are using
1015 * this same mutex variable so we can detect invalid 'destroy' sequences.
1016 * If isconforming < 0, we skip the _pthread_testcancel(), but keep the
1017 * remaining conforming behavior..
1019 __private_extern__
int
1020 __new_pthread_cond_wait(pthread_cond_t
*ocond
,
1021 pthread_mutex_t
*omutex
,
1022 const struct timespec
*abstime
,
1027 npthread_cond_t
* cond
= (npthread_cond_t
*)ocond
;
1028 npthread_mutex_t
* mutex
= (npthread_mutex_t
* )omutex
;
1029 mach_timespec_t then
= {0,0};
1030 struct timespec cthen
= {0,0};
1031 int sig
= cond
->sig
;
1032 int msig
= mutex
->sig
;
1034 npthread_mutex_t
* pmtx
;
1035 uint32_t mtxgen
, mtxugen
, flags
, updateval
, notify
;
1036 uint32_t lgenval
, ugenval
;
1037 uint32_t * c_lseqcnt
;
1038 uint32_t * c_useqcnt
;
1039 uint32_t * npmtx
= NULL
;
1041 extern void _pthread_testcancel(pthread_t thread
, int isconforming
);
1043 /* to provide backwards compat for apps using united condtn vars */
1044 if((sig
!= _PTHREAD_COND_SIG
) && (sig
!= _PTHREAD_COND_SIG_init
))
1048 if((msig
!= _PTHREAD_MUTEX_SIG
) && (msig
!= _PTHREAD_MUTEX_SIG_init
))
1050 if (isconforming
> 0)
1051 _pthread_testcancel(pthread_self(), 1);
1053 if (cond
->sig
!= _PTHREAD_COND_SIG
)
1056 if (cond
->sig
!= _PTHREAD_COND_SIG_init
)
1059 return (EINVAL
); /* Not a condition variable */
1061 _new_pthread_cond_init(ocond
, NULL
, 0);
1066 (void)__kdebug_trace(_KSYN_TRACE_UM_CVWAIT
| DBG_FUNC_START
, (uint32_t)cond
, 0, 0, (uint32_t)abstime
, 0);
1068 COND_GETSEQ_ADDR(cond
, c_lseqcnt
, c_useqcnt
);
1070 /* send relative time to kernel */
1072 if (isRelative
== 0) {
1073 struct timespec now
;
1075 gettimeofday(&tv
, NULL
);
1076 TIMEVAL_TO_TIMESPEC(&tv
, &now
);
1078 /* Compute relative time to sleep */
1079 then
.tv_nsec
= abstime
->tv_nsec
- now
.tv_nsec
;
1080 then
.tv_sec
= abstime
->tv_sec
- now
.tv_sec
;
1081 if (then
.tv_nsec
< 0)
1083 then
.tv_nsec
+= NSEC_PER_SEC
;
1086 if (((int)then
.tv_sec
< 0) ||
1087 ((then
.tv_sec
== 0) && (then
.tv_nsec
== 0)))
1092 if (isconforming
!= 0) {
1093 cthen
.tv_sec
= abstime
->tv_sec
;
1094 cthen
.tv_nsec
= abstime
->tv_nsec
;
1095 if ((cthen
.tv_sec
< 0) || (cthen
.tv_nsec
< 0)) {
1099 if (cthen
.tv_nsec
>= NSEC_PER_SEC
) {
1105 then
.tv_sec
= abstime
->tv_sec
;
1106 then
.tv_nsec
= abstime
->tv_nsec
;
1108 if(isconforming
&& ((then
.tv_sec
< 0) || (then
.tv_nsec
< 0))) {
1111 if (then
.tv_nsec
>= NSEC_PER_SEC
) {
1119 ugenval
= *c_useqcnt
;
1120 lgenval
= OSAtomicIncrement32((volatile int32_t *)c_lseqcnt
);
1124 (void)__kdebug_trace(_KSYN_TRACE_UM_CVWAIT
| DBG_FUNC_NONE
, (uint32_t)cond
, 1, lgenval
, ugenval
, 0);
1127 retval
= __mtx_droplock(pmtx
, 1, &flags
, &npmtx
, &mtxgen
, &mtxugen
, ¬ify
);
1130 if ((notify
& 1) == 0) {
1133 if ((notify
& 0xc0000000) != 0)
1134 then
.tv_nsec
|= (notify
& 0xc0000000);
1137 (void)__kdebug_trace(_KSYN_TRACE_UM_CVWAIT
| DBG_FUNC_NONE
, (uint32_t)cond
, 3, (uint32_t)mutex
, 0, 0);
1141 pthread_cleanup_push(_new_cond_cleanup
, (void *)cond
);
1142 updateval
= __psynch_cvwait(ocond
, lgenval
, ugenval
, (pthread_mutex_t
*)npmtx
, mtxgen
, mtxugen
, (uint64_t)then
.tv_sec
, (uint64_t)then
.tv_nsec
);
1143 pthread_cleanup_pop(0);
1145 updateval
= __psynch_cvwait(ocond
, lgenval
, ugenval
, (pthread_mutex_t
*)npmtx
, mtxgen
, mtxugen
, (uint64_t)then
.tv_sec
, (uint64_t)then
.tv_nsec
);
1151 #ifdef COND_MTX_WAITQUEUEMOVE
1152 /* Needs to handle timedout */
1153 if (updateval
== (uint32_t)-1) {
1156 (void)__kdebug_trace(_KSYN_TRACE_UM_CVWAIT
| DBG_FUNC_NONE
, (uint32_t)cond
, 4, retval
, 0, 0);
1158 /* add unlock ref to show one less waiter */
1159 _new_cond_dropwait(cond
);
1161 pthread_mutex_lock(omutex
);
1163 } else if ((updateval
& PTHRW_MTX_NONE
) != 0) {
1165 (void)__kdebug_trace(_KSYN_TRACE_UM_CVWAIT
| DBG_FUNC_NONE
, (uint32_t)cond
, 5, updateval
, 0, 0);
1167 pthread_mutex_lock(omutex
);
1169 /* on successful return mutex held */
1170 /* returns 0 on succesful update */
1172 (void)__kdebug_trace(_KSYN_TRACE_UM_CVWAIT
| DBG_FUNC_NONE
, (uint32_t)cond
, 6, updateval
, 0, 0);
1174 firstfit
= (mutex
->mtxopts
.options
.policy
== _PTHREAD_MUTEX_POLICY_FIRSTFIT
);
1175 if (__mtx_updatebits( mutex
, updateval
, firstfit
, 1) == 1) {
1176 /* not expected to be here */
1177 LIBC_ABORT("CONDWAIT mutex acquire mishap");
1179 if (mutex
->mtxopts
.options
.type
== PTHREAD_MUTEX_RECURSIVE
)
1180 mutex
->mtxopts
.options
.lock_count
++;
1182 #else /* COND_MTX_WAITQUEUEMOVE */
1183 if (updateval
== (uint32_t)-1) {
1184 if (errno
== ETIMEDOUT
) {
1186 } else if (errno
== EINTR
) {
1188 ** EINTR can be treated as a spurious wakeup unless we were canceled.
1194 /* add unlock ref to show one less waiter */
1195 _new_cond_dropwait(cond
);
1199 (void)__kdebug_trace(_KSYN_TRACE_UM_CVWAIT
| DBG_FUNC_NONE
, (uint32_t)cond
, 4, retval
, 0, 0);
1201 pthread_mutex_lock(omutex
);
1203 #endif /* COND_MTX_WAITQUEUEMOVE */
1206 (void)__kdebug_trace(_KSYN_TRACE_UM_CVWAIT
| DBG_FUNC_END
, (uint32_t)cond
, 0, 0, retval
, 0);
1212 _new_cond_cleanup(void *arg
)
1214 npthread_cond_t
*cond
= (npthread_cond_t
*)arg
;
1215 pthread_mutex_t
*mutex
;
1218 pthread_t thread
= pthread_self();
1222 thcanceled
= (thread
->detached
& _PTHREAD_WASCANCEL
);
1223 UNLOCK(thread
->lock
);
1225 if (thcanceled
== 0)
1231 /* add unlock ref to show one less waiter */
1232 _new_cond_dropwait(cond
);
1235 ** Can't do anything if this fails -- we're on the way out
1238 (void)pthread_mutex_lock(mutex
);
1243 _new_cond_dropwait(npthread_cond_t
* cond
)
1245 int sig
= cond
->sig
;
1247 uint32_t lgenval
, ugenval
, diffgen
, mgen
, ugen
, flags
;
1248 uint32_t * c_lseqcnt
;
1249 uint32_t * c_useqcnt
;
1250 uint64_t oldval64
, newval64
;
1252 /* to provide backwards compat for apps using united condtn vars */
1254 if (sig
!= _PTHREAD_COND_SIG
)
1258 (void)__kdebug_trace(_KSYN_TRACE_UM_CVSIG
| DBG_FUNC_START
, (uint32_t)cond
, 0, 0, 0xee, 0);
1260 COND_GETSEQ_ADDR(cond
, c_lseqcnt
, c_useqcnt
);
1262 lgenval
= *c_lseqcnt
;
1263 ugenval
= *c_useqcnt
;
1264 diffgen
= lgenval
- ugenval
; /* pending waiters */
1268 (void)__kdebug_trace(_KSYN_TRACE_UM_CVSIG
| DBG_FUNC_END
, (uint32_t)cond
, 1, 0, 0xee, 0);
1273 if (OSAtomicCompareAndSwap32(ugenval
, ugenval
+1, (volatile int *)c_useqcnt
) != TRUE
)
1276 if (lgenval
== ugenval
+1) {
1278 /* send last drop notify to erase pre post */
1279 flags
= _PTHREAD_MTX_OPT_LASTDROP
;
1281 if (cond
->pshared
== PTHREAD_PROCESS_SHARED
)
1282 flags
|= _PTHREAD_MTX_OPT_PSHARED
;
1286 (void)__kdebug_trace(_KSYN_TRACE_UM_CVSIG
| DBG_FUNC_NONE
, (uint32_t)cond
, 1, 0, 0xee, 0);
1288 retval
= __psynch_cvsignal((pthread_cond_t
*)cond
, lgenval
, ugenval
+1,(pthread_mutex_t
*)NULL
, mgen
, ugen
, MACH_PORT_NULL
, flags
);
1290 oldval64
= (((uint64_t)(ugenval
+1)) << 32);
1291 oldval64
|= lgenval
;
1293 OSAtomicCompareAndSwap64(oldval64
, newval64
, (volatile int64_t *)c_lseqcnt
);
1297 (void)__kdebug_trace(_KSYN_TRACE_UM_CVSIG
| DBG_FUNC_END
, (uint32_t)cond
, 2, 0, 0xee, 0);
1304 _new_pthread_cond_timedwait_relative_np(pthread_cond_t
*cond
,
1305 pthread_mutex_t
*mutex
,
1306 const struct timespec
*abstime
)
1308 return (__new_pthread_cond_wait(cond
, mutex
, abstime
, 1, 0));
1313 _new_pthread_cond_wait(pthread_cond_t
*cond
,
1314 pthread_mutex_t
*mutex
)
1316 return(__new_pthread_cond_wait(cond
, mutex
, 0, 0, 1));
1320 _new_pthread_cond_timedwait(pthread_cond_t
*cond
,
1321 pthread_mutex_t
*mutex
,
1322 const struct timespec
*abstime
)
1324 return(__new_pthread_cond_wait(cond
, mutex
, abstime
, 0, 1));
1327 #endif /* __i386__ || __x86_64__ */
1329 #else /* !BUILDING_VARIANT */
1331 extern int _pthread_cond_wait(pthread_cond_t
*cond
,
1332 pthread_mutex_t
*mutex
,
1333 const struct timespec
*abstime
,
1337 #endif /* !BUILDING_VARIANT ] */
1339 * Initialize a condition variable. Note: 'attr' is ignored.
1343 * Initialize a condition variable. This is the public interface.
1344 * We can't trust the lock, so initialize it first before taking
1348 pthread_cond_init(pthread_cond_t
*cond
,
1349 const pthread_condattr_t
*attr
)
1355 #else /* __DARWIN_UNIX03 */
1357 #endif /* __DARWIN_UNIX03 */
1359 LOCK_INIT(cond
->lock
);
1360 #if defined(__i386__) || defined(__x86_64__)
1361 if ((attr
!= NULL
) && (attr
->pshared
== PTHREAD_PROCESS_SHARED
)) {
1362 return(_new_pthread_cond_init(cond
, attr
, conforming
));
1364 #endif /* __i386__ || __x86_64__ */
1366 return (_pthread_cond_init(cond
, attr
, conforming
));
1371 pthread_cond_wait(pthread_cond_t *cond,
1372 pthread_mutex_t *mutex)
1375 pthread_cond_timedwait(pthread_cond_t *cond,
1376 pthread_mutex_t *mutex,
1377 const struct timespec *abstime)
1379 moved to pthread_cancelable.c */