]> git.saurik.com Git - apple/libc.git/blob - pthreads.subproj/pthread_cond.c
Libc-167.tar.gz
[apple/libc.git] / pthreads.subproj / 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(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 */
165 int
166 pthread_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
175 static 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
193 static 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 */
221 static 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 }
298 if (kern_res == KERN_SUCCESS) {
299 return (ESUCCESS);
300 } else if (kern_res == KERN_OPERATION_TIMED_OUT) {
301 return (ETIMEDOUT);
302 } else {
303 return (EINVAL);
304 }
305 }
306
307 int
308 pthread_cond_wait(pthread_cond_t *cond,
309 pthread_mutex_t *mutex)
310 {
311 return (_pthread_cond_wait(cond, mutex, (struct timespec *)NULL, 0));
312 }
313
314 int
315 pthread_cond_timedwait(pthread_cond_t *cond,
316 pthread_mutex_t *mutex,
317 const struct timespec *abstime)
318 {
319 return (_pthread_cond_wait(cond, mutex, abstime, 0));
320 }
321
322 int
323 pthread_cond_timedwait_relative_np(pthread_cond_t *cond,
324 pthread_mutex_t *mutex,
325 const struct timespec *abstime)
326 {
327 return (_pthread_cond_wait(cond, mutex, abstime, 1));
328 }
329