]> git.saurik.com Git - apple/libc.git/blame - pthreads.subproj/pthread_cond.c
Libc-186.tar.gz
[apple/libc.git] / pthreads.subproj / pthread_cond.c
CommitLineData
e9ce8d39
A
1/*
2 * Copyright 1996 1995 by Open Software Foundation, Inc. 1997 1996 1995 1994 1993 1992 1991
3 * All Rights Reserved
4 *
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.
10 *
11 * OSF DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
12 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
13 * FOR A PARTICULAR PURPOSE.
14 *
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.
20 */
21/*
22 * MkLinux
23 */
24
25/*
26 * POSIX Pthread Library
27 */
28
29#include "pthread_internals.h"
30#include <sys/time.h> /* For struct timespec and getclock(). */
31#include <stdio.h>
32
33 /*
34 * Destroy a condition variable.
35 */
36int
37pthread_cond_destroy(pthread_cond_t *cond)
38{
39 if (cond->sig == _PTHREAD_COND_SIG)
40 {
41 LOCK(cond->lock);
42 if (cond->busy != (pthread_mutex_t *)NULL)
43 {
44 UNLOCK(cond->lock);
45 return (EBUSY);
46 } else
47 {
48 cond->sig = _PTHREAD_NO_SIG;
49 UNLOCK(cond->lock);
50 return (ESUCCESS);
51 }
52 } else
53 return (EINVAL); /* Not an initialized condition variable structure */
54}
55
56/*
57 * Initialize a condition variable. Note: 'attr' is ignored.
58 */
59int
60pthread_cond_init(pthread_cond_t *cond,
61 const pthread_condattr_t *attr)
62{
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;
68 cond->waiters = 0;
69 cond->sigspending = 0;
70 cond->sem = MACH_PORT_NULL;
71 return (ESUCCESS);
72}
73
74/*
75 * Signal a condition variable, waking up all threads waiting for it.
76 */
77int
78pthread_cond_broadcast(pthread_cond_t *cond)
79{
80 kern_return_t kern_res;
3f7af3d8 81 int res;
e9ce8d39
A
82 if (cond->sig == _PTHREAD_COND_SIG_init) {
83 if ((res = pthread_cond_init(cond, NULL)) != 0) {
84 return (res);
85 }
86 }
87 if (cond->sig != _PTHREAD_COND_SIG) {
88 /* Not a condition variable */
89 return (EINVAL);
90 }
91 LOCK(cond->lock);
3f7af3d8
A
92 if (cond->sem == MACH_PORT_NULL) {
93 /* Avoid kernel call since there are no waiters... */
e9ce8d39
A
94 UNLOCK(cond->lock);
95 return (ESUCCESS);
96 }
3f7af3d8 97 cond->sigspending++;
e9ce8d39
A
98 UNLOCK(cond->lock);
99 PTHREAD_MACH_CALL(semaphore_signal_all(cond->sem), kern_res);
100 LOCK(cond->lock);
3f7af3d8 101 cond->sigspending--;
e9ce8d39
A
102 if (cond->waiters == 0 && cond->sigspending == 0) {
103 restore_sem_to_pool(cond->sem);
104 cond->sem = MACH_PORT_NULL;
105 }
106 UNLOCK(cond->lock);
107 if (kern_res != KERN_SUCCESS) {
108 return (EINVAL);
109 }
110 return (ESUCCESS);
111}
112
113/*
114 * Signal a condition variable, waking a specified thread.
115 */
116int
117pthread_cond_signal_thread_np(pthread_cond_t *cond, pthread_t thread)
118{
119 kern_return_t kern_res;
120 if (cond->sig == _PTHREAD_COND_SIG_init) {
121 int res;
122 if ((res = pthread_cond_init(cond, NULL)) != 0) {
123 return (res);
124 }
125 }
126 if (cond->sig != _PTHREAD_COND_SIG) {
127 return (EINVAL); /* Not a condition variable */
128 }
129 LOCK(cond->lock);
3f7af3d8 130 if (cond->sem == MACH_PORT_NULL) {
e9ce8d39
A
131 /* Avoid kernel call since there are not enough waiters... */
132 UNLOCK(cond->lock);
133 return (ESUCCESS);
134 }
135 cond->sigspending++;
136 UNLOCK(cond->lock);
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;
143 }
144 } else if (thread->sig == _PTHREAD_SIG) {
145 PTHREAD_MACH_CALL(semaphore_signal_thread(cond->sem, thread->kernel_thread), kern_res);
146 } else {
147 kern_res = KERN_FAILURE;
148 }
149 LOCK(cond->lock);
150 cond->sigspending--;
151 if (cond->waiters == 0 && cond->sigspending == 0) {
152 restore_sem_to_pool(cond->sem);
153 cond->sem = MACH_PORT_NULL;
154 }
155 UNLOCK(cond->lock);
156 if (kern_res != KERN_SUCCESS) {
157 return (EINVAL);
158 }
159 return (ESUCCESS);
160}
161
162/*
163 * Signal a condition variable, waking only one thread.
164 */
165int
166pthread_cond_signal(pthread_cond_t *cond)
167{
168 return pthread_cond_signal_thread_np(cond, NULL);
169}
170
171/*
172 * Manage a list of condition variables associated with a mutex
173 */
174
175static void
176_pthread_cond_add(pthread_cond_t *cond, pthread_mutex_t *mutex)
177{
178 pthread_cond_t *c;
179 LOCK(mutex->lock);
180 if ((c = mutex->busy) != (pthread_cond_t *)NULL)
181 {
182 c->prev = cond;
183 }
184 cond->next = c;
185 cond->prev = (pthread_cond_t *)NULL;
186 mutex->busy = cond;
187 UNLOCK(mutex->lock);
188 if (cond->sem == MACH_PORT_NULL) {
189 cond->sem = new_sem_from_pool();
190 }
191}
192
193static void
194_pthread_cond_remove(pthread_cond_t *cond, pthread_mutex_t *mutex)
195{
196 pthread_cond_t *n, *p;
197 LOCK(mutex->lock);
198 if ((n = cond->next) != (pthread_cond_t *)NULL)
199 {
200 n->prev = cond->prev;
201 }
202 if ((p = cond->prev) != (pthread_cond_t *)NULL)
203 {
204 p->next = cond->next;
205 } else
206 { /* This is the first in the list */
207 mutex->busy = n;
208 }
209 UNLOCK(mutex->lock);
210 if (cond->sigspending == 0) {
211 restore_sem_to_pool(cond->sem);
212 cond->sem = MACH_PORT_NULL;
213 }
214}
215
216/*
217 * Suspend waiting for a condition variable.
218 * Note: we have to keep a list of condition variables which are using
219 * this same mutex variable so we can detect invalid 'destroy' sequences.
220 */
221static int
222_pthread_cond_wait(pthread_cond_t *cond,
223 pthread_mutex_t *mutex,
224 const struct timespec *abstime,
225 int isRelative)
226{
227 int res;
228 kern_return_t kern_res;
229 pthread_mutex_t *busy;
230 mach_timespec_t then;
231 if (cond->sig == _PTHREAD_COND_SIG_init) {
232 if ((res = pthread_cond_init(cond, NULL)) != 0) {
233 return (res);
234 }
235 }
236 if (cond->sig != _PTHREAD_COND_SIG) {
237 /* Not a condition variable */
238 return (EINVAL);
239 }
240
241 if (abstime) {
242 if (isRelative == 0) {
243 struct timespec now;
244 struct timeval tv;
245 gettimeofday(&tv, NULL);
246 TIMEVAL_TO_TIMESPEC(&tv, &now);
247
248 /* Compute relative time to sleep */
249 then.tv_nsec = abstime->tv_nsec - now.tv_nsec;
250 then.tv_sec = abstime->tv_sec - now.tv_sec;
251 if (then.tv_nsec < 0) {
252 then.tv_nsec += 1000000000; /* nsec/sec */
253 then.tv_sec--;
254 }
255 if (((int)then.tv_sec < 0) ||
256 ((then.tv_sec == 0) && (then.tv_nsec == 0))) {
257 return ETIMEDOUT;
258 }
259 } else {
260 then.tv_sec = abstime->tv_sec;
261 then.tv_nsec = abstime->tv_nsec;
262 }
263 }
264 LOCK(cond->lock);
265 busy = cond->busy;
266 if ((busy != (pthread_mutex_t *)NULL) && (busy != mutex)) {
267 /* Must always specify the same mutex! */
268 UNLOCK(cond->lock);
269 return (EINVAL);
270 }
271 cond->waiters++;
272 if (cond->waiters == 1) {
273 _pthread_cond_add(cond, mutex);
274 cond->busy = mutex;
275 }
276 UNLOCK(cond->lock);
277 LOCK(mutex->lock);
278 if (mutex->sem == MACH_PORT_NULL) {
279 mutex->sem = new_sem_from_pool();
280 }
281 mutex->cond_lock = 1;
282 UNLOCK(mutex->lock);
283 if (abstime) {
284 kern_res = semaphore_timedwait_signal(cond->sem, mutex->sem, then);
285 } else {
286 PTHREAD_MACH_CALL(semaphore_wait_signal(cond->sem, mutex->sem), kern_res);
287 }
288 LOCK(cond->lock);
289 cond->waiters--;
290 if (cond->waiters == 0) {
291 _pthread_cond_remove(cond, mutex);
292 cond->busy = (pthread_mutex_t *)NULL;
293 }
294 UNLOCK(cond->lock);
295 if ((res = pthread_mutex_lock(mutex)) != ESUCCESS) {
296 return (res);
297 }
3b2a1fe8
A
298 /* KERN_ABORTED can be treated as a spurious wakeup */
299 if ((kern_res == KERN_SUCCESS) || (kern_res == KERN_ABORTED)) {
e9ce8d39
A
300 return (ESUCCESS);
301 } else if (kern_res == KERN_OPERATION_TIMED_OUT) {
302 return (ETIMEDOUT);
303 } else {
304 return (EINVAL);
305 }
306}
307
308int
309pthread_cond_wait(pthread_cond_t *cond,
310 pthread_mutex_t *mutex)
311{
312 return (_pthread_cond_wait(cond, mutex, (struct timespec *)NULL, 0));
313}
314
315int
316pthread_cond_timedwait(pthread_cond_t *cond,
317 pthread_mutex_t *mutex,
318 const struct timespec *abstime)
319{
320 return (_pthread_cond_wait(cond, mutex, abstime, 0));
321}
322
323int
324pthread_cond_timedwait_relative_np(pthread_cond_t *cond,
325 pthread_mutex_t *mutex,
326 const struct timespec *abstime)
327{
328 return (_pthread_cond_wait(cond, mutex, abstime, 1));
329}
330