pthread_cond.c revision 1.1.2.6 1 /* $NetBSD: pthread_cond.c,v 1.1.2.6 2002/01/28 19:03:09 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
42 #include "pthread.h"
43 #include "pthread_int.h"
44
45 static void pthread_cond_wait__callback(void *);
46
47
48 int
49 pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr)
50 {
51
52 #ifdef ERRORCHECK
53 if ((cond == NULL) ||
54 (attr && (attr->ptca_magic != _PT_CONDATTR_MAGIC)))
55 return EINVAL;
56 #endif
57
58 cond->ptc_magic = _PT_COND_MAGIC;
59 pthread_lockinit(&cond->ptc_lock);
60 PTQ_INIT(&cond->ptc_waiters);
61 cond->ptc_mutex = NULL;
62
63 return 0;
64 }
65
66
67 int
68 pthread_cond_destroy(pthread_cond_t *cond)
69 {
70
71 #ifdef ERRORCHECK
72 if ((cond == NULL) || (cond->ptc_magic != _PT_COND_MAGIC) ||
73 (cond->ptc_mutex != NULL) ||
74 (cond->ptc_lock != __SIMPLELOCK_UNLOCKED))
75 return EINVAL;
76 #endif
77
78 cond->ptc_magic = _PT_COND_DEAD;
79
80 return 0;
81 }
82
83
84 int
85 pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
86 {
87 pthread_t self;
88 #ifdef ERRORCHECK
89 if ((cond == NULL) || (cond->ptc_magic != _PT_COND_MAGIC) ||
90 (mutex == NULL) || (mutex->ptm_magic != _PT_MUTEX_MAGIC))
91 return EINVAL;
92 #endif
93
94 self = pthread__self();
95 pthread_spinlock(self, &cond->ptc_lock);
96 if (cond->ptc_mutex == NULL)
97 cond->ptc_mutex = mutex;
98 else
99 if (cond->ptc_mutex != mutex) {
100 pthread_spinunlock(self, &cond->ptc_lock);
101 return EINVAL;
102 }
103 pthread_spinlock(self, &self->pt_statelock);
104 if (self->pt_cancel) {
105 pthread_spinunlock(self, &self->pt_statelock);
106 pthread_spinunlock(self, &cond->ptc_lock);
107 pthread_exit(PTHREAD_CANCELED);
108 }
109 self->pt_state = PT_STATE_BLOCKED_QUEUE;
110 self->pt_sleepq = &cond->ptc_waiters;
111 self->pt_sleeplock = &cond->ptc_lock;
112 pthread_spinunlock(self, &self->pt_statelock);
113
114 PTQ_INSERT_TAIL(&cond->ptc_waiters, self, pt_sleep);
115 pthread_mutex_unlock(mutex);
116
117 pthread__block(self, &cond->ptc_lock);
118 /* Spinlock is unlocked on return */
119 pthread_mutex_lock(mutex);
120 pthread__testcancel(self);
121
122 return 0;
123 }
124
125
126 struct pthread_cond__waitarg {
127 pthread_t ptw_thread;
128 pthread_cond_t *ptw_cond;
129 };
130
131 int
132 pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
133 const struct timespec *abstime)
134 {
135 pthread_t self;
136 struct pthread_cond__waitarg wait;
137 int retval;
138 void *alarm;
139
140 #ifdef ERRORCHECK
141 if ((cond == NULL) || (cond->ptc_magic != _PT_COND_MAGIC) ||
142 (mutex == NULL) || (mutex->ptm_magic != _PT_MUTEX_MAGIC))
143 return EINVAL;
144 #endif
145
146 self = pthread__self();
147 pthread_spinlock(self, &cond->ptc_lock);
148 if (cond->ptc_mutex == NULL)
149 cond->ptc_mutex = mutex;
150 else
151 if (cond->ptc_mutex != mutex) {
152 pthread_spinunlock(self, &cond->ptc_lock);
153 return EINVAL;
154 }
155
156 wait.ptw_thread = self;
157 wait.ptw_cond = cond;
158 retval = 0;
159
160 pthread_spinlock(self, &self->pt_statelock);
161 if (self->pt_cancel) {
162 pthread_spinunlock(self, &self->pt_statelock);
163 pthread_spinunlock(self, &cond->ptc_lock);
164 pthread_exit(PTHREAD_CANCELED);
165 }
166 alarm = pthread__alarm_add(self, abstime, pthread_cond_wait__callback,
167 &wait);
168 self->pt_state = PT_STATE_BLOCKED_QUEUE;
169 self->pt_sleepq = &cond->ptc_waiters;
170 self->pt_sleeplock = &cond->ptc_lock;
171 pthread_spinunlock(self, &self->pt_statelock);
172
173 PTQ_INSERT_TAIL(&cond->ptc_waiters, self, pt_sleep);
174 pthread_mutex_unlock(mutex);
175
176 pthread__block(self, &cond->ptc_lock);
177 /* Spinlock is unlocked on return */
178 if (pthread__alarm_fired(alarm))
179 retval = ETIMEDOUT;
180 pthread__alarm_del(self, alarm);
181 pthread_mutex_lock(mutex);
182 pthread__testcancel(self);
183
184 return retval;
185 }
186
187 static void
188 pthread_cond_wait__callback(void *arg)
189 {
190 struct pthread_cond__waitarg *a;
191 pthread_t self;
192
193 a = arg;
194 self = pthread__self();
195 pthread_spinlock(self, &a->ptw_cond->ptc_lock);
196 PTQ_REMOVE(&a->ptw_cond->ptc_waiters, a->ptw_thread, pt_sleep);
197 pthread_spinunlock(self, &a->ptw_cond->ptc_lock);
198 pthread__sched(self, a->ptw_thread);
199 }
200
201 int
202 pthread_cond_signal(pthread_cond_t *cond)
203 {
204 pthread_t self, signaled;
205 #ifdef ERRORCHECK
206 if ((cond == NULL) || (cond->ptc_magic != _PT_COND_MAGIC))
207 return EINVAL;
208 #endif
209
210 self = pthread__self();
211
212 pthread_spinlock(self, &cond->ptc_lock);
213 signaled = PTQ_FIRST(&cond->ptc_waiters);
214 if (signaled != NULL)
215 PTQ_REMOVE(&cond->ptc_waiters, signaled, pt_sleep);
216 if (PTQ_EMPTY(&cond->ptc_waiters))
217 cond->ptc_mutex = NULL;
218 pthread_spinunlock(self, &cond->ptc_lock);
219
220 if (signaled != NULL)
221 pthread__sched(self, signaled);
222
223 return 0;
224 }
225
226
227 int
228 pthread_cond_broadcast(pthread_cond_t *cond)
229 {
230 pthread_t self, signaled;
231 struct pthread_queue_t blockedq, nullq = PTQ_HEAD_INITIALIZER;
232 #ifdef ERRORCHECK
233 if ((cond == NULL) || (cond->ptc_magic != _PT_COND_MAGIC))
234 return EINVAL;
235 #endif
236
237 self = pthread__self();
238
239 pthread_spinlock(self, &cond->ptc_lock);
240 blockedq = cond->ptc_waiters;
241 cond->ptc_waiters = nullq;
242 cond->ptc_mutex = NULL;
243 pthread_spinunlock(self, &cond->ptc_lock);
244
245 PTQ_FOREACH(signaled, &blockedq, pt_sleep)
246 pthread__sched(self, signaled);
247
248 return 0;
249
250 }
251
252
253 int
254 pthread_condattr_init(pthread_condattr_t *attr)
255 {
256
257 #ifdef ERRORCHECK
258 if (attr == NULL)
259 return EINVAL;
260 #endif
261
262 attr->ptca_magic = _PT_CONDATTR_MAGIC;
263
264 return 0;
265 }
266
267
268 int
269 pthread_condattr_destroy(pthread_condattr_t *attr)
270 {
271
272 #ifdef ERRORCHECK
273 if ((attr == NULL) ||
274 (attr->ptca_magic != _PT_CONDATTR_MAGIC))
275 return EINVAL;
276 #endif
277
278 attr->ptca_magic = _PT_CONDATTR_DEAD;
279
280 return 0;
281 }
282