2 * Copyright (c) 2000-2003, 2007 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(). */
55 #include "plockstat.h"
57 extern void _pthread_mutex_remove(pthread_mutex_t
*, pthread_t
);
58 extern int __unix_conforming
;
60 #ifndef BUILDING_VARIANT /* [ */
63 * Destroy a condition variable.
66 pthread_cond_destroy(pthread_cond_t
*cond
)
71 /* to provide backwards compat for apps using united condtn vars */
72 if((sig
!= _PTHREAD_COND_SIG
) && (sig
!= _PTHREAD_COND_SIG_init
) && (sig
!= _PTHREAD_KERN_COND_SIG
))
76 if (cond
->sig
== _PTHREAD_COND_SIG
)
78 if (cond
->busy
== (pthread_mutex_t
*)NULL
)
80 cond
->sig
= _PTHREAD_NO_SIG
;
84 } else if (cond
->sig
== _PTHREAD_KERN_COND_SIG
) {
85 int condid
= cond
->_pthread_cond_kernid
;
87 if (__pthread_cond_destroy(condid
) == -1)
89 cond
->sig
= _PTHREAD_NO_SIG
;
92 ret
= EINVAL
; /* Not an initialized condition variable structure */
99 * Signal a condition variable, waking up all threads waiting for it.
102 pthread_cond_broadcast(pthread_cond_t
*cond
)
104 kern_return_t kern_res
;
108 /* to provide backwards compat for apps using united condtn vars */
109 if((sig
!= _PTHREAD_COND_SIG
) && (sig
!= _PTHREAD_COND_SIG_init
) && (sig
!= _PTHREAD_KERN_COND_SIG
))
113 if (cond
->sig
!= _PTHREAD_COND_SIG
)
117 if (cond
->sig
== _PTHREAD_COND_SIG_init
)
119 _pthread_cond_init(cond
, NULL
, 0);
121 } else if (cond
->sig
== _PTHREAD_KERN_COND_SIG
) {
122 int condid
= cond
->_pthread_cond_kernid
;
124 if (__pthread_cond_broadcast(condid
) == -1)
128 res
= EINVAL
; /* Not a condition variable */
132 else if ((sem
= cond
->sem
) == SEMAPHORE_NULL
)
134 /* Avoid kernel call since there are no waiters... */
141 PTHREAD_MACH_CALL(semaphore_signal_all(sem
), kern_res
);
145 if (cond
->waiters
== 0 && cond
->sigspending
== 0)
147 cond
->sem
= SEMAPHORE_NULL
;
148 restore_sem_to_pool(sem
);
151 if (kern_res
!= KERN_SUCCESS
)
157 * Signal a condition variable, waking a specified thread.
160 pthread_cond_signal_thread_np(pthread_cond_t
*cond
, pthread_t thread
)
162 kern_return_t kern_res
;
166 /* to provide backwards compat for apps using united condtn vars */
168 if((sig
!= _PTHREAD_COND_SIG
) && (sig
!= _PTHREAD_COND_SIG_init
) && (sig
!= _PTHREAD_KERN_COND_SIG
))
171 if (cond
->sig
!= _PTHREAD_COND_SIG
)
175 if (cond
->sig
== _PTHREAD_COND_SIG_init
)
177 _pthread_cond_init(cond
, NULL
, 0);
179 } else if (cond
->sig
== _PTHREAD_KERN_COND_SIG
) {
180 int condid
= cond
->_pthread_cond_kernid
;
182 if (__pthread_cond_signal(condid
) == -1)
186 ret
= EINVAL
; /* Not a condition variable */
190 else if ((sem
= cond
->sem
) == SEMAPHORE_NULL
)
192 /* Avoid kernel call since there are not enough waiters... */
199 if (thread
== (pthread_t
)NULL
)
201 kern_res
= semaphore_signal_thread(sem
, THREAD_NULL
);
202 if (kern_res
== KERN_NOT_WAITING
)
203 kern_res
= KERN_SUCCESS
;
205 else if (thread
->sig
== _PTHREAD_SIG
)
207 PTHREAD_MACH_CALL(semaphore_signal_thread(
208 sem
, pthread_mach_thread_np(thread
)), kern_res
);
211 kern_res
= KERN_FAILURE
;
215 if (cond
->waiters
== 0 && cond
->sigspending
== 0)
217 cond
->sem
= SEMAPHORE_NULL
;
218 restore_sem_to_pool(sem
);
221 if (kern_res
!= KERN_SUCCESS
)
227 * Signal a condition variable, waking only one thread.
230 pthread_cond_signal(pthread_cond_t
*cond
)
232 return pthread_cond_signal_thread_np(cond
, NULL
);
236 * Manage a list of condition variables associated with a mutex
240 _pthread_cond_add(pthread_cond_t
*cond
, pthread_mutex_t
*mutex
)
244 if ((c
= mutex
->busy
) != (pthread_cond_t
*)NULL
)
249 cond
->prev
= (pthread_cond_t
*)NULL
;
252 if (cond
->sem
== SEMAPHORE_NULL
)
253 cond
->sem
= new_sem_from_pool();
257 _pthread_cond_remove(pthread_cond_t
*cond
, pthread_mutex_t
*mutex
)
259 pthread_cond_t
*n
, *p
;
262 if ((n
= cond
->next
) != (pthread_cond_t
*)NULL
)
264 n
->prev
= cond
->prev
;
266 if ((p
= cond
->prev
) != (pthread_cond_t
*)NULL
)
268 p
->next
= cond
->next
;
271 { /* This is the first in the list */
275 if (cond
->sigspending
== 0)
277 restore_sem_to_pool(cond
->sem
);
278 cond
->sem
= SEMAPHORE_NULL
;
282 static void cond_cleanup(void *arg
)
284 pthread_cond_t
*cond
= (pthread_cond_t
*)arg
;
285 pthread_mutex_t
*mutex
;
287 pthread_t thread
= pthread_self();
291 thcanceled
= (thread
->detached
& _PTHREAD_WASCANCEL
);
292 UNLOCK(thread
->lock
);
301 if (cond
->waiters
== 0) {
302 _pthread_cond_remove(cond
, mutex
);
303 cond
->busy
= (pthread_mutex_t
*)NULL
;
308 ** Can't do anything if this fails -- we're on the way out
310 (void)pthread_mutex_lock(mutex
);
314 * Suspend waiting for a condition variable.
315 * Note: we have to keep a list of condition variables which are using
316 * this same mutex variable so we can detect invalid 'destroy' sequences.
317 * If isconforming < 0, we skip the _pthread_testcancel(), but keep the
318 * remaining conforming behavior..
320 __private_extern__
int
321 _pthread_cond_wait(pthread_cond_t
*cond
,
322 pthread_mutex_t
*mutex
,
323 const struct timespec
*abstime
,
327 int res
, saved_error
;
328 kern_return_t kern_res
;
330 pthread_mutex_t
*busy
;
331 mach_timespec_t then
;
332 struct timespec cthen
= {0,0};
334 int msig
= mutex
->sig
;
335 extern void _pthread_testcancel(pthread_t thread
, int isconforming
);
337 /* to provide backwards compat for apps using united condtn vars */
338 if((sig
!= _PTHREAD_COND_SIG
) && (sig
!= _PTHREAD_COND_SIG_init
) && (sig
!= _PTHREAD_KERN_COND_SIG
))
342 if((msig
!= _PTHREAD_MUTEX_SIG
) && (msig
!= _PTHREAD_MUTEX_SIG_init
) && (msig
!= _PTHREAD_KERN_MUTEX_SIG
))
344 if (isconforming
> 0)
345 _pthread_testcancel(pthread_self(), 1);
348 if (cond
->sig
!= _PTHREAD_COND_SIG
)
350 if (cond
->sig
!= _PTHREAD_COND_SIG_init
)
352 if ((cond
->sig
== _PTHREAD_KERN_COND_SIG
) && (mutex
->sig
== _PTHREAD_KERN_MUTEX_SIG
)) {
353 int condid
= cond
->_pthread_cond_kernid
;
354 int mutexid
= mutex
->_pthread_mutex_kernid
;
360 gettimeofday(&tv
, NULL
);
361 TIMEVAL_TO_TIMESPEC(&tv
, &now
);
363 /* Compute relative time to sleep */
364 then
.tv_nsec
= abstime
->tv_nsec
- now
.tv_nsec
;
365 then
.tv_sec
= abstime
->tv_sec
- now
.tv_sec
;
366 if (then
.tv_nsec
< 0)
368 then
.tv_nsec
+= NSEC_PER_SEC
;
371 if (((int)then
.tv_sec
< 0) ||
372 ((then
.tv_sec
== 0) && (then
.tv_nsec
== 0)))
377 if ((res
= pthread_mutex_unlock(mutex
)) != 0)
380 if ((__pthread_cond_timedwait(condid
, mutexid
, &then
)) == -1)
385 if ((res
= pthread_mutex_unlock(mutex
)) != 0)
387 if(( __pthread_cond_wait(condid
, mutexid
)) == -1)
392 if ((res
= pthread_mutex_lock(mutex
)) != 0)
397 return (EINVAL
); /* Not a condition variable */
400 _pthread_cond_init(cond
, NULL
, 0);
406 if (isRelative
== 0) {
409 gettimeofday(&tv
, NULL
);
410 TIMEVAL_TO_TIMESPEC(&tv
, &now
);
412 /* Compute relative time to sleep */
413 then
.tv_nsec
= abstime
->tv_nsec
- now
.tv_nsec
;
414 then
.tv_sec
= abstime
->tv_sec
- now
.tv_sec
;
415 if (then
.tv_nsec
< 0)
417 then
.tv_nsec
+= NSEC_PER_SEC
;
420 if (((int)then
.tv_sec
< 0) ||
421 ((then
.tv_sec
== 0) && (then
.tv_nsec
== 0)))
427 then
.tv_sec
= abstime
->tv_sec
;
428 then
.tv_nsec
= abstime
->tv_nsec
;
430 if (then
.tv_nsec
>= NSEC_PER_SEC
) {
435 if (isRelative
== 0) {
436 /* preflight the checks for failures */
439 gettimeofday(&tv
, NULL
);
440 TIMEVAL_TO_TIMESPEC(&tv
, &now
);
442 /* Compute relative time to sleep */
443 then
.tv_nsec
= abstime
->tv_nsec
- now
.tv_nsec
;
444 then
.tv_sec
= abstime
->tv_sec
- now
.tv_sec
;
445 if (then
.tv_nsec
< 0)
447 then
.tv_nsec
+= NSEC_PER_SEC
;
450 if (((int)then
.tv_sec
< 0) ||
451 ((then
.tv_sec
== 0) && (then
.tv_nsec
== 0)))
456 if (then
.tv_nsec
>= NSEC_PER_SEC
) {
461 /* we can cleanup this code and pass the calculated time
462 * to the kernel. But kernel is going to do the same. TILL
463 * we change the kernel do this anyway
465 cthen
.tv_sec
= abstime
->tv_sec
;
466 cthen
.tv_nsec
= abstime
->tv_nsec
;
467 if ((cthen
.tv_sec
< 0) || (cthen
.tv_nsec
< 0)) {
471 if (cthen
.tv_nsec
>= NSEC_PER_SEC
) {
478 if (++cond
->waiters
== 1)
480 _pthread_cond_add(cond
, mutex
);
483 else if ((busy
= cond
->busy
) != mutex
)
485 /* Must always specify the same mutex! */
493 _pthread_mutex_remove(mutex
, pthread_self());
496 if (--mutex
->lock_count
== 0)
498 PLOCKSTAT_MUTEX_RELEASE(mutex
, (mutex
->type
== PTHREAD_MUTEX_RECURSIVE
)? 1:0);
500 if (mutex
->sem
== SEMAPHORE_NULL
)
501 mutex
->sem
= new_sem_from_pool();
502 mutex
->owner
= _PTHREAD_MUTEX_OWNER_SWITCHING
;
507 kern_res
= semaphore_timedwait_signal(cond
->sem
, mutex
->sem
, then
);
509 PTHREAD_MACH_CALL(semaphore_wait_signal(cond
->sem
, mutex
->sem
), kern_res
);
512 pthread_cleanup_push(cond_cleanup
, (void *)cond
);
513 wait_res
= __semwait_signal(cond
->sem
, mutex
->sem
, abstime
!= NULL
, isRelative
,
514 cthen
.tv_sec
, cthen
.tv_nsec
);
515 pthread_cleanup_pop(0);
518 PLOCKSTAT_MUTEX_RELEASE(mutex
, (mutex
->type
== PTHREAD_MUTEX_RECURSIVE
)? 1:0);
522 kern_res
= semaphore_timedwait(cond
->sem
, then
);
524 PTHREAD_MACH_CALL(semaphore_wait(cond
->sem
), kern_res
);
527 pthread_cleanup_push(cond_cleanup
, (void *)cond
);
528 wait_res
= __semwait_signal(cond
->sem
, NULL
, abstime
!= NULL
, isRelative
,
529 cthen
.tv_sec
, cthen
.tv_nsec
);
530 pthread_cleanup_pop(0);
537 if (cond
->waiters
== 0)
539 _pthread_cond_remove(cond
, mutex
);
540 cond
->busy
= (pthread_mutex_t
*)NULL
;
543 if ((res
= pthread_mutex_lock(mutex
)) != 0)
547 /* KERN_ABORTED can be treated as a spurious wakeup */
548 if ((kern_res
== KERN_SUCCESS
) || (kern_res
== KERN_ABORTED
))
550 else if (kern_res
== KERN_OPERATION_TIMED_OUT
)
555 if (errno
== ETIMEDOUT
) {
557 } else if (errno
== EINTR
) {
559 ** EINTR can be treated as a spurious wakeup unless we were canceled.
571 pthread_cond_timedwait_relative_np(pthread_cond_t
*cond
,
572 pthread_mutex_t
*mutex
,
573 const struct timespec
*abstime
)
575 return (_pthread_cond_wait(cond
, mutex
, abstime
, 1, 0));
579 pthread_condattr_init(pthread_condattr_t
*attr
)
581 attr
->sig
= _PTHREAD_COND_ATTR_SIG
;
582 attr
->pshared
= _PTHREAD_DEFAULT_PSHARED
;
587 pthread_condattr_destroy(pthread_condattr_t
*attr
)
589 attr
->sig
= _PTHREAD_NO_SIG
; /* Uninitialized */
594 pthread_condattr_getpshared(const pthread_condattr_t
*attr
,
597 if (attr
->sig
== _PTHREAD_COND_ATTR_SIG
)
599 *pshared
= (int)attr
->pshared
;
603 return (EINVAL
); /* Not an initialized 'attribute' structure */
608 /* 5243343 - temporary hack to detect if we are running the conformance test */
609 extern int PR_5243343_flag
;
610 #endif /* PR_5243343 */
612 __private_extern__
int
613 _pthread_cond_init(pthread_cond_t
*cond
,
614 const pthread_condattr_t
*attr
,
617 cond
->next
= (pthread_cond_t
*)NULL
;
618 cond
->prev
= (pthread_cond_t
*)NULL
;
619 cond
->busy
= (pthread_mutex_t
*)NULL
;
621 cond
->sigspending
= 0;
624 cond
->pshared
= attr
->pshared
;
625 if (cond
->pshared
== PTHREAD_PROCESS_SHARED
) {
626 cond
->sem
= SEMAPHORE_NULL
;
628 if( __pthread_cond_init(cond
, attr
) == -1)
630 cond
->sig
= _PTHREAD_KERN_COND_SIG
;
635 cond
->pshared
= _PTHREAD_DEFAULT_PSHARED
;
637 cond
->pshared
= _PTHREAD_DEFAULT_PSHARED
;
638 cond
->sem
= SEMAPHORE_NULL
;
639 cond
->sig
= _PTHREAD_COND_SIG
;
644 /* temp home till pshared is fixed correctly */
646 pthread_condattr_setpshared(pthread_condattr_t
* attr
, int pshared
)
649 if (attr
->sig
== _PTHREAD_COND_ATTR_SIG
)
653 if (( pshared
== PTHREAD_PROCESS_PRIVATE
) || (pshared
== PTHREAD_PROCESS_SHARED
&& PR_5243343_flag
))
654 #else /* !PR_5243343 */
655 if (( pshared
== PTHREAD_PROCESS_PRIVATE
) || (pshared
== PTHREAD_PROCESS_SHARED
))
656 #endif /* PR_5243343 */
657 #else /* __DARWIN_UNIX03 */
658 if ( pshared
== PTHREAD_PROCESS_PRIVATE
)
659 #endif /* __DARWIN_UNIX03 */
661 attr
->pshared
= pshared
;
665 return (EINVAL
); /* Invalid parameter */
669 return (EINVAL
); /* Not an initialized 'attribute' structure */
675 #else /* !BUILDING_VARIANT */
676 extern int _pthread_cond_wait(pthread_cond_t
*cond
,
677 pthread_mutex_t
*mutex
,
678 const struct timespec
*abstime
,
683 _pthread_cond_init(pthread_cond_t
*cond
,
684 const pthread_condattr_t
*attr
,
687 #endif /* !BUILDING_VARIANT ] */
689 * Initialize a condition variable. Note: 'attr' is ignored.
693 * Initialize a condition variable. This is the public interface.
694 * We can't trust the lock, so initialize it first before taking
698 pthread_cond_init(pthread_cond_t
*cond
,
699 const pthread_condattr_t
*attr
)
705 #else /* __DARWIN_UNIX03 */
707 #endif /* __DARWIN_UNIX03 */
710 LOCK_INIT(cond
->lock
);
711 return (_pthread_cond_init(cond
, attr
, conforming
));
716 pthread_cond_wait(pthread_cond_t *cond,
717 pthread_mutex_t *mutex)
720 pthread_cond_timedwait(pthread_cond_t *cond,
721 pthread_mutex_t *mutex,
722 const struct timespec *abstime)
724 moved to pthread_cancelable.c */