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
);
58 * Destroy a condition variable.
61 pthread_cond_destroy(pthread_cond_t
*cond
)
66 /* to provide backwards compat for apps using united condtn vars */
67 if((sig
!= _PTHREAD_COND_SIG
) && (sig
!=_PTHREAD_COND_SIG_init
))
71 if (cond
->sig
== _PTHREAD_COND_SIG
)
73 if (cond
->busy
== (pthread_mutex_t
*)NULL
)
75 cond
->sig
= _PTHREAD_NO_SIG
;
80 ret
= EINVAL
; /* Not an initialized condition variable structure */
86 * Initialize a condition variable. Note: 'attr' is ignored.
89 _pthread_cond_init(pthread_cond_t
*cond
,
90 const pthread_condattr_t
*attr
)
92 cond
->next
= (pthread_cond_t
*)NULL
;
93 cond
->prev
= (pthread_cond_t
*)NULL
;
94 cond
->busy
= (pthread_mutex_t
*)NULL
;
96 cond
->sigspending
= 0;
97 cond
->sem
= SEMAPHORE_NULL
;
98 cond
->sig
= _PTHREAD_COND_SIG
;
103 * Initialize a condition variable. This is the public interface.
104 * We can't trust the lock, so initialize it first before taking
108 pthread_cond_init(pthread_cond_t
*cond
,
109 const pthread_condattr_t
*attr
)
111 LOCK_INIT(cond
->lock
);
112 return (_pthread_cond_init(cond
, attr
));
116 * Signal a condition variable, waking up all threads waiting for it.
119 pthread_cond_broadcast(pthread_cond_t
*cond
)
121 kern_return_t kern_res
;
125 /* to provide backwards compat for apps using united condtn vars */
126 if((sig
!= _PTHREAD_COND_SIG
) && (sig
!=_PTHREAD_COND_SIG_init
))
130 if (cond
->sig
!= _PTHREAD_COND_SIG
)
134 if (cond
->sig
== _PTHREAD_COND_SIG_init
)
136 _pthread_cond_init(cond
, NULL
);
139 res
= EINVAL
; /* Not a condition variable */
143 else if ((sem
= cond
->sem
) == SEMAPHORE_NULL
)
145 /* Avoid kernel call since there are no waiters... */
152 PTHREAD_MACH_CALL(semaphore_signal_all(sem
), kern_res
);
156 if (cond
->waiters
== 0 && cond
->sigspending
== 0)
158 cond
->sem
= SEMAPHORE_NULL
;
159 restore_sem_to_pool(sem
);
162 if (kern_res
!= KERN_SUCCESS
)
168 * Signal a condition variable, waking a specified thread.
171 pthread_cond_signal_thread_np(pthread_cond_t
*cond
, pthread_t thread
)
173 kern_return_t kern_res
;
177 /* to provide backwards compat for apps using united condtn vars */
178 if((sig
!= _PTHREAD_COND_SIG
) && (sig
!=_PTHREAD_COND_SIG_init
))
182 if (cond
->sig
!= _PTHREAD_COND_SIG
)
186 if (cond
->sig
== _PTHREAD_COND_SIG_init
)
188 _pthread_cond_init(cond
, NULL
);
192 ret
= EINVAL
; /* Not a condition variable */
196 else if ((sem
= cond
->sem
) == SEMAPHORE_NULL
)
198 /* Avoid kernel call since there are not enough waiters... */
205 if (thread
== (pthread_t
)NULL
)
207 kern_res
= semaphore_signal_thread(sem
, THREAD_NULL
);
208 if (kern_res
== KERN_NOT_WAITING
)
209 kern_res
= KERN_SUCCESS
;
211 else if (thread
->sig
== _PTHREAD_SIG
)
213 PTHREAD_MACH_CALL(semaphore_signal_thread(
214 sem
, pthread_mach_thread_np(thread
)), kern_res
);
217 kern_res
= KERN_FAILURE
;
221 if (cond
->waiters
== 0 && cond
->sigspending
== 0)
223 cond
->sem
= SEMAPHORE_NULL
;
224 restore_sem_to_pool(sem
);
227 if (kern_res
!= KERN_SUCCESS
)
233 * Signal a condition variable, waking only one thread.
236 pthread_cond_signal(pthread_cond_t
*cond
)
238 return pthread_cond_signal_thread_np(cond
, NULL
);
242 * Manage a list of condition variables associated with a mutex
246 _pthread_cond_add(pthread_cond_t
*cond
, pthread_mutex_t
*mutex
)
250 if ((c
= mutex
->busy
) != (pthread_cond_t
*)NULL
)
255 cond
->prev
= (pthread_cond_t
*)NULL
;
258 if (cond
->sem
== SEMAPHORE_NULL
)
259 cond
->sem
= new_sem_from_pool();
263 _pthread_cond_remove(pthread_cond_t
*cond
, pthread_mutex_t
*mutex
)
265 pthread_cond_t
*n
, *p
;
268 if ((n
= cond
->next
) != (pthread_cond_t
*)NULL
)
270 n
->prev
= cond
->prev
;
272 if ((p
= cond
->prev
) != (pthread_cond_t
*)NULL
)
274 p
->next
= cond
->next
;
277 { /* This is the first in the list */
281 if (cond
->sigspending
== 0)
283 restore_sem_to_pool(cond
->sem
);
284 cond
->sem
= SEMAPHORE_NULL
;
289 * Suspend waiting for a condition variable.
290 * Note: we have to keep a list of condition variables which are using
291 * this same mutex variable so we can detect invalid 'destroy' sequences.
294 _pthread_cond_wait(pthread_cond_t
*cond
,
295 pthread_mutex_t
*mutex
,
296 const struct timespec
*abstime
,
300 kern_return_t kern_res
;
301 pthread_mutex_t
*busy
;
302 mach_timespec_t then
;
305 /* to provide backwards compat for apps using united condtn vars */
306 if((sig
!= _PTHREAD_COND_SIG
) && (sig
!=_PTHREAD_COND_SIG_init
))
309 if (cond
->sig
!= _PTHREAD_COND_SIG
)
311 if (cond
->sig
!= _PTHREAD_COND_SIG_init
)
314 return (EINVAL
); /* Not a condition variable */
316 _pthread_cond_init(cond
, NULL
);
325 gettimeofday(&tv
, NULL
);
326 TIMEVAL_TO_TIMESPEC(&tv
, &now
);
328 /* Compute relative time to sleep */
329 then
.tv_nsec
= abstime
->tv_nsec
- now
.tv_nsec
;
330 then
.tv_sec
= abstime
->tv_sec
- now
.tv_sec
;
331 if (then
.tv_nsec
< 0)
333 then
.tv_nsec
+= NSEC_PER_SEC
;
336 if (((int)then
.tv_sec
< 0) ||
337 ((then
.tv_sec
== 0) && (then
.tv_nsec
== 0)))
345 then
.tv_sec
= abstime
->tv_sec
;
346 then
.tv_nsec
= abstime
->tv_nsec
;
348 if (then
.tv_nsec
>= NSEC_PER_SEC
)
355 if (++cond
->waiters
== 1)
357 _pthread_cond_add(cond
, mutex
);
360 else if ((busy
= cond
->busy
) != mutex
)
362 /* Must always specify the same mutex! */
370 _pthread_mutex_remove(mutex
, pthread_self());
373 if (--mutex
->lock_count
== 0)
375 if (mutex
->sem
== SEMAPHORE_NULL
)
376 mutex
->sem
= new_sem_from_pool();
377 mutex
->owner
= _PTHREAD_MUTEX_OWNER_SWITCHING
;
381 kern_res
= semaphore_timedwait_signal(cond
->sem
, mutex
->sem
, then
);
383 PTHREAD_MACH_CALL(semaphore_wait_signal(cond
->sem
, mutex
->sem
), kern_res
);
390 kern_res
= semaphore_timedwait(cond
->sem
, then
);
392 PTHREAD_MACH_CALL(semaphore_wait(cond
->sem
), kern_res
);
398 if (cond
->waiters
== 0)
400 _pthread_cond_remove(cond
, mutex
);
401 cond
->busy
= (pthread_mutex_t
*)NULL
;
404 if ((res
= pthread_mutex_lock(mutex
)) != ESUCCESS
)
407 /* KERN_ABORTED can be treated as a spurious wakeup */
408 if ((kern_res
== KERN_SUCCESS
) || (kern_res
== KERN_ABORTED
))
410 else if (kern_res
== KERN_OPERATION_TIMED_OUT
)
416 pthread_cond_wait(pthread_cond_t
*cond
,
417 pthread_mutex_t
*mutex
)
419 return (_pthread_cond_wait(cond
, mutex
, (struct timespec
*)NULL
, 0));
423 pthread_cond_timedwait(pthread_cond_t
*cond
,
424 pthread_mutex_t
*mutex
,
425 const struct timespec
*abstime
)
427 return (_pthread_cond_wait(cond
, mutex
, abstime
, 0));
431 pthread_cond_timedwait_relative_np(pthread_cond_t
*cond
,
432 pthread_mutex_t
*mutex
,
433 const struct timespec
*abstime
)
435 return (_pthread_cond_wait(cond
, mutex
, abstime
, 1));
439 pthread_condattr_init(pthread_condattr_t
*attr
)
441 attr
->sig
= _PTHREAD_COND_ATTR_SIG
;
446 pthread_condattr_destroy(pthread_condattr_t
*attr
)
448 attr
->sig
= _PTHREAD_NO_SIG
; /* Uninitialized */
453 pthread_condattr_getpshared(const pthread_condattr_t
*attr
,
456 if (attr
->sig
== _PTHREAD_COND_ATTR_SIG
)
458 *pshared
= (int)PTHREAD_PROCESS_PRIVATE
;
462 return (EINVAL
); /* Not an initialized 'attribute' structure */
468 pthread_condattr_setpshared(pthread_condattr_t
* attr
, int pshared
)
470 if (attr
->sig
== _PTHREAD_COND_ATTR_SIG
)
472 if ( pshared
== PTHREAD_PROCESS_PRIVATE
)
474 /* attr->pshared = pshared */
478 return (EINVAL
); /* Invalid parameter */
482 return (EINVAL
); /* Not an initialized 'attribute' structure */