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 */
61 extern void _pthread_mutex_remove(pthread_mutex_t
*, pthread_t
);
62 extern int __unix_conforming
;
64 #ifndef BUILDING_VARIANT /* [ */
67 * Destroy a condition variable.
70 pthread_cond_destroy(pthread_cond_t
*cond
)
75 /* to provide backwards compat for apps using united condtn vars */
76 if((sig
!= _PTHREAD_COND_SIG
) && (sig
!= _PTHREAD_COND_SIG_init
) && (sig
!= _PTHREAD_KERN_COND_SIG
))
80 if (cond
->sig
== _PTHREAD_COND_SIG
)
82 if (cond
->busy
== (pthread_mutex_t
*)NULL
)
84 cond
->sig
= _PTHREAD_NO_SIG
;
88 } else if (cond
->sig
== _PTHREAD_KERN_COND_SIG
) {
89 int condid
= cond
->_pthread_cond_kernid
;
91 if (__pthread_cond_destroy(condid
) == -1)
93 cond
->sig
= _PTHREAD_NO_SIG
;
96 ret
= EINVAL
; /* Not an initialized condition variable structure */
103 * Signal a condition variable, waking up all threads waiting for it.
106 pthread_cond_broadcast(pthread_cond_t
*cond
)
108 kern_return_t kern_res
;
112 /* to provide backwards compat for apps using united condtn vars */
113 if((sig
!= _PTHREAD_COND_SIG
) && (sig
!= _PTHREAD_COND_SIG_init
) && (sig
!= _PTHREAD_KERN_COND_SIG
))
117 if (cond
->sig
!= _PTHREAD_COND_SIG
)
121 if (cond
->sig
== _PTHREAD_COND_SIG_init
)
123 _pthread_cond_init(cond
, NULL
, 0);
125 } else if (cond
->sig
== _PTHREAD_KERN_COND_SIG
) {
126 int condid
= cond
->_pthread_cond_kernid
;
128 if (__pthread_cond_broadcast(condid
) == -1)
132 res
= EINVAL
; /* Not a condition variable */
136 else if ((sem
= cond
->sem
) == SEMAPHORE_NULL
)
138 /* Avoid kernel call since there are no waiters... */
145 PTHREAD_MACH_CALL(semaphore_signal_all(sem
), kern_res
);
149 if (cond
->waiters
== 0 && cond
->sigspending
== 0)
151 cond
->sem
= SEMAPHORE_NULL
;
152 restore_sem_to_pool(sem
);
155 if (kern_res
!= KERN_SUCCESS
)
161 * Signal a condition variable, waking a specified thread.
164 pthread_cond_signal_thread_np(pthread_cond_t
*cond
, pthread_t thread
)
166 kern_return_t kern_res
;
170 /* to provide backwards compat for apps using united condtn vars */
172 if((sig
!= _PTHREAD_COND_SIG
) && (sig
!= _PTHREAD_COND_SIG_init
) && (sig
!= _PTHREAD_KERN_COND_SIG
))
175 if (cond
->sig
!= _PTHREAD_COND_SIG
)
179 if (cond
->sig
== _PTHREAD_COND_SIG_init
)
181 _pthread_cond_init(cond
, NULL
, 0);
183 } else if (cond
->sig
== _PTHREAD_KERN_COND_SIG
) {
184 int condid
= cond
->_pthread_cond_kernid
;
186 if (__pthread_cond_signal(condid
) == -1)
190 ret
= EINVAL
; /* Not a condition variable */
194 else if ((sem
= cond
->sem
) == SEMAPHORE_NULL
)
196 /* Avoid kernel call since there are not enough waiters... */
203 if (thread
== (pthread_t
)NULL
)
205 kern_res
= semaphore_signal_thread(sem
, THREAD_NULL
);
206 if (kern_res
== KERN_NOT_WAITING
)
207 kern_res
= KERN_SUCCESS
;
209 else if (thread
->sig
== _PTHREAD_SIG
)
211 PTHREAD_MACH_CALL(semaphore_signal_thread(
212 sem
, pthread_mach_thread_np(thread
)), kern_res
);
215 kern_res
= KERN_FAILURE
;
219 if (cond
->waiters
== 0 && cond
->sigspending
== 0)
221 cond
->sem
= SEMAPHORE_NULL
;
222 restore_sem_to_pool(sem
);
225 if (kern_res
!= KERN_SUCCESS
)
231 * Signal a condition variable, waking only one thread.
234 pthread_cond_signal(pthread_cond_t
*cond
)
236 return pthread_cond_signal_thread_np(cond
, NULL
);
240 * Manage a list of condition variables associated with a mutex
244 _pthread_cond_add(pthread_cond_t
*cond
, pthread_mutex_t
*mutex
)
248 if ((c
= mutex
->busy
) != (pthread_cond_t
*)NULL
)
253 cond
->prev
= (pthread_cond_t
*)NULL
;
256 if (cond
->sem
== SEMAPHORE_NULL
)
257 cond
->sem
= new_sem_from_pool();
261 _pthread_cond_remove(pthread_cond_t
*cond
, pthread_mutex_t
*mutex
)
263 pthread_cond_t
*n
, *p
;
266 if ((n
= cond
->next
) != (pthread_cond_t
*)NULL
)
268 n
->prev
= cond
->prev
;
270 if ((p
= cond
->prev
) != (pthread_cond_t
*)NULL
)
272 p
->next
= cond
->next
;
275 { /* This is the first in the list */
279 if (cond
->sigspending
== 0)
281 restore_sem_to_pool(cond
->sem
);
282 cond
->sem
= SEMAPHORE_NULL
;
286 static void cond_cleanup(void *arg
)
288 pthread_cond_t
*cond
= (pthread_cond_t
*)arg
;
289 pthread_mutex_t
*mutex
;
291 pthread_t thread
= pthread_self();
295 thcanceled
= (thread
->detached
& _PTHREAD_WASCANCEL
);
296 UNLOCK(thread
->lock
);
305 if (cond
->waiters
== 0) {
306 _pthread_cond_remove(cond
, mutex
);
307 cond
->busy
= (pthread_mutex_t
*)NULL
;
312 ** Can't do anything if this fails -- we're on the way out
314 (void)pthread_mutex_lock(mutex
);
318 * Suspend waiting for a condition variable.
319 * Note: we have to keep a list of condition variables which are using
320 * this same mutex variable so we can detect invalid 'destroy' sequences.
321 * If isconforming < 0, we skip the _pthread_testcancel(), but keep the
322 * remaining conforming behavior..
324 __private_extern__
int
325 _pthread_cond_wait(pthread_cond_t
*cond
,
326 pthread_mutex_t
*mutex
,
327 const struct timespec
*abstime
,
331 int res
, saved_error
;
332 kern_return_t kern_res
;
334 pthread_mutex_t
*busy
;
335 mach_timespec_t then
;
336 struct timespec cthen
= {0,0};
338 int msig
= mutex
->sig
;
339 extern void _pthread_testcancel(pthread_t thread
, int isconforming
);
341 /* to provide backwards compat for apps using united condtn vars */
342 if((sig
!= _PTHREAD_COND_SIG
) && (sig
!= _PTHREAD_COND_SIG_init
) && (sig
!= _PTHREAD_KERN_COND_SIG
))
346 if((msig
!= _PTHREAD_MUTEX_SIG
) && (msig
!= _PTHREAD_MUTEX_SIG_init
) && (msig
!= _PTHREAD_KERN_MUTEX_SIG
))
348 if (isconforming
> 0)
349 _pthread_testcancel(pthread_self(), 1);
352 if (cond
->sig
!= _PTHREAD_COND_SIG
)
354 if (cond
->sig
!= _PTHREAD_COND_SIG_init
)
356 if ((cond
->sig
== _PTHREAD_KERN_COND_SIG
) && (mutex
->sig
== _PTHREAD_KERN_MUTEX_SIG
)) {
357 int condid
= cond
->_pthread_cond_kernid
;
358 int mutexid
= mutex
->_pthread_mutex_kernid
;
364 gettimeofday(&tv
, NULL
);
365 TIMEVAL_TO_TIMESPEC(&tv
, &now
);
367 /* Compute relative time to sleep */
368 then
.tv_nsec
= abstime
->tv_nsec
- now
.tv_nsec
;
369 then
.tv_sec
= abstime
->tv_sec
- now
.tv_sec
;
370 if (then
.tv_nsec
< 0)
372 then
.tv_nsec
+= NSEC_PER_SEC
;
375 if (((int)then
.tv_sec
< 0) ||
376 ((then
.tv_sec
== 0) && (then
.tv_nsec
== 0)))
381 if ((res
= pthread_mutex_unlock(mutex
)) != 0)
384 if ((__pthread_cond_timedwait(condid
, mutexid
, &then
)) == -1)
389 if ((res
= pthread_mutex_unlock(mutex
)) != 0)
391 if(( __pthread_cond_wait(condid
, mutexid
)) == -1)
396 if ((res
= pthread_mutex_lock(mutex
)) != 0)
401 return (EINVAL
); /* Not a condition variable */
404 _pthread_cond_init(cond
, NULL
, 0);
410 if (isRelative
== 0) {
413 gettimeofday(&tv
, NULL
);
414 TIMEVAL_TO_TIMESPEC(&tv
, &now
);
416 /* Compute relative time to sleep */
417 then
.tv_nsec
= abstime
->tv_nsec
- now
.tv_nsec
;
418 then
.tv_sec
= abstime
->tv_sec
- now
.tv_sec
;
419 if (then
.tv_nsec
< 0)
421 then
.tv_nsec
+= NSEC_PER_SEC
;
424 if (((int)then
.tv_sec
< 0) ||
425 ((then
.tv_sec
== 0) && (then
.tv_nsec
== 0)))
431 then
.tv_sec
= abstime
->tv_sec
;
432 then
.tv_nsec
= abstime
->tv_nsec
;
434 if (then
.tv_nsec
>= NSEC_PER_SEC
) {
439 if (isRelative
== 0) {
440 /* preflight the checks for failures */
443 gettimeofday(&tv
, NULL
);
444 TIMEVAL_TO_TIMESPEC(&tv
, &now
);
446 /* Compute relative time to sleep */
447 then
.tv_nsec
= abstime
->tv_nsec
- now
.tv_nsec
;
448 then
.tv_sec
= abstime
->tv_sec
- now
.tv_sec
;
449 if (then
.tv_nsec
< 0)
451 then
.tv_nsec
+= NSEC_PER_SEC
;
454 if (((int)then
.tv_sec
< 0) ||
455 ((then
.tv_sec
== 0) && (then
.tv_nsec
== 0)))
460 if (then
.tv_nsec
>= NSEC_PER_SEC
) {
465 /* we can cleanup this code and pass the calculated time
466 * to the kernel. But kernel is going to do the same. TILL
467 * we change the kernel do this anyway
469 cthen
.tv_sec
= abstime
->tv_sec
;
470 cthen
.tv_nsec
= abstime
->tv_nsec
;
471 if ((cthen
.tv_sec
< 0) || (cthen
.tv_nsec
< 0)) {
475 if (cthen
.tv_nsec
>= NSEC_PER_SEC
) {
482 if (++cond
->waiters
== 1)
484 _pthread_cond_add(cond
, mutex
);
487 else if ((busy
= cond
->busy
) != mutex
)
489 /* Must always specify the same mutex! */
497 _pthread_mutex_remove(mutex
, pthread_self());
500 if (--mutex
->lock_count
== 0)
502 PLOCKSTAT_MUTEX_RELEASE(mutex
, (mutex
->type
== PTHREAD_MUTEX_RECURSIVE
)? 1:0);
504 if (mutex
->sem
== SEMAPHORE_NULL
)
505 mutex
->sem
= new_sem_from_pool();
506 mutex
->owner
= _PTHREAD_MUTEX_OWNER_SWITCHING
;
511 kern_res
= semaphore_timedwait_signal(cond
->sem
, mutex
->sem
, then
);
513 PTHREAD_MACH_CALL(semaphore_wait_signal(cond
->sem
, mutex
->sem
), kern_res
);
516 pthread_cleanup_push(cond_cleanup
, (void *)cond
);
517 wait_res
= __semwait_signal(cond
->sem
, mutex
->sem
, abstime
!= NULL
, isRelative
,
518 cthen
.tv_sec
, cthen
.tv_nsec
);
519 pthread_cleanup_pop(0);
522 PLOCKSTAT_MUTEX_RELEASE(mutex
, (mutex
->type
== PTHREAD_MUTEX_RECURSIVE
)? 1:0);
526 kern_res
= semaphore_timedwait(cond
->sem
, then
);
528 PTHREAD_MACH_CALL(semaphore_wait(cond
->sem
), kern_res
);
531 pthread_cleanup_push(cond_cleanup
, (void *)cond
);
532 wait_res
= __semwait_signal(cond
->sem
, NULL
, abstime
!= NULL
, isRelative
,
533 cthen
.tv_sec
, cthen
.tv_nsec
);
534 pthread_cleanup_pop(0);
541 if (cond
->waiters
== 0)
543 _pthread_cond_remove(cond
, mutex
);
544 cond
->busy
= (pthread_mutex_t
*)NULL
;
547 if ((res
= pthread_mutex_lock(mutex
)) != 0)
551 /* KERN_ABORTED can be treated as a spurious wakeup */
552 if ((kern_res
== KERN_SUCCESS
) || (kern_res
== KERN_ABORTED
))
554 else if (kern_res
== KERN_OPERATION_TIMED_OUT
)
559 if (errno
== ETIMEDOUT
) {
561 } else if (errno
== EINTR
) {
563 ** EINTR can be treated as a spurious wakeup unless we were canceled.
575 pthread_cond_timedwait_relative_np(pthread_cond_t
*cond
,
576 pthread_mutex_t
*mutex
,
577 const struct timespec
*abstime
)
579 return (_pthread_cond_wait(cond
, mutex
, abstime
, 1, 0));
583 pthread_condattr_init(pthread_condattr_t
*attr
)
585 attr
->sig
= _PTHREAD_COND_ATTR_SIG
;
586 attr
->pshared
= _PTHREAD_DEFAULT_PSHARED
;
591 pthread_condattr_destroy(pthread_condattr_t
*attr
)
593 attr
->sig
= _PTHREAD_NO_SIG
; /* Uninitialized */
598 pthread_condattr_getpshared(const pthread_condattr_t
*attr
,
601 if (attr
->sig
== _PTHREAD_COND_ATTR_SIG
)
603 *pshared
= (int)attr
->pshared
;
607 return (EINVAL
); /* Not an initialized 'attribute' structure */
612 /* 5243343 - temporary hack to detect if we are running the conformance test */
613 extern int PR_5243343_flag
;
614 #endif /* PR_5243343 */
616 __private_extern__
int
617 _pthread_cond_init(pthread_cond_t
*cond
,
618 const pthread_condattr_t
*attr
,
621 cond
->next
= (pthread_cond_t
*)NULL
;
622 cond
->prev
= (pthread_cond_t
*)NULL
;
623 cond
->busy
= (pthread_mutex_t
*)NULL
;
625 cond
->sigspending
= 0;
628 cond
->pshared
= attr
->pshared
;
629 if (cond
->pshared
== PTHREAD_PROCESS_SHARED
) {
630 cond
->sem
= SEMAPHORE_NULL
;
632 if( __pthread_cond_init(cond
, attr
) == -1)
634 cond
->sig
= _PTHREAD_KERN_COND_SIG
;
639 cond
->pshared
= _PTHREAD_DEFAULT_PSHARED
;
641 cond
->pshared
= _PTHREAD_DEFAULT_PSHARED
;
642 cond
->sem
= SEMAPHORE_NULL
;
643 cond
->sig
= _PTHREAD_COND_SIG
;
648 /* temp home till pshared is fixed correctly */
650 pthread_condattr_setpshared(pthread_condattr_t
* attr
, int pshared
)
653 if (attr
->sig
== _PTHREAD_COND_ATTR_SIG
)
657 if (( pshared
== PTHREAD_PROCESS_PRIVATE
) || (pshared
== PTHREAD_PROCESS_SHARED
&& PR_5243343_flag
))
658 #else /* !PR_5243343 */
659 if (( pshared
== PTHREAD_PROCESS_PRIVATE
) || (pshared
== PTHREAD_PROCESS_SHARED
))
660 #endif /* PR_5243343 */
661 #else /* __DARWIN_UNIX03 */
662 if ( pshared
== PTHREAD_PROCESS_PRIVATE
)
663 #endif /* __DARWIN_UNIX03 */
665 attr
->pshared
= pshared
;
669 return (EINVAL
); /* Invalid parameter */
673 return (EINVAL
); /* Not an initialized 'attribute' structure */
679 #else /* !BUILDING_VARIANT */
680 extern int _pthread_cond_wait(pthread_cond_t
*cond
,
681 pthread_mutex_t
*mutex
,
682 const struct timespec
*abstime
,
687 _pthread_cond_init(pthread_cond_t
*cond
,
688 const pthread_condattr_t
*attr
,
691 #endif /* !BUILDING_VARIANT ] */
693 * Initialize a condition variable. Note: 'attr' is ignored.
697 * Initialize a condition variable. This is the public interface.
698 * We can't trust the lock, so initialize it first before taking
702 pthread_cond_init(pthread_cond_t
*cond
,
703 const pthread_condattr_t
*attr
)
709 #else /* __DARWIN_UNIX03 */
711 #endif /* __DARWIN_UNIX03 */
714 LOCK_INIT(cond
->lock
);
715 return (_pthread_cond_init(cond
, attr
, conforming
));
720 pthread_cond_wait(pthread_cond_t *cond,
721 pthread_mutex_t *mutex)
724 pthread_cond_timedwait(pthread_cond_t *cond,
725 pthread_mutex_t *mutex,
726 const struct timespec *abstime)
728 moved to pthread_cancelable.c */