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