]> git.saurik.com Git - apple/libc.git/blame - pthreads/pthread_cond.c
Libc-339.tar.gz
[apple/libc.git] / pthreads / pthread_cond.c
CommitLineData
9385eb3d
A
1/*
2 * Copyright (c) 2000-2003 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
59e0d9fe
A
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
7 *
9385eb3d
A
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
13 * file.
14 *
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.
22 *
23 * @APPLE_LICENSE_HEADER_END@
24 */
e9ce8d39
A
25/*
26 * Copyright 1996 1995 by Open Software Foundation, Inc. 1997 1996 1995 1994 1993 1992 1991
27 * All Rights Reserved
28 *
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.
34 *
35 * OSF DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
36 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
37 * FOR A PARTICULAR PURPOSE.
38 *
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.
44 */
45/*
46 * MkLinux
47 */
48
49/*
50 * POSIX Pthread Library
51 */
52
53#include "pthread_internals.h"
54#include <sys/time.h> /* For struct timespec and getclock(). */
55#include <stdio.h>
56
9385eb3d
A
57extern void _pthread_mutex_remove(pthread_mutex_t *, pthread_t);
58
59/*
e9ce8d39
A
60 * Destroy a condition variable.
61 */
62int
63pthread_cond_destroy(pthread_cond_t *cond)
64{
9385eb3d
A
65 int ret;
66 int sig = cond->sig;
67
68 /* to provide backwards compat for apps using united condtn vars */
69 if((sig != _PTHREAD_COND_SIG) && (sig !=_PTHREAD_COND_SIG_init))
70 return(EINVAL);
71
72 LOCK(cond->lock);
e9ce8d39
A
73 if (cond->sig == _PTHREAD_COND_SIG)
74 {
9385eb3d 75 if (cond->busy == (pthread_mutex_t *)NULL)
e9ce8d39
A
76 {
77 cond->sig = _PTHREAD_NO_SIG;
9385eb3d
A
78 ret = ESUCCESS;
79 } else
80 ret = EBUSY;
e9ce8d39 81 } else
9385eb3d
A
82 ret = EINVAL; /* Not an initialized condition variable structure */
83 UNLOCK(cond->lock);
84 return (ret);
e9ce8d39
A
85}
86
87/*
88 * Initialize a condition variable. Note: 'attr' is ignored.
89 */
9385eb3d
A
90static int
91_pthread_cond_init(pthread_cond_t *cond,
e9ce8d39
A
92 const pthread_condattr_t *attr)
93{
e9ce8d39
A
94 cond->next = (pthread_cond_t *)NULL;
95 cond->prev = (pthread_cond_t *)NULL;
96 cond->busy = (pthread_mutex_t *)NULL;
97 cond->waiters = 0;
98 cond->sigspending = 0;
9385eb3d
A
99 cond->sem = SEMAPHORE_NULL;
100 cond->sig = _PTHREAD_COND_SIG;
101 return (ESUCCESS);
102}
103
104/*
105 * Initialize a condition variable. This is the public interface.
106 * We can't trust the lock, so initialize it first before taking
107 * it.
108 */
109int
110pthread_cond_init(pthread_cond_t *cond,
111 const pthread_condattr_t *attr)
112{
113 LOCK_INIT(cond->lock);
114 return (_pthread_cond_init(cond, attr));
e9ce8d39
A
115}
116
117/*
118 * Signal a condition variable, waking up all threads waiting for it.
119 */
120int
121pthread_cond_broadcast(pthread_cond_t *cond)
122{
9385eb3d
A
123 kern_return_t kern_res;
124 semaphore_t sem;
125 int sig = cond->sig;
126
127 /* to provide backwards compat for apps using united condtn vars */
128 if((sig != _PTHREAD_COND_SIG) && (sig !=_PTHREAD_COND_SIG_init))
129 return(EINVAL);
130
131 LOCK(cond->lock);
132 if (cond->sig != _PTHREAD_COND_SIG)
133 {
134 int res;
135
136 if (cond->sig == _PTHREAD_COND_SIG_init)
137 {
138 _pthread_cond_init(cond, NULL);
139 res = ESUCCESS;
140 } else
141 res = EINVAL; /* Not a condition variable */
142 UNLOCK(cond->lock);
143 return (res);
144 }
145 else if ((sem = cond->sem) == SEMAPHORE_NULL)
146 {
147 /* Avoid kernel call since there are no waiters... */
148 UNLOCK(cond->lock);
149 return (ESUCCESS);
150 }
151 cond->sigspending++;
152 UNLOCK(cond->lock);
153
154 PTHREAD_MACH_CALL(semaphore_signal_all(sem), kern_res);
155
156 LOCK(cond->lock);
157 cond->sigspending--;
158 if (cond->waiters == 0 && cond->sigspending == 0)
159 {
160 cond->sem = SEMAPHORE_NULL;
161 restore_sem_to_pool(sem);
162 }
163 UNLOCK(cond->lock);
164 if (kern_res != KERN_SUCCESS)
165 return (EINVAL);
166 return (ESUCCESS);
e9ce8d39
A
167}
168
169/*
170 * Signal a condition variable, waking a specified thread.
171 */
172int
173pthread_cond_signal_thread_np(pthread_cond_t *cond, pthread_t thread)
174{
9385eb3d
A
175 kern_return_t kern_res;
176 semaphore_t sem;
177 int sig = cond->sig;
178
179 /* to provide backwards compat for apps using united condtn vars */
180 if((sig != _PTHREAD_COND_SIG) && (sig !=_PTHREAD_COND_SIG_init))
181 return(EINVAL);
182
183 LOCK(cond->lock);
184 if (cond->sig != _PTHREAD_COND_SIG)
185 {
186 int ret;
187
188 if (cond->sig == _PTHREAD_COND_SIG_init)
189 {
190 _pthread_cond_init(cond, NULL);
191 ret = ESUCCESS;
192 }
193 else
194 ret = EINVAL; /* Not a condition variable */
195 UNLOCK(cond->lock);
196 return (ret);
197 }
198 else if ((sem = cond->sem) == SEMAPHORE_NULL)
199 {
200 /* Avoid kernel call since there are not enough waiters... */
201 UNLOCK(cond->lock);
202 return (ESUCCESS);
e9ce8d39 203 }
9385eb3d
A
204 cond->sigspending++;
205 UNLOCK(cond->lock);
206
207 if (thread == (pthread_t)NULL)
208 {
209 kern_res = semaphore_signal_thread(sem, THREAD_NULL);
210 if (kern_res == KERN_NOT_WAITING)
211 kern_res = KERN_SUCCESS;
212 }
213 else if (thread->sig == _PTHREAD_SIG)
214 {
215 PTHREAD_MACH_CALL(semaphore_signal_thread(
216 sem, pthread_mach_thread_np(thread)), kern_res);
217 }
218 else
219 kern_res = KERN_FAILURE;
220
221 LOCK(cond->lock);
222 cond->sigspending--;
223 if (cond->waiters == 0 && cond->sigspending == 0)
224 {
225 cond->sem = SEMAPHORE_NULL;
226 restore_sem_to_pool(sem);
227 }
228 UNLOCK(cond->lock);
229 if (kern_res != KERN_SUCCESS)
230 return (EINVAL);
231 return (ESUCCESS);
e9ce8d39
A
232}
233
234/*
235 * Signal a condition variable, waking only one thread.
236 */
237int
238pthread_cond_signal(pthread_cond_t *cond)
239{
9385eb3d 240 return pthread_cond_signal_thread_np(cond, NULL);
e9ce8d39
A
241}
242
243/*
244 * Manage a list of condition variables associated with a mutex
245 */
246
247static void
248_pthread_cond_add(pthread_cond_t *cond, pthread_mutex_t *mutex)
249{
250 pthread_cond_t *c;
251 LOCK(mutex->lock);
252 if ((c = mutex->busy) != (pthread_cond_t *)NULL)
253 {
254 c->prev = cond;
255 }
256 cond->next = c;
257 cond->prev = (pthread_cond_t *)NULL;
258 mutex->busy = cond;
259 UNLOCK(mutex->lock);
9385eb3d 260 if (cond->sem == SEMAPHORE_NULL)
e9ce8d39 261 cond->sem = new_sem_from_pool();
e9ce8d39
A
262}
263
264static void
265_pthread_cond_remove(pthread_cond_t *cond, pthread_mutex_t *mutex)
266{
267 pthread_cond_t *n, *p;
9385eb3d 268
e9ce8d39
A
269 LOCK(mutex->lock);
270 if ((n = cond->next) != (pthread_cond_t *)NULL)
271 {
272 n->prev = cond->prev;
273 }
274 if ((p = cond->prev) != (pthread_cond_t *)NULL)
275 {
276 p->next = cond->next;
9385eb3d
A
277 }
278 else
e9ce8d39
A
279 { /* This is the first in the list */
280 mutex->busy = n;
281 }
282 UNLOCK(mutex->lock);
9385eb3d
A
283 if (cond->sigspending == 0)
284 {
285 restore_sem_to_pool(cond->sem);
286 cond->sem = SEMAPHORE_NULL;
e9ce8d39
A
287 }
288}
289
290/*
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.
294 */
295static int
296_pthread_cond_wait(pthread_cond_t *cond,
297 pthread_mutex_t *mutex,
298 const struct timespec *abstime,
299 int isRelative)
300{
9385eb3d
A
301 int res;
302 kern_return_t kern_res;
303 pthread_mutex_t *busy;
304 mach_timespec_t then;
305 int sig = cond->sig;
306
307 /* to provide backwards compat for apps using united condtn vars */
308 if((sig != _PTHREAD_COND_SIG) && (sig !=_PTHREAD_COND_SIG_init))
309 return(EINVAL);
310 LOCK(cond->lock);
311 if (cond->sig != _PTHREAD_COND_SIG)
312 {
313 if (cond->sig != _PTHREAD_COND_SIG_init)
314 {
315 UNLOCK(cond->lock);
316 return (EINVAL); /* Not a condition variable */
317 }
318 _pthread_cond_init(cond, NULL);
319 }
320
321 if (abstime)
322 {
323 if (isRelative == 0)
324 {
325 struct timespec now;
326 struct timeval tv;
327 gettimeofday(&tv, NULL);
328 TIMEVAL_TO_TIMESPEC(&tv, &now);
329
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)
334 {
335 then.tv_nsec += NSEC_PER_SEC;
336 then.tv_sec--;
337 }
338 if (((int)then.tv_sec < 0) ||
339 ((then.tv_sec == 0) && (then.tv_nsec == 0)))
340 {
341 UNLOCK(cond->lock);
342 return ETIMEDOUT;
343 }
344 }
345 else
346 {
347 then.tv_sec = abstime->tv_sec;
348 then.tv_nsec = abstime->tv_nsec;
349 }
350 if (then.tv_nsec >= NSEC_PER_SEC)
351 {
352 UNLOCK(cond->lock);
353 return EINVAL;
354 }
355 }
356
357 if (++cond->waiters == 1)
358 {
359 _pthread_cond_add(cond, mutex);
360 cond->busy = mutex;
361 }
362 else if ((busy = cond->busy) != mutex)
363 {
364 /* Must always specify the same mutex! */
365 cond->waiters--;
366 UNLOCK(cond->lock);
367 return (EINVAL);
368 }
369 UNLOCK(cond->lock);
370
371#if defined(DEBUG)
372 _pthread_mutex_remove(mutex, pthread_self());
373#endif
374 LOCK(mutex->lock);
375 if (--mutex->lock_count == 0)
376 {
377 if (mutex->sem == SEMAPHORE_NULL)
378 mutex->sem = new_sem_from_pool();
379 mutex->owner = _PTHREAD_MUTEX_OWNER_SWITCHING;
380 UNLOCK(mutex->lock);
381
382 if (abstime) {
383 kern_res = semaphore_timedwait_signal(cond->sem, mutex->sem, then);
384 } else {
385 PTHREAD_MACH_CALL(semaphore_wait_signal(cond->sem, mutex->sem), kern_res);
386 }
387 }
388 else
389 {
390 UNLOCK(mutex->lock);
391 if (abstime) {
392 kern_res = semaphore_timedwait(cond->sem, then);
393 } else {
394 PTHREAD_MACH_CALL(semaphore_wait(cond->sem), kern_res);
395 }
396 }
397
398 LOCK(cond->lock);
399 cond->waiters--;
400 if (cond->waiters == 0)
401 {
402 _pthread_cond_remove(cond, mutex);
403 cond->busy = (pthread_mutex_t *)NULL;
404 }
405 UNLOCK(cond->lock);
406 if ((res = pthread_mutex_lock(mutex)) != ESUCCESS)
407 return (res);
408
409 /* KERN_ABORTED can be treated as a spurious wakeup */
410 if ((kern_res == KERN_SUCCESS) || (kern_res == KERN_ABORTED))
411 return (ESUCCESS);
412 else if (kern_res == KERN_OPERATION_TIMED_OUT)
413 return (ETIMEDOUT);
414 return (EINVAL);
e9ce8d39
A
415}
416
417int
418pthread_cond_wait(pthread_cond_t *cond,
419 pthread_mutex_t *mutex)
420{
421 return (_pthread_cond_wait(cond, mutex, (struct timespec *)NULL, 0));
422}
423
424int
425pthread_cond_timedwait(pthread_cond_t *cond,
426 pthread_mutex_t *mutex,
427 const struct timespec *abstime)
428{
429 return (_pthread_cond_wait(cond, mutex, abstime, 0));
430}
431
432int
433pthread_cond_timedwait_relative_np(pthread_cond_t *cond,
434 pthread_mutex_t *mutex,
435 const struct timespec *abstime)
436{
437 return (_pthread_cond_wait(cond, mutex, abstime, 1));
438}
439
5b2abdfb
A
440int
441pthread_condattr_init(pthread_condattr_t *attr)
442{
443 attr->sig = _PTHREAD_COND_ATTR_SIG;
444 return (ESUCCESS);
445}
446
447int
448pthread_condattr_destroy(pthread_condattr_t *attr)
449{
450 attr->sig = _PTHREAD_NO_SIG; /* Uninitialized */
451 return (ESUCCESS);
452}
453
454int
455pthread_condattr_getpshared(const pthread_condattr_t *attr,
456 int *pshared)
457{
458 if (attr->sig == _PTHREAD_COND_ATTR_SIG)
459 {
460 *pshared = (int)PTHREAD_PROCESS_PRIVATE;
461 return (ESUCCESS);
462 } else
463 {
464 return (EINVAL); /* Not an initialized 'attribute' structure */
465 }
466}
467
468
469int
470pthread_condattr_setpshared(pthread_condattr_t * attr, int pshared)
471{
472 if (attr->sig == _PTHREAD_COND_ATTR_SIG)
473 {
474 if ( pshared == PTHREAD_PROCESS_PRIVATE)
475 {
476 /* attr->pshared = pshared */
477 return (ESUCCESS);
478 } else
479 {
480 return (EINVAL); /* Invalid parameter */
481 }
482 } else
483 {
484 return (EINVAL); /* Not an initialized 'attribute' structure */
485 }
486
487}
488