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