2 * Copyright (c) 2000-2003 Apple Computer, 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 extern void _pthread_mutex_remove(pthread_mutex_t
*, pthread_t
);
56 extern int __unix_conforming
;
58 #ifndef BUILDING_VARIANT /* [ */
61 * Destroy a condition variable.
64 pthread_cond_destroy(pthread_cond_t
*cond
)
69 /* to provide backwards compat for apps using united condtn vars */
70 if((sig
!= _PTHREAD_COND_SIG
) && (sig
!=_PTHREAD_COND_SIG_init
))
74 if (cond
->sig
== _PTHREAD_COND_SIG
)
76 if (cond
->busy
== (pthread_mutex_t
*)NULL
)
78 cond
->sig
= _PTHREAD_NO_SIG
;
83 ret
= EINVAL
; /* Not an initialized condition variable structure */
89 * Initialize a condition variable. Note: 'attr' is ignored.
92 _pthread_cond_init(pthread_cond_t
*cond
,
93 const pthread_condattr_t
*attr
)
95 cond
->next
= (pthread_cond_t
*)NULL
;
96 cond
->prev
= (pthread_cond_t
*)NULL
;
97 cond
->busy
= (pthread_mutex_t
*)NULL
;
99 cond
->sigspending
= 0;
100 cond
->sem
= SEMAPHORE_NULL
;
101 cond
->sig
= _PTHREAD_COND_SIG
;
106 * Initialize a condition variable. This is the public interface.
107 * We can't trust the lock, so initialize it first before taking
111 pthread_cond_init(pthread_cond_t
*cond
,
112 const pthread_condattr_t
*attr
)
114 LOCK_INIT(cond
->lock
);
115 return (_pthread_cond_init(cond
, attr
));
119 * Signal a condition variable, waking up all threads waiting for it.
122 pthread_cond_broadcast(pthread_cond_t
*cond
)
124 kern_return_t kern_res
;
128 /* to provide backwards compat for apps using united condtn vars */
129 if((sig
!= _PTHREAD_COND_SIG
) && (sig
!=_PTHREAD_COND_SIG_init
))
133 if (cond
->sig
!= _PTHREAD_COND_SIG
)
137 if (cond
->sig
== _PTHREAD_COND_SIG_init
)
139 _pthread_cond_init(cond
, NULL
);
142 res
= EINVAL
; /* Not a condition variable */
146 else if ((sem
= cond
->sem
) == SEMAPHORE_NULL
)
148 /* Avoid kernel call since there are no waiters... */
155 PTHREAD_MACH_CALL(semaphore_signal_all(sem
), kern_res
);
159 if (cond
->waiters
== 0 && cond
->sigspending
== 0)
161 cond
->sem
= SEMAPHORE_NULL
;
162 restore_sem_to_pool(sem
);
165 if (kern_res
!= KERN_SUCCESS
)
171 * Signal a condition variable, waking a specified thread.
174 pthread_cond_signal_thread_np(pthread_cond_t
*cond
, pthread_t thread
)
176 kern_return_t kern_res
;
180 /* to provide backwards compat for apps using united condtn vars */
181 if((sig
!= _PTHREAD_COND_SIG
) && (sig
!=_PTHREAD_COND_SIG_init
))
185 if (cond
->sig
!= _PTHREAD_COND_SIG
)
189 if (cond
->sig
== _PTHREAD_COND_SIG_init
)
191 _pthread_cond_init(cond
, NULL
);
195 ret
= EINVAL
; /* Not a condition variable */
199 else if ((sem
= cond
->sem
) == SEMAPHORE_NULL
)
201 /* Avoid kernel call since there are not enough waiters... */
208 if (thread
== (pthread_t
)NULL
)
210 kern_res
= semaphore_signal_thread(sem
, THREAD_NULL
);
211 if (kern_res
== KERN_NOT_WAITING
)
212 kern_res
= KERN_SUCCESS
;
214 else if (thread
->sig
== _PTHREAD_SIG
)
216 PTHREAD_MACH_CALL(semaphore_signal_thread(
217 sem
, pthread_mach_thread_np(thread
)), kern_res
);
220 kern_res
= KERN_FAILURE
;
224 if (cond
->waiters
== 0 && cond
->sigspending
== 0)
226 cond
->sem
= SEMAPHORE_NULL
;
227 restore_sem_to_pool(sem
);
230 if (kern_res
!= KERN_SUCCESS
)
236 * Signal a condition variable, waking only one thread.
239 pthread_cond_signal(pthread_cond_t
*cond
)
241 return pthread_cond_signal_thread_np(cond
, NULL
);
245 * Manage a list of condition variables associated with a mutex
249 _pthread_cond_add(pthread_cond_t
*cond
, pthread_mutex_t
*mutex
)
253 if ((c
= mutex
->busy
) != (pthread_cond_t
*)NULL
)
258 cond
->prev
= (pthread_cond_t
*)NULL
;
261 if (cond
->sem
== SEMAPHORE_NULL
)
262 cond
->sem
= new_sem_from_pool();
266 _pthread_cond_remove(pthread_cond_t
*cond
, pthread_mutex_t
*mutex
)
268 pthread_cond_t
*n
, *p
;
271 if ((n
= cond
->next
) != (pthread_cond_t
*)NULL
)
273 n
->prev
= cond
->prev
;
275 if ((p
= cond
->prev
) != (pthread_cond_t
*)NULL
)
277 p
->next
= cond
->next
;
280 { /* This is the first in the list */
284 if (cond
->sigspending
== 0)
286 restore_sem_to_pool(cond
->sem
);
287 cond
->sem
= SEMAPHORE_NULL
;
291 static void cond_cleanup(void *arg
)
293 pthread_cond_t
*cond
= (pthread_cond_t
*)arg
;
294 pthread_mutex_t
*mutex
;
298 if (cond
->waiters
== 0) {
299 _pthread_cond_remove(cond
, mutex
);
300 cond
->busy
= (pthread_mutex_t
*)NULL
;
304 ** Can't do anything if this fails -- we're on the way out
306 (void)pthread_mutex_lock(mutex
);
310 * Suspend waiting for a condition variable.
311 * Note: we have to keep a list of condition variables which are using
312 * this same mutex variable so we can detect invalid 'destroy' sequences.
314 __private_extern__
int
315 _pthread_cond_wait(pthread_cond_t
*cond
,
316 pthread_mutex_t
*mutex
,
317 const struct timespec
*abstime
,
322 kern_return_t kern_res
;
324 pthread_mutex_t
*busy
;
325 mach_timespec_t then
;
326 struct timespec cthen
= {0,0};
329 /* to provide backwards compat for apps using united condtn vars */
330 if((sig
!= _PTHREAD_COND_SIG
) && (sig
!=_PTHREAD_COND_SIG_init
))
333 if (cond
->sig
!= _PTHREAD_COND_SIG
)
335 if (cond
->sig
!= _PTHREAD_COND_SIG_init
)
338 return (EINVAL
); /* Not a condition variable */
340 _pthread_cond_init(cond
, NULL
);
346 if (isRelative
== 0) {
349 gettimeofday(&tv
, NULL
);
350 TIMEVAL_TO_TIMESPEC(&tv
, &now
);
352 /* Compute relative time to sleep */
353 then
.tv_nsec
= abstime
->tv_nsec
- now
.tv_nsec
;
354 then
.tv_sec
= abstime
->tv_sec
- now
.tv_sec
;
355 if (then
.tv_nsec
< 0)
357 then
.tv_nsec
+= NSEC_PER_SEC
;
360 if (((int)then
.tv_sec
< 0) ||
361 ((then
.tv_sec
== 0) && (then
.tv_nsec
== 0)))
367 then
.tv_sec
= abstime
->tv_sec
;
368 then
.tv_nsec
= abstime
->tv_nsec
;
370 if (then
.tv_nsec
>= NSEC_PER_SEC
) {
375 cthen
.tv_sec
= abstime
->tv_sec
;
376 cthen
.tv_nsec
= abstime
->tv_nsec
;
377 if ((cthen
.tv_sec
< 0) || (cthen
.tv_nsec
< 0)) {
381 if (cthen
.tv_nsec
>= NSEC_PER_SEC
) {
388 if (++cond
->waiters
== 1)
390 _pthread_cond_add(cond
, mutex
);
393 else if ((busy
= cond
->busy
) != mutex
)
395 /* Must always specify the same mutex! */
403 _pthread_mutex_remove(mutex
, pthread_self());
406 if (--mutex
->lock_count
== 0)
408 if (mutex
->sem
== SEMAPHORE_NULL
)
409 mutex
->sem
= new_sem_from_pool();
410 mutex
->owner
= _PTHREAD_MUTEX_OWNER_SWITCHING
;
415 kern_res
= semaphore_timedwait_signal(cond
->sem
, mutex
->sem
, then
);
417 PTHREAD_MACH_CALL(semaphore_wait_signal(cond
->sem
, mutex
->sem
), kern_res
);
420 pthread_cleanup_push(cond_cleanup
, (void *)cond
);
421 wait_res
= __semwait_signal(cond
->sem
, mutex
->sem
, abstime
!= NULL
, isRelative
,
422 cthen
.tv_sec
, cthen
.tv_nsec
);
423 pthread_cleanup_pop(0);
429 kern_res
= semaphore_timedwait(cond
->sem
, then
);
431 PTHREAD_MACH_CALL(semaphore_wait(cond
->sem
), kern_res
);
434 pthread_cleanup_push(cond_cleanup
, (void *)cond
);
435 wait_res
= __semwait_signal(cond
->sem
, NULL
, abstime
!= NULL
, isRelative
,
436 cthen
.tv_sec
, cthen
.tv_nsec
);
437 pthread_cleanup_pop(0);
444 if (cond
->waiters
== 0)
446 _pthread_cond_remove(cond
, mutex
);
447 cond
->busy
= (pthread_mutex_t
*)NULL
;
450 if ((res
= pthread_mutex_lock(mutex
)) != ESUCCESS
)
454 /* KERN_ABORTED can be treated as a spurious wakeup */
455 if ((kern_res
== KERN_SUCCESS
) || (kern_res
== KERN_ABORTED
))
457 else if (kern_res
== KERN_OPERATION_TIMED_OUT
)
462 if (errno
== ETIMEDOUT
) {
464 } else if (errno
== EINTR
) {
466 ** EINTR can be treated as a spurious wakeup unless we were canceled.
478 pthread_cond_timedwait_relative_np(pthread_cond_t
*cond
,
479 pthread_mutex_t
*mutex
,
480 const struct timespec
*abstime
)
482 return (_pthread_cond_wait(cond
, mutex
, abstime
, 1, 0));
486 pthread_condattr_init(pthread_condattr_t
*attr
)
488 attr
->sig
= _PTHREAD_COND_ATTR_SIG
;
493 pthread_condattr_destroy(pthread_condattr_t
*attr
)
495 attr
->sig
= _PTHREAD_NO_SIG
; /* Uninitialized */
500 pthread_condattr_getpshared(const pthread_condattr_t
*attr
,
503 if (attr
->sig
== _PTHREAD_COND_ATTR_SIG
)
505 *pshared
= (int)PTHREAD_PROCESS_PRIVATE
;
509 return (EINVAL
); /* Not an initialized 'attribute' structure */
515 pthread_condattr_setpshared(pthread_condattr_t
* attr
, int pshared
)
517 if (attr
->sig
== _PTHREAD_COND_ATTR_SIG
)
519 if ( pshared
== PTHREAD_PROCESS_PRIVATE
)
521 /* attr->pshared = pshared */
525 return (EINVAL
); /* Invalid parameter */
529 return (EINVAL
); /* Not an initialized 'attribute' structure */
534 #else /* !BUILDING_VARIANT */
535 extern int _pthread_cond_wait(pthread_cond_t
*cond
,
536 pthread_mutex_t
*mutex
,
537 const struct timespec
*abstime
,
541 #endif /* !BUILDING_VARIANT ] */
544 pthread_cond_wait(pthread_cond_t
*cond
,
545 pthread_mutex_t
*mutex
)
550 if (__unix_conforming
== 0)
551 __unix_conforming
= 1;
554 #else /* __DARWIN_UNIX03 */
556 #endif /* __DARWIN_UNIX03 */
557 return (_pthread_cond_wait(cond
, mutex
, (struct timespec
*)NULL
, 0, conforming
));
561 pthread_cond_timedwait(pthread_cond_t
*cond
,
562 pthread_mutex_t
*mutex
,
563 const struct timespec
*abstime
)
567 if (__unix_conforming
== 0)
568 __unix_conforming
= 1;
571 #else /* __DARWIN_UNIX03 */
573 #endif /* __DARWIN_UNIX03 */
575 return (_pthread_cond_wait(cond
, mutex
, abstime
, 0, conforming
));