2 * Copyright (c) 2000-2003 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
23 * @APPLE_LICENSE_HEADER_END@
26 * Copyright 1996 1995 by Open Software Foundation, Inc. 1997 1996 1995 1994 1993 1992 1991
29 * Permission to use, copy, modify, and distribute this software and
30 * its documentation for any purpose and without fee is hereby granted,
31 * provided that the above copyright notice appears in all copies and
32 * that both the copyright notice and this permission notice appear in
33 * supporting documentation.
35 * OSF DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
36 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
37 * FOR A PARTICULAR PURPOSE.
39 * IN NO EVENT SHALL OSF BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
40 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
41 * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
42 * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
43 * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
50 * POSIX Pthread Library
53 #include "pthread_internals.h"
54 #include <sys/time.h> /* For struct timespec and getclock(). */
57 extern void _pthread_mutex_remove(pthread_mutex_t
*, pthread_t
);
60 * Destroy a condition variable.
63 pthread_cond_destroy(pthread_cond_t
*cond
)
68 /* to provide backwards compat for apps using united condtn vars */
69 if((sig
!= _PTHREAD_COND_SIG
) && (sig
!=_PTHREAD_COND_SIG_init
))
73 if (cond
->sig
== _PTHREAD_COND_SIG
)
75 if (cond
->busy
== (pthread_mutex_t
*)NULL
)
77 cond
->sig
= _PTHREAD_NO_SIG
;
82 ret
= EINVAL
; /* Not an initialized condition variable structure */
88 * Initialize a condition variable. Note: 'attr' is ignored.
91 _pthread_cond_init(pthread_cond_t
*cond
,
92 const pthread_condattr_t
*attr
)
94 cond
->next
= (pthread_cond_t
*)NULL
;
95 cond
->prev
= (pthread_cond_t
*)NULL
;
96 cond
->busy
= (pthread_mutex_t
*)NULL
;
98 cond
->sigspending
= 0;
99 cond
->sem
= SEMAPHORE_NULL
;
100 cond
->sig
= _PTHREAD_COND_SIG
;
105 * Initialize a condition variable. This is the public interface.
106 * We can't trust the lock, so initialize it first before taking
110 pthread_cond_init(pthread_cond_t
*cond
,
111 const pthread_condattr_t
*attr
)
113 LOCK_INIT(cond
->lock
);
114 return (_pthread_cond_init(cond
, attr
));
118 * Signal a condition variable, waking up all threads waiting for it.
121 pthread_cond_broadcast(pthread_cond_t
*cond
)
123 kern_return_t kern_res
;
127 /* to provide backwards compat for apps using united condtn vars */
128 if((sig
!= _PTHREAD_COND_SIG
) && (sig
!=_PTHREAD_COND_SIG_init
))
132 if (cond
->sig
!= _PTHREAD_COND_SIG
)
136 if (cond
->sig
== _PTHREAD_COND_SIG_init
)
138 _pthread_cond_init(cond
, NULL
);
141 res
= EINVAL
; /* Not a condition variable */
145 else if ((sem
= cond
->sem
) == SEMAPHORE_NULL
)
147 /* Avoid kernel call since there are no waiters... */
154 PTHREAD_MACH_CALL(semaphore_signal_all(sem
), kern_res
);
158 if (cond
->waiters
== 0 && cond
->sigspending
== 0)
160 cond
->sem
= SEMAPHORE_NULL
;
161 restore_sem_to_pool(sem
);
164 if (kern_res
!= KERN_SUCCESS
)
170 * Signal a condition variable, waking a specified thread.
173 pthread_cond_signal_thread_np(pthread_cond_t
*cond
, pthread_t thread
)
175 kern_return_t kern_res
;
179 /* to provide backwards compat for apps using united condtn vars */
180 if((sig
!= _PTHREAD_COND_SIG
) && (sig
!=_PTHREAD_COND_SIG_init
))
184 if (cond
->sig
!= _PTHREAD_COND_SIG
)
188 if (cond
->sig
== _PTHREAD_COND_SIG_init
)
190 _pthread_cond_init(cond
, NULL
);
194 ret
= EINVAL
; /* Not a condition variable */
198 else if ((sem
= cond
->sem
) == SEMAPHORE_NULL
)
200 /* Avoid kernel call since there are not enough waiters... */
207 if (thread
== (pthread_t
)NULL
)
209 kern_res
= semaphore_signal_thread(sem
, THREAD_NULL
);
210 if (kern_res
== KERN_NOT_WAITING
)
211 kern_res
= KERN_SUCCESS
;
213 else if (thread
->sig
== _PTHREAD_SIG
)
215 PTHREAD_MACH_CALL(semaphore_signal_thread(
216 sem
, pthread_mach_thread_np(thread
)), kern_res
);
219 kern_res
= KERN_FAILURE
;
223 if (cond
->waiters
== 0 && cond
->sigspending
== 0)
225 cond
->sem
= SEMAPHORE_NULL
;
226 restore_sem_to_pool(sem
);
229 if (kern_res
!= KERN_SUCCESS
)
235 * Signal a condition variable, waking only one thread.
238 pthread_cond_signal(pthread_cond_t
*cond
)
240 return pthread_cond_signal_thread_np(cond
, NULL
);
244 * Manage a list of condition variables associated with a mutex
248 _pthread_cond_add(pthread_cond_t
*cond
, pthread_mutex_t
*mutex
)
252 if ((c
= mutex
->busy
) != (pthread_cond_t
*)NULL
)
257 cond
->prev
= (pthread_cond_t
*)NULL
;
260 if (cond
->sem
== SEMAPHORE_NULL
)
261 cond
->sem
= new_sem_from_pool();
265 _pthread_cond_remove(pthread_cond_t
*cond
, pthread_mutex_t
*mutex
)
267 pthread_cond_t
*n
, *p
;
270 if ((n
= cond
->next
) != (pthread_cond_t
*)NULL
)
272 n
->prev
= cond
->prev
;
274 if ((p
= cond
->prev
) != (pthread_cond_t
*)NULL
)
276 p
->next
= cond
->next
;
279 { /* This is the first in the list */
283 if (cond
->sigspending
== 0)
285 restore_sem_to_pool(cond
->sem
);
286 cond
->sem
= SEMAPHORE_NULL
;
291 * Suspend waiting for a condition variable.
292 * Note: we have to keep a list of condition variables which are using
293 * this same mutex variable so we can detect invalid 'destroy' sequences.
296 _pthread_cond_wait(pthread_cond_t
*cond
,
297 pthread_mutex_t
*mutex
,
298 const struct timespec
*abstime
,
302 kern_return_t kern_res
;
303 pthread_mutex_t
*busy
;
304 mach_timespec_t then
;
307 /* to provide backwards compat for apps using united condtn vars */
308 if((sig
!= _PTHREAD_COND_SIG
) && (sig
!=_PTHREAD_COND_SIG_init
))
311 if (cond
->sig
!= _PTHREAD_COND_SIG
)
313 if (cond
->sig
!= _PTHREAD_COND_SIG_init
)
316 return (EINVAL
); /* Not a condition variable */
318 _pthread_cond_init(cond
, NULL
);
327 gettimeofday(&tv
, NULL
);
328 TIMEVAL_TO_TIMESPEC(&tv
, &now
);
330 /* Compute relative time to sleep */
331 then
.tv_nsec
= abstime
->tv_nsec
- now
.tv_nsec
;
332 then
.tv_sec
= abstime
->tv_sec
- now
.tv_sec
;
333 if (then
.tv_nsec
< 0)
335 then
.tv_nsec
+= NSEC_PER_SEC
;
338 if (((int)then
.tv_sec
< 0) ||
339 ((then
.tv_sec
== 0) && (then
.tv_nsec
== 0)))
347 then
.tv_sec
= abstime
->tv_sec
;
348 then
.tv_nsec
= abstime
->tv_nsec
;
350 if (then
.tv_nsec
>= NSEC_PER_SEC
)
357 if (++cond
->waiters
== 1)
359 _pthread_cond_add(cond
, mutex
);
362 else if ((busy
= cond
->busy
) != mutex
)
364 /* Must always specify the same mutex! */
372 _pthread_mutex_remove(mutex
, pthread_self());
375 if (--mutex
->lock_count
== 0)
377 if (mutex
->sem
== SEMAPHORE_NULL
)
378 mutex
->sem
= new_sem_from_pool();
379 mutex
->owner
= _PTHREAD_MUTEX_OWNER_SWITCHING
;
383 kern_res
= semaphore_timedwait_signal(cond
->sem
, mutex
->sem
, then
);
385 PTHREAD_MACH_CALL(semaphore_wait_signal(cond
->sem
, mutex
->sem
), kern_res
);
392 kern_res
= semaphore_timedwait(cond
->sem
, then
);
394 PTHREAD_MACH_CALL(semaphore_wait(cond
->sem
), kern_res
);
400 if (cond
->waiters
== 0)
402 _pthread_cond_remove(cond
, mutex
);
403 cond
->busy
= (pthread_mutex_t
*)NULL
;
406 if ((res
= pthread_mutex_lock(mutex
)) != ESUCCESS
)
409 /* KERN_ABORTED can be treated as a spurious wakeup */
410 if ((kern_res
== KERN_SUCCESS
) || (kern_res
== KERN_ABORTED
))
412 else if (kern_res
== KERN_OPERATION_TIMED_OUT
)
418 pthread_cond_wait(pthread_cond_t
*cond
,
419 pthread_mutex_t
*mutex
)
421 return (_pthread_cond_wait(cond
, mutex
, (struct timespec
*)NULL
, 0));
425 pthread_cond_timedwait(pthread_cond_t
*cond
,
426 pthread_mutex_t
*mutex
,
427 const struct timespec
*abstime
)
429 return (_pthread_cond_wait(cond
, mutex
, abstime
, 0));
433 pthread_cond_timedwait_relative_np(pthread_cond_t
*cond
,
434 pthread_mutex_t
*mutex
,
435 const struct timespec
*abstime
)
437 return (_pthread_cond_wait(cond
, mutex
, abstime
, 1));
441 pthread_condattr_init(pthread_condattr_t
*attr
)
443 attr
->sig
= _PTHREAD_COND_ATTR_SIG
;
448 pthread_condattr_destroy(pthread_condattr_t
*attr
)
450 attr
->sig
= _PTHREAD_NO_SIG
; /* Uninitialized */
455 pthread_condattr_getpshared(const pthread_condattr_t
*attr
,
458 if (attr
->sig
== _PTHREAD_COND_ATTR_SIG
)
460 *pshared
= (int)PTHREAD_PROCESS_PRIVATE
;
464 return (EINVAL
); /* Not an initialized 'attribute' structure */
470 pthread_condattr_setpshared(pthread_condattr_t
* attr
, int pshared
)
472 if (attr
->sig
== _PTHREAD_COND_ATTR_SIG
)
474 if ( pshared
== PTHREAD_PROCESS_PRIVATE
)
476 /* attr->pshared = pshared */
480 return (EINVAL
); /* Invalid parameter */
484 return (EINVAL
); /* Not an initialized 'attribute' structure */