pthread_cond.c revision 1.1.2.13 1 /* $NetBSD: pthread_cond.c,v 1.1.2.13 2002/10/07 19:37:22 nathanw Exp $ */
2
3 /*-
4 * Copyright (c) 2001 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Nathan J. Williams.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the NetBSD
21 * Foundation, Inc. and its contributors.
22 * 4. Neither the name of The NetBSD Foundation nor the names of its
23 * contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
37 */
38
39 #include <assert.h>
40 #include <errno.h>
41 #include <sys/cdefs.h>
42
43 #include "pthread.h"
44 #include "pthread_int.h"
45
46 #undef PTHREAD_COND_DEBUG
47
48 #ifdef PTHREAD_COND_DEBUG
49 #define SDPRINTF(x) DPRINTF(x)
50 #else
51 #define SDPRINTF(x)
52 #endif
53
54 static void pthread_cond_wait__callback(void *);
55
56 int
57 pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr)
58 {
59
60 #ifdef ERRORCHECK
61 if ((cond == NULL) ||
62 (attr && (attr->ptca_magic != _PT_CONDATTR_MAGIC)))
63 return EINVAL;
64 #endif
65
66 cond->ptc_magic = _PT_COND_MAGIC;
67 pthread_lockinit(&cond->ptc_lock);
68 PTQ_INIT(&cond->ptc_waiters);
69 cond->ptc_mutex = NULL;
70
71 return 0;
72 }
73
74
75 int
76 pthread_cond_destroy(pthread_cond_t *cond)
77 {
78
79 #ifdef ERRORCHECK
80 if ((cond == NULL) || (cond->ptc_magic != _PT_COND_MAGIC) ||
81 (cond->ptc_mutex != NULL) ||
82 (cond->ptc_lock != __SIMPLELOCK_UNLOCKED))
83 return EINVAL;
84 #endif
85
86 cond->ptc_magic = _PT_COND_DEAD;
87
88 return 0;
89 }
90
91
92 int
93 pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
94 {
95 pthread_t self;
96 #ifdef ERRORCHECK
97 if ((cond == NULL) || (cond->ptc_magic != _PT_COND_MAGIC) ||
98 (mutex == NULL) || (mutex->ptm_magic != _PT_MUTEX_MAGIC))
99 return EINVAL;
100 #endif
101
102 self = pthread__self();
103 pthread_spinlock(self, &cond->ptc_lock);
104 #ifdef ERRORCHECK
105 if (cond->ptc_mutex == NULL)
106 cond->ptc_mutex = mutex;
107 else
108 if (cond->ptc_mutex != mutex) {
109 pthread_spinunlock(self, &cond->ptc_lock);
110 return EINVAL;
111 }
112 #endif
113 SDPRINTF(("(cond wait %p) Waiting on %p, mutex %p\n",
114 self, cond, mutex));
115 pthread_spinlock(self, &self->pt_statelock);
116 if (self->pt_cancel) {
117 pthread_spinunlock(self, &self->pt_statelock);
118 pthread_spinunlock(self, &cond->ptc_lock);
119 pthread_exit(PTHREAD_CANCELED);
120 }
121 self->pt_state = PT_STATE_BLOCKED_QUEUE;
122 self->pt_sleepobj = cond;
123 self->pt_sleepq = &cond->ptc_waiters;
124 self->pt_sleeplock = &cond->ptc_lock;
125 pthread_spinunlock(self, &self->pt_statelock);
126
127 PTQ_INSERT_TAIL(&cond->ptc_waiters, self, pt_sleep);
128 pthread_mutex_unlock(mutex);
129
130 pthread__block(self, &cond->ptc_lock);
131 /* Spinlock is unlocked on return */
132 pthread_mutex_lock(mutex);
133 pthread__testcancel(self);
134 SDPRINTF(("(cond wait %p) Woke up on %p, mutex %p\n",
135 self, cond, mutex));
136
137 return 0;
138 }
139
140
141 struct pthread_cond__waitarg {
142 pthread_t ptw_thread;
143 pthread_cond_t *ptw_cond;
144 };
145
146 int
147 pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
148 const struct timespec *abstime)
149 {
150 pthread_t self;
151 struct pthread_cond__waitarg wait;
152 struct pt_alarm_t alarm;
153 int retval;
154
155 #ifdef ERRORCHECK
156 if ((cond == NULL) || (cond->ptc_magic != _PT_COND_MAGIC) ||
157 (mutex == NULL) || (mutex->ptm_magic != _PT_MUTEX_MAGIC))
158 return EINVAL;
159 #endif
160
161 self = pthread__self();
162 pthread_spinlock(self, &cond->ptc_lock);
163 #ifdef ERRORCHECK
164 if (cond->ptc_mutex == NULL)
165 cond->ptc_mutex = mutex;
166 else
167 if (cond->ptc_mutex != mutex) {
168 pthread_spinunlock(self, &cond->ptc_lock);
169 return EINVAL;
170 }
171 #endif
172 wait.ptw_thread = self;
173 wait.ptw_cond = cond;
174 retval = 0;
175 SDPRINTF(("(cond timed wait %p) Waiting on %p, until %d.%06ld\n",
176 self, cond, mutex, abstime->tv_sec, abstime->tv_nsec/1000));
177
178 pthread_spinlock(self, &self->pt_statelock);
179 if (self->pt_cancel) {
180 pthread_spinunlock(self, &self->pt_statelock);
181 pthread_spinunlock(self, &cond->ptc_lock);
182 pthread_exit(PTHREAD_CANCELED);
183 }
184 pthread__alarm_add(self, &alarm, abstime, pthread_cond_wait__callback,
185 &wait);
186 self->pt_state = PT_STATE_BLOCKED_QUEUE;
187 self->pt_sleepobj = cond;
188 self->pt_sleepq = &cond->ptc_waiters;
189 self->pt_sleeplock = &cond->ptc_lock;
190 pthread_spinunlock(self, &self->pt_statelock);
191
192 PTQ_INSERT_TAIL(&cond->ptc_waiters, self, pt_sleep);
193 pthread_mutex_unlock(mutex);
194
195 pthread__block(self, &cond->ptc_lock);
196 /* Spinlock is unlocked on return */
197 if (pthread__alarm_fired(&alarm))
198 retval = ETIMEDOUT;
199 pthread__alarm_del(self, &alarm);
200 pthread_mutex_lock(mutex);
201 pthread__testcancel(self);
202
203 SDPRINTF(("(cond timed wait %p) Woke up on %p, mutex %p %s\n",
204 self, cond, mutex, (retval == ETIMEDOUT) ? "(timed out)" : ""));
205
206 return retval;
207 }
208
209 static void
210 pthread_cond_wait__callback(void *arg)
211 {
212 struct pthread_cond__waitarg *a;
213 pthread_t self;
214
215 a = arg;
216 self = pthread__self();
217
218 pthread_spinlock(self, &a->ptw_cond->ptc_lock);
219 PTQ_REMOVE(&a->ptw_cond->ptc_waiters, a->ptw_thread, pt_sleep);
220 #ifdef ERRORCHECK
221 if (PTQ_EMPTY(&a->ptw_cond->ptc_waiters))
222 a->ptw_cond->ptc_mutex = NULL;
223 #endif
224 pthread_spinunlock(self, &a->ptw_cond->ptc_lock);
225 pthread__sched(self, a->ptw_thread);
226 }
227
228 int
229 pthread_cond_signal(pthread_cond_t *cond)
230 {
231 pthread_t self, signaled;
232 #ifdef ERRORCHECK
233 if ((cond == NULL) || (cond->ptc_magic != _PT_COND_MAGIC))
234 return EINVAL;
235 #endif
236
237 self = pthread__self();
238 SDPRINTF(("(cond signal %p) Signaling %p\n",
239 self, cond));
240
241 pthread_spinlock(self, &cond->ptc_lock);
242 signaled = PTQ_FIRST(&cond->ptc_waiters);
243 if (signaled != NULL)
244 PTQ_REMOVE(&cond->ptc_waiters, signaled, pt_sleep);
245 #ifdef ERRORCHECK
246 if (PTQ_EMPTY(&cond->ptc_waiters))
247 cond->ptc_mutex = NULL;
248 #endif
249 pthread_spinunlock(self, &cond->ptc_lock);
250
251 if (signaled != NULL)
252 pthread__sched(self, signaled);
253
254 return 0;
255 }
256
257
258 int
259 pthread_cond_broadcast(pthread_cond_t *cond)
260 {
261 pthread_t self, signaled;
262 struct pthread_queue_t blockedq, nullq = PTQ_HEAD_INITIALIZER;
263 #ifdef ERRORCHECK
264 if ((cond == NULL) || (cond->ptc_magic != _PT_COND_MAGIC))
265 return EINVAL;
266 #endif
267
268 self = pthread__self();
269 SDPRINTF(("(cond signal %p) Broadcasting %p\n",
270 self, cond));
271
272 pthread_spinlock(self, &cond->ptc_lock);
273 blockedq = cond->ptc_waiters;
274 cond->ptc_waiters = nullq;
275 #ifdef ERRORCHECK
276 cond->ptc_mutex = NULL;
277 #endif
278 pthread_spinunlock(self, &cond->ptc_lock);
279
280 PTQ_FOREACH(signaled, &blockedq, pt_sleep)
281 pthread__sched(self, signaled);
282
283 return 0;
284
285 }
286
287
288 int
289 pthread_condattr_init(pthread_condattr_t *attr)
290 {
291
292 #ifdef ERRORCHECK
293 if (attr == NULL)
294 return EINVAL;
295 #endif
296
297 attr->ptca_magic = _PT_CONDATTR_MAGIC;
298
299 return 0;
300 }
301
302
303 int
304 pthread_condattr_destroy(pthread_condattr_t *attr)
305 {
306
307 #ifdef ERRORCHECK
308 if ((attr == NULL) ||
309 (attr->ptca_magic != _PT_CONDATTR_MAGIC))
310 return EINVAL;
311 #endif
312
313 attr->ptca_magic = _PT_CONDATTR_DEAD;
314
315 return 0;
316 }
317