]>
git.saurik.com Git - apple/libc.git/blob - pthreads/pthread_cond.c
409f23180c3efe08c01b918329836ab9d177d94a
2 * Copyright 1996 1995 by Open Software Foundation, Inc. 1997 1996 1995 1994 1993 1992 1991
5 * Permission to use, copy, modify, and distribute this software and
6 * its documentation for any purpose and without fee is hereby granted,
7 * provided that the above copyright notice appears in all copies and
8 * that both the copyright notice and this permission notice appear in
9 * supporting documentation.
11 * OSF DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
12 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
13 * FOR A PARTICULAR PURPOSE.
15 * IN NO EVENT SHALL OSF BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
16 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
17 * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
18 * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
19 * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
26 * POSIX Pthread Library
29 #include "pthread_internals.h"
30 #include <sys/time.h> /* For struct timespec and getclock(). */
34 * Destroy a condition variable.
37 pthread_cond_destroy(pthread_cond_t
*cond
)
39 if (cond
->sig
== _PTHREAD_COND_SIG
)
42 if (cond
->busy
!= (pthread_mutex_t
*)NULL
)
48 cond
->sig
= _PTHREAD_NO_SIG
;
53 return (EINVAL
); /* Not an initialized condition variable structure */
57 * Initialize a condition variable. Note: 'attr' is ignored.
60 pthread_cond_init(pthread_cond_t
*cond
,
61 const pthread_condattr_t
*attr
)
63 LOCK_INIT(cond
->lock
);
64 cond
->sig
= _PTHREAD_COND_SIG
;
65 cond
->next
= (pthread_cond_t
*)NULL
;
66 cond
->prev
= (pthread_cond_t
*)NULL
;
67 cond
->busy
= (pthread_mutex_t
*)NULL
;
69 cond
->sigspending
= 0;
70 cond
->sem
= MACH_PORT_NULL
;
75 * Signal a condition variable, waking up all threads waiting for it.
78 pthread_cond_broadcast(pthread_cond_t
*cond
)
80 kern_return_t kern_res
;
82 if (cond
->sig
== _PTHREAD_COND_SIG_init
) {
83 if ((res
= pthread_cond_init(cond
, NULL
)) != 0) {
87 if (cond
->sig
!= _PTHREAD_COND_SIG
) {
88 /* Not a condition variable */
92 if (cond
->sem
== MACH_PORT_NULL
) {
93 /* Avoid kernel call since there are no waiters... */
99 PTHREAD_MACH_CALL(semaphore_signal_all(cond
->sem
), kern_res
);
102 if (cond
->waiters
== 0 && cond
->sigspending
== 0) {
103 restore_sem_to_pool(cond
->sem
);
104 cond
->sem
= MACH_PORT_NULL
;
107 if (kern_res
!= KERN_SUCCESS
) {
114 * Signal a condition variable, waking a specified thread.
117 pthread_cond_signal_thread_np(pthread_cond_t
*cond
, pthread_t thread
)
119 kern_return_t kern_res
;
120 if (cond
->sig
== _PTHREAD_COND_SIG_init
) {
122 if ((res
= pthread_cond_init(cond
, NULL
)) != 0) {
126 if (cond
->sig
!= _PTHREAD_COND_SIG
) {
127 return (EINVAL
); /* Not a condition variable */
130 if (cond
->sem
== MACH_PORT_NULL
) {
131 /* Avoid kernel call since there are not enough waiters... */
137 if (thread
== (pthread_t
)NULL
) {
138 kern_res
= semaphore_signal_thread(cond
->sem
, MACH_PORT_NULL
);
139 if (kern_res
== KERN_INVALID_ARGUMENT
) {
140 PTHREAD_MACH_CALL(semaphore_signal(cond
->sem
), kern_res
);
141 } else if (kern_res
== KERN_NOT_WAITING
) {
142 kern_res
= KERN_SUCCESS
;
144 } else if (thread
->sig
== _PTHREAD_SIG
) {
145 PTHREAD_MACH_CALL(semaphore_signal_thread(
146 cond
->sem
, pthread_mach_thread_np(thread
)), kern_res
);
148 kern_res
= KERN_FAILURE
;
152 if (cond
->waiters
== 0 && cond
->sigspending
== 0) {
153 restore_sem_to_pool(cond
->sem
);
154 cond
->sem
= MACH_PORT_NULL
;
157 if (kern_res
!= KERN_SUCCESS
) {
164 * Signal a condition variable, waking only one thread.
167 pthread_cond_signal(pthread_cond_t
*cond
)
169 return pthread_cond_signal_thread_np(cond
, NULL
);
173 * Manage a list of condition variables associated with a mutex
177 _pthread_cond_add(pthread_cond_t
*cond
, pthread_mutex_t
*mutex
)
181 if ((c
= mutex
->busy
) != (pthread_cond_t
*)NULL
)
186 cond
->prev
= (pthread_cond_t
*)NULL
;
189 if (cond
->sem
== MACH_PORT_NULL
) {
190 cond
->sem
= new_sem_from_pool();
195 _pthread_cond_remove(pthread_cond_t
*cond
, pthread_mutex_t
*mutex
)
197 pthread_cond_t
*n
, *p
;
199 if ((n
= cond
->next
) != (pthread_cond_t
*)NULL
)
201 n
->prev
= cond
->prev
;
203 if ((p
= cond
->prev
) != (pthread_cond_t
*)NULL
)
205 p
->next
= cond
->next
;
207 { /* This is the first in the list */
211 if (cond
->sigspending
== 0) {
212 restore_sem_to_pool(cond
->sem
);
213 cond
->sem
= MACH_PORT_NULL
;
218 * Suspend waiting for a condition variable.
219 * Note: we have to keep a list of condition variables which are using
220 * this same mutex variable so we can detect invalid 'destroy' sequences.
223 _pthread_cond_wait(pthread_cond_t
*cond
,
224 pthread_mutex_t
*mutex
,
225 const struct timespec
*abstime
,
229 kern_return_t kern_res
;
230 pthread_mutex_t
*busy
;
231 mach_timespec_t then
;
232 if (cond
->sig
== _PTHREAD_COND_SIG_init
) {
233 if ((res
= pthread_cond_init(cond
, NULL
)) != 0) {
237 if (cond
->sig
!= _PTHREAD_COND_SIG
) {
238 /* Not a condition variable */
243 if (isRelative
== 0) {
246 gettimeofday(&tv
, NULL
);
247 TIMEVAL_TO_TIMESPEC(&tv
, &now
);
249 /* Compute relative time to sleep */
250 then
.tv_nsec
= abstime
->tv_nsec
- now
.tv_nsec
;
251 then
.tv_sec
= abstime
->tv_sec
- now
.tv_sec
;
252 if (then
.tv_nsec
< 0) {
253 then
.tv_nsec
+= NSEC_PER_SEC
;
256 if (((int)then
.tv_sec
< 0) ||
257 ((then
.tv_sec
== 0) && (then
.tv_nsec
== 0))) {
261 then
.tv_sec
= abstime
->tv_sec
;
262 then
.tv_nsec
= abstime
->tv_nsec
;
264 if (then
.tv_nsec
>= NSEC_PER_SEC
) {
270 if ((busy
!= (pthread_mutex_t
*)NULL
) && (busy
!= mutex
)) {
271 /* Must always specify the same mutex! */
276 if (cond
->waiters
== 1) {
277 _pthread_cond_add(cond
, mutex
);
282 if (mutex
->sem
== MACH_PORT_NULL
) {
283 mutex
->sem
= new_sem_from_pool();
285 mutex
->cond_lock
= 1;
288 kern_res
= semaphore_timedwait_signal(cond
->sem
, mutex
->sem
, then
);
290 PTHREAD_MACH_CALL(semaphore_wait_signal(cond
->sem
, mutex
->sem
), kern_res
);
294 if (cond
->waiters
== 0) {
295 _pthread_cond_remove(cond
, mutex
);
296 cond
->busy
= (pthread_mutex_t
*)NULL
;
299 if ((res
= pthread_mutex_lock(mutex
)) != ESUCCESS
) {
302 /* KERN_ABORTED can be treated as a spurious wakeup */
303 if ((kern_res
== KERN_SUCCESS
) || (kern_res
== KERN_ABORTED
)) {
305 } else if (kern_res
== KERN_OPERATION_TIMED_OUT
) {
313 pthread_cond_wait(pthread_cond_t
*cond
,
314 pthread_mutex_t
*mutex
)
316 return (_pthread_cond_wait(cond
, mutex
, (struct timespec
*)NULL
, 0));
320 pthread_cond_timedwait(pthread_cond_t
*cond
,
321 pthread_mutex_t
*mutex
,
322 const struct timespec
*abstime
)
324 return (_pthread_cond_wait(cond
, mutex
, abstime
, 0));
328 pthread_cond_timedwait_relative_np(pthread_cond_t
*cond
,
329 pthread_mutex_t
*mutex
,
330 const struct timespec
*abstime
)
332 return (_pthread_cond_wait(cond
, mutex
, abstime
, 1));
336 pthread_condattr_init(pthread_condattr_t
*attr
)
338 attr
->sig
= _PTHREAD_COND_ATTR_SIG
;
343 pthread_condattr_destroy(pthread_condattr_t
*attr
)
345 attr
->sig
= _PTHREAD_NO_SIG
; /* Uninitialized */
350 pthread_condattr_getpshared(const pthread_condattr_t
*attr
,
353 if (attr
->sig
== _PTHREAD_COND_ATTR_SIG
)
355 *pshared
= (int)PTHREAD_PROCESS_PRIVATE
;
359 return (EINVAL
); /* Not an initialized 'attribute' structure */
365 pthread_condattr_setpshared(pthread_condattr_t
* attr
, int pshared
)
367 if (attr
->sig
== _PTHREAD_COND_ATTR_SIG
)
369 if ( pshared
== PTHREAD_PROCESS_PRIVATE
)
371 /* attr->pshared = pshared */
375 return (EINVAL
); /* Invalid parameter */
379 return (EINVAL
); /* Not an initialized 'attribute' structure */