]> git.saurik.com Git - apple/libc.git/blob - pthreads/pthread_cond.c
409f23180c3efe08c01b918329836ab9d177d94a
[apple/libc.git] / pthreads / pthread_cond.c
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 */
36 int
37 pthread_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 */
59 int
60 pthread_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 */
77 int
78 pthread_cond_broadcast(pthread_cond_t *cond)
79 {
80 kern_return_t kern_res;
81 int res;
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);
92 if (cond->sem == MACH_PORT_NULL) {
93 /* Avoid kernel call since there are no waiters... */
94 UNLOCK(cond->lock);
95 return (ESUCCESS);
96 }
97 cond->sigspending++;
98 UNLOCK(cond->lock);
99 PTHREAD_MACH_CALL(semaphore_signal_all(cond->sem), kern_res);
100 LOCK(cond->lock);
101 cond->sigspending--;
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 */
116 int
117 pthread_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);
130 if (cond->sem == MACH_PORT_NULL) {
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(
146 cond->sem, pthread_mach_thread_np(thread)), kern_res);
147 } else {
148 kern_res = KERN_FAILURE;
149 }
150 LOCK(cond->lock);
151 cond->sigspending--;
152 if (cond->waiters == 0 && cond->sigspending == 0) {
153 restore_sem_to_pool(cond->sem);
154 cond->sem = MACH_PORT_NULL;
155 }
156 UNLOCK(cond->lock);
157 if (kern_res != KERN_SUCCESS) {
158 return (EINVAL);
159 }
160 return (ESUCCESS);
161 }
162
163 /*
164 * Signal a condition variable, waking only one thread.
165 */
166 int
167 pthread_cond_signal(pthread_cond_t *cond)
168 {
169 return pthread_cond_signal_thread_np(cond, NULL);
170 }
171
172 /*
173 * Manage a list of condition variables associated with a mutex
174 */
175
176 static void
177 _pthread_cond_add(pthread_cond_t *cond, pthread_mutex_t *mutex)
178 {
179 pthread_cond_t *c;
180 LOCK(mutex->lock);
181 if ((c = mutex->busy) != (pthread_cond_t *)NULL)
182 {
183 c->prev = cond;
184 }
185 cond->next = c;
186 cond->prev = (pthread_cond_t *)NULL;
187 mutex->busy = cond;
188 UNLOCK(mutex->lock);
189 if (cond->sem == MACH_PORT_NULL) {
190 cond->sem = new_sem_from_pool();
191 }
192 }
193
194 static void
195 _pthread_cond_remove(pthread_cond_t *cond, pthread_mutex_t *mutex)
196 {
197 pthread_cond_t *n, *p;
198 LOCK(mutex->lock);
199 if ((n = cond->next) != (pthread_cond_t *)NULL)
200 {
201 n->prev = cond->prev;
202 }
203 if ((p = cond->prev) != (pthread_cond_t *)NULL)
204 {
205 p->next = cond->next;
206 } else
207 { /* This is the first in the list */
208 mutex->busy = n;
209 }
210 UNLOCK(mutex->lock);
211 if (cond->sigspending == 0) {
212 restore_sem_to_pool(cond->sem);
213 cond->sem = MACH_PORT_NULL;
214 }
215 }
216
217 /*
218 * Suspend waiting for a condition variable.
219 * Note: we have to keep a list of condition variables which are using
220 * this same mutex variable so we can detect invalid 'destroy' sequences.
221 */
222 static int
223 _pthread_cond_wait(pthread_cond_t *cond,
224 pthread_mutex_t *mutex,
225 const struct timespec *abstime,
226 int isRelative)
227 {
228 int res;
229 kern_return_t kern_res;
230 pthread_mutex_t *busy;
231 mach_timespec_t then;
232 if (cond->sig == _PTHREAD_COND_SIG_init) {
233 if ((res = pthread_cond_init(cond, NULL)) != 0) {
234 return (res);
235 }
236 }
237 if (cond->sig != _PTHREAD_COND_SIG) {
238 /* Not a condition variable */
239 return (EINVAL);
240 }
241
242 if (abstime) {
243 if (isRelative == 0) {
244 struct timespec now;
245 struct timeval tv;
246 gettimeofday(&tv, NULL);
247 TIMEVAL_TO_TIMESPEC(&tv, &now);
248
249 /* Compute relative time to sleep */
250 then.tv_nsec = abstime->tv_nsec - now.tv_nsec;
251 then.tv_sec = abstime->tv_sec - now.tv_sec;
252 if (then.tv_nsec < 0) {
253 then.tv_nsec += NSEC_PER_SEC;
254 then.tv_sec--;
255 }
256 if (((int)then.tv_sec < 0) ||
257 ((then.tv_sec == 0) && (then.tv_nsec == 0))) {
258 return ETIMEDOUT;
259 }
260 } else {
261 then.tv_sec = abstime->tv_sec;
262 then.tv_nsec = abstime->tv_nsec;
263 }
264 if (then.tv_nsec >= NSEC_PER_SEC) {
265 return EINVAL;
266 }
267 }
268 LOCK(cond->lock);
269 busy = cond->busy;
270 if ((busy != (pthread_mutex_t *)NULL) && (busy != mutex)) {
271 /* Must always specify the same mutex! */
272 UNLOCK(cond->lock);
273 return (EINVAL);
274 }
275 cond->waiters++;
276 if (cond->waiters == 1) {
277 _pthread_cond_add(cond, mutex);
278 cond->busy = mutex;
279 }
280 UNLOCK(cond->lock);
281 LOCK(mutex->lock);
282 if (mutex->sem == MACH_PORT_NULL) {
283 mutex->sem = new_sem_from_pool();
284 }
285 mutex->cond_lock = 1;
286 UNLOCK(mutex->lock);
287 if (abstime) {
288 kern_res = semaphore_timedwait_signal(cond->sem, mutex->sem, then);
289 } else {
290 PTHREAD_MACH_CALL(semaphore_wait_signal(cond->sem, mutex->sem), kern_res);
291 }
292 LOCK(cond->lock);
293 cond->waiters--;
294 if (cond->waiters == 0) {
295 _pthread_cond_remove(cond, mutex);
296 cond->busy = (pthread_mutex_t *)NULL;
297 }
298 UNLOCK(cond->lock);
299 if ((res = pthread_mutex_lock(mutex)) != ESUCCESS) {
300 return (res);
301 }
302 /* KERN_ABORTED can be treated as a spurious wakeup */
303 if ((kern_res == KERN_SUCCESS) || (kern_res == KERN_ABORTED)) {
304 return (ESUCCESS);
305 } else if (kern_res == KERN_OPERATION_TIMED_OUT) {
306 return (ETIMEDOUT);
307 } else {
308 return (EINVAL);
309 }
310 }
311
312 int
313 pthread_cond_wait(pthread_cond_t *cond,
314 pthread_mutex_t *mutex)
315 {
316 return (_pthread_cond_wait(cond, mutex, (struct timespec *)NULL, 0));
317 }
318
319 int
320 pthread_cond_timedwait(pthread_cond_t *cond,
321 pthread_mutex_t *mutex,
322 const struct timespec *abstime)
323 {
324 return (_pthread_cond_wait(cond, mutex, abstime, 0));
325 }
326
327 int
328 pthread_cond_timedwait_relative_np(pthread_cond_t *cond,
329 pthread_mutex_t *mutex,
330 const struct timespec *abstime)
331 {
332 return (_pthread_cond_wait(cond, mutex, abstime, 1));
333 }
334
335 int
336 pthread_condattr_init(pthread_condattr_t *attr)
337 {
338 attr->sig = _PTHREAD_COND_ATTR_SIG;
339 return (ESUCCESS);
340 }
341
342 int
343 pthread_condattr_destroy(pthread_condattr_t *attr)
344 {
345 attr->sig = _PTHREAD_NO_SIG; /* Uninitialized */
346 return (ESUCCESS);
347 }
348
349 int
350 pthread_condattr_getpshared(const pthread_condattr_t *attr,
351 int *pshared)
352 {
353 if (attr->sig == _PTHREAD_COND_ATTR_SIG)
354 {
355 *pshared = (int)PTHREAD_PROCESS_PRIVATE;
356 return (ESUCCESS);
357 } else
358 {
359 return (EINVAL); /* Not an initialized 'attribute' structure */
360 }
361 }
362
363
364 int
365 pthread_condattr_setpshared(pthread_condattr_t * attr, int pshared)
366 {
367 if (attr->sig == _PTHREAD_COND_ATTR_SIG)
368 {
369 if ( pshared == PTHREAD_PROCESS_PRIVATE)
370 {
371 /* attr->pshared = pshared */
372 return (ESUCCESS);
373 } else
374 {
375 return (EINVAL); /* Invalid parameter */
376 }
377 } else
378 {
379 return (EINVAL); /* Not an initialized 'attribute' structure */
380 }
381
382 }
383