pthread_rwlock.c revision 1.13 1 1.13 chs /* $NetBSD: pthread_rwlock.c,v 1.13 2005/10/19 02:15:03 chs Exp $ */
2 1.2 thorpej
3 1.2 thorpej /*-
4 1.2 thorpej * Copyright (c) 2002 The NetBSD Foundation, Inc.
5 1.2 thorpej * All rights reserved.
6 1.2 thorpej *
7 1.2 thorpej * This code is derived from software contributed to The NetBSD Foundation
8 1.2 thorpej * by Nathan J. Williams.
9 1.2 thorpej *
10 1.2 thorpej * Redistribution and use in source and binary forms, with or without
11 1.2 thorpej * modification, are permitted provided that the following conditions
12 1.2 thorpej * are met:
13 1.2 thorpej * 1. Redistributions of source code must retain the above copyright
14 1.2 thorpej * notice, this list of conditions and the following disclaimer.
15 1.2 thorpej * 2. Redistributions in binary form must reproduce the above copyright
16 1.2 thorpej * notice, this list of conditions and the following disclaimer in the
17 1.2 thorpej * documentation and/or other materials provided with the distribution.
18 1.2 thorpej * 3. All advertising materials mentioning features or use of this software
19 1.2 thorpej * must display the following acknowledgement:
20 1.2 thorpej * This product includes software developed by the NetBSD
21 1.2 thorpej * Foundation, Inc. and its contributors.
22 1.2 thorpej * 4. Neither the name of The NetBSD Foundation nor the names of its
23 1.2 thorpej * contributors may be used to endorse or promote products derived
24 1.2 thorpej * from this software without specific prior written permission.
25 1.2 thorpej *
26 1.2 thorpej * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27 1.2 thorpej * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 1.2 thorpej * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 1.2 thorpej * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30 1.2 thorpej * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 1.2 thorpej * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 1.2 thorpej * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 1.2 thorpej * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 1.2 thorpej * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 1.2 thorpej * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 1.2 thorpej * POSSIBILITY OF SUCH DAMAGE.
37 1.2 thorpej */
38 1.2 thorpej
39 1.5 lukem #include <sys/cdefs.h>
40 1.13 chs __RCSID("$NetBSD: pthread_rwlock.c,v 1.13 2005/10/19 02:15:03 chs Exp $");
41 1.5 lukem
42 1.2 thorpej #include <errno.h>
43 1.2 thorpej
44 1.2 thorpej #include "pthread.h"
45 1.2 thorpej #include "pthread_int.h"
46 1.2 thorpej
47 1.2 thorpej static void pthread_rwlock__callback(void *);
48 1.2 thorpej
49 1.2 thorpej __strong_alias(__libc_rwlock_init,pthread_rwlock_init)
50 1.2 thorpej __strong_alias(__libc_rwlock_rdlock,pthread_rwlock_rdlock)
51 1.2 thorpej __strong_alias(__libc_rwlock_wrlock,pthread_rwlock_wrlock)
52 1.2 thorpej __strong_alias(__libc_rwlock_tryrdlock,pthread_rwlock_tryrdlock)
53 1.2 thorpej __strong_alias(__libc_rwlock_trywrlock,pthread_rwlock_trywrlock)
54 1.2 thorpej __strong_alias(__libc_rwlock_unlock,pthread_rwlock_unlock)
55 1.2 thorpej __strong_alias(__libc_rwlock_destroy,pthread_rwlock_destroy)
56 1.2 thorpej
57 1.2 thorpej int
58 1.2 thorpej pthread_rwlock_init(pthread_rwlock_t *rwlock,
59 1.2 thorpej const pthread_rwlockattr_t *attr)
60 1.2 thorpej {
61 1.2 thorpej #ifdef ERRORCHECK
62 1.2 thorpej if ((rwlock == NULL) ||
63 1.2 thorpej (attr && (attr->ptra_magic != _PT_RWLOCKATTR_MAGIC)))
64 1.2 thorpej return EINVAL;
65 1.2 thorpej #endif
66 1.2 thorpej rwlock->ptr_magic = _PT_RWLOCK_MAGIC;
67 1.2 thorpej pthread_lockinit(&rwlock->ptr_interlock);
68 1.2 thorpej PTQ_INIT(&rwlock->ptr_rblocked);
69 1.2 thorpej PTQ_INIT(&rwlock->ptr_wblocked);
70 1.2 thorpej rwlock->ptr_nreaders = 0;
71 1.2 thorpej rwlock->ptr_writer = NULL;
72 1.2 thorpej
73 1.2 thorpej return 0;
74 1.2 thorpej }
75 1.2 thorpej
76 1.2 thorpej
77 1.2 thorpej int
78 1.2 thorpej pthread_rwlock_destroy(pthread_rwlock_t *rwlock)
79 1.2 thorpej {
80 1.2 thorpej #ifdef ERRORCHECK
81 1.2 thorpej if ((rwlock == NULL) ||
82 1.2 thorpej (rwlock->ptr_magic != _PT_RWLOCK_MAGIC) ||
83 1.2 thorpej (!PTQ_EMPTY(&rwlock->ptr_rblocked)) ||
84 1.2 thorpej (!PTQ_EMPTY(&rwlock->ptr_wblocked)) ||
85 1.2 thorpej (rwlock->ptr_nreaders != 0) ||
86 1.2 thorpej (rwlock->ptr_writer != NULL))
87 1.2 thorpej return EINVAL;
88 1.2 thorpej #endif
89 1.2 thorpej rwlock->ptr_magic = _PT_RWLOCK_DEAD;
90 1.2 thorpej
91 1.2 thorpej return 0;
92 1.2 thorpej }
93 1.2 thorpej
94 1.2 thorpej
95 1.2 thorpej int
96 1.2 thorpej pthread_rwlock_rdlock(pthread_rwlock_t *rwlock)
97 1.2 thorpej {
98 1.2 thorpej pthread_t self;
99 1.2 thorpej #ifdef ERRORCHECK
100 1.2 thorpej if ((rwlock == NULL) || (rwlock->ptr_magic != _PT_RWLOCK_MAGIC))
101 1.2 thorpej return EINVAL;
102 1.2 thorpej #endif
103 1.2 thorpej self = pthread__self();
104 1.2 thorpej
105 1.2 thorpej pthread_spinlock(self, &rwlock->ptr_interlock);
106 1.2 thorpej #ifdef ERRORCHECK
107 1.2 thorpej if (rwlock->ptr_writer == self) {
108 1.2 thorpej pthread_spinunlock(self, &rwlock->ptr_interlock);
109 1.2 thorpej return EDEADLK;
110 1.2 thorpej }
111 1.2 thorpej #endif
112 1.2 thorpej /*
113 1.2 thorpej * Don't get a readlock if there is a writer or if there are waiting
114 1.2 thorpej * writers; i.e. prefer writers to readers. This strategy is dictated
115 1.2 thorpej * by SUSv3.
116 1.2 thorpej */
117 1.2 thorpej while ((rwlock->ptr_writer != NULL) ||
118 1.2 thorpej (!PTQ_EMPTY(&rwlock->ptr_wblocked))) {
119 1.2 thorpej PTQ_INSERT_TAIL(&rwlock->ptr_rblocked, self, pt_sleep);
120 1.2 thorpej /* Locking a rwlock is not a cancellation point; don't check */
121 1.2 thorpej pthread_spinlock(self, &self->pt_statelock);
122 1.2 thorpej self->pt_state = PT_STATE_BLOCKED_QUEUE;
123 1.2 thorpej self->pt_sleepobj = rwlock;
124 1.2 thorpej self->pt_sleepq = &rwlock->ptr_rblocked;
125 1.2 thorpej self->pt_sleeplock = &rwlock->ptr_interlock;
126 1.2 thorpej pthread_spinunlock(self, &self->pt_statelock);
127 1.2 thorpej pthread__block(self, &rwlock->ptr_interlock);
128 1.2 thorpej /* interlock is not held when we return */
129 1.2 thorpej pthread_spinlock(self, &rwlock->ptr_interlock);
130 1.2 thorpej }
131 1.2 thorpej
132 1.2 thorpej rwlock->ptr_nreaders++;
133 1.2 thorpej pthread_spinunlock(self, &rwlock->ptr_interlock);
134 1.2 thorpej
135 1.2 thorpej return 0;
136 1.2 thorpej }
137 1.2 thorpej
138 1.2 thorpej
139 1.2 thorpej int
140 1.2 thorpej pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock)
141 1.2 thorpej {
142 1.2 thorpej pthread_t self;
143 1.2 thorpej #ifdef ERRORCHECK
144 1.2 thorpej if ((rwlock == NULL) || (rwlock->ptr_magic != _PT_RWLOCK_MAGIC))
145 1.2 thorpej return EINVAL;
146 1.2 thorpej #endif
147 1.2 thorpej self = pthread__self();
148 1.2 thorpej
149 1.2 thorpej pthread_spinlock(self, &rwlock->ptr_interlock);
150 1.2 thorpej /*
151 1.2 thorpej * Don't get a readlock if there is a writer or if there are waiting
152 1.2 thorpej * writers; i.e. prefer writers to readers. This strategy is dictated
153 1.2 thorpej * by SUSv3.
154 1.2 thorpej */
155 1.2 thorpej if ((rwlock->ptr_writer != NULL) ||
156 1.2 thorpej (!PTQ_EMPTY(&rwlock->ptr_wblocked))) {
157 1.2 thorpej pthread_spinunlock(self, &rwlock->ptr_interlock);
158 1.2 thorpej return EBUSY;
159 1.2 thorpej }
160 1.2 thorpej
161 1.2 thorpej rwlock->ptr_nreaders++;
162 1.2 thorpej pthread_spinunlock(self, &rwlock->ptr_interlock);
163 1.2 thorpej
164 1.2 thorpej return 0;
165 1.2 thorpej }
166 1.2 thorpej
167 1.2 thorpej
168 1.2 thorpej int
169 1.2 thorpej pthread_rwlock_wrlock(pthread_rwlock_t *rwlock)
170 1.2 thorpej {
171 1.2 thorpej pthread_t self;
172 1.13 chs extern int pthread__started;
173 1.13 chs
174 1.2 thorpej #ifdef ERRORCHECK
175 1.2 thorpej if ((rwlock == NULL) || (rwlock->ptr_magic != _PT_RWLOCK_MAGIC))
176 1.2 thorpej return EINVAL;
177 1.2 thorpej #endif
178 1.2 thorpej self = pthread__self();
179 1.2 thorpej
180 1.2 thorpej pthread_spinlock(self, &rwlock->ptr_interlock);
181 1.7 cl #ifdef ERRORCHECK
182 1.7 cl if (rwlock->ptr_writer == self) {
183 1.7 cl pthread_spinunlock(self, &rwlock->ptr_interlock);
184 1.7 cl return EDEADLK;
185 1.7 cl }
186 1.7 cl #endif
187 1.2 thorpej /*
188 1.2 thorpej * Prefer writers to readers here; permit writers even if there are
189 1.2 thorpej * waiting readers.
190 1.2 thorpej */
191 1.2 thorpej while ((rwlock->ptr_nreaders > 0) || (rwlock->ptr_writer != NULL)) {
192 1.13 chs #ifdef ERRORCHECK
193 1.13 chs if (pthread__started == 0) {
194 1.13 chs pthread_spinunlock(self, &rwlock->ptr_interlock);
195 1.13 chs return EDEADLK;
196 1.13 chs }
197 1.13 chs #endif
198 1.2 thorpej PTQ_INSERT_TAIL(&rwlock->ptr_wblocked, self, pt_sleep);
199 1.2 thorpej /* Locking a rwlock is not a cancellation point; don't check */
200 1.2 thorpej pthread_spinlock(self, &self->pt_statelock);
201 1.2 thorpej self->pt_state = PT_STATE_BLOCKED_QUEUE;
202 1.2 thorpej self->pt_sleepobj = rwlock;
203 1.2 thorpej self->pt_sleepq = &rwlock->ptr_wblocked;
204 1.2 thorpej self->pt_sleeplock = &rwlock->ptr_interlock;
205 1.2 thorpej pthread_spinunlock(self, &self->pt_statelock);
206 1.2 thorpej pthread__block(self, &rwlock->ptr_interlock);
207 1.2 thorpej /* interlock is not held when we return */
208 1.2 thorpej pthread_spinlock(self, &rwlock->ptr_interlock);
209 1.2 thorpej }
210 1.2 thorpej
211 1.2 thorpej rwlock->ptr_writer = self;
212 1.2 thorpej pthread_spinunlock(self, &rwlock->ptr_interlock);
213 1.2 thorpej
214 1.2 thorpej return 0;
215 1.2 thorpej }
216 1.2 thorpej
217 1.2 thorpej
218 1.2 thorpej int
219 1.2 thorpej pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock)
220 1.2 thorpej {
221 1.2 thorpej pthread_t self;
222 1.2 thorpej #ifdef ERRORCHECK
223 1.2 thorpej if ((rwlock == NULL) || (rwlock->ptr_magic != _PT_RWLOCK_MAGIC))
224 1.2 thorpej return EINVAL;
225 1.2 thorpej #endif
226 1.2 thorpej self = pthread__self();
227 1.2 thorpej
228 1.2 thorpej pthread_spinlock(self, &rwlock->ptr_interlock);
229 1.2 thorpej /*
230 1.2 thorpej * Prefer writers to readers here; permit writers even if there are
231 1.2 thorpej * waiting readers.
232 1.2 thorpej */
233 1.2 thorpej if ((rwlock->ptr_nreaders > 0) || (rwlock->ptr_writer != NULL)) {
234 1.2 thorpej pthread_spinunlock(self, &rwlock->ptr_interlock);
235 1.2 thorpej return EBUSY;
236 1.2 thorpej }
237 1.2 thorpej
238 1.2 thorpej rwlock->ptr_writer = self;
239 1.2 thorpej pthread_spinunlock(self, &rwlock->ptr_interlock);
240 1.2 thorpej
241 1.2 thorpej return 0;
242 1.2 thorpej }
243 1.2 thorpej
244 1.2 thorpej
245 1.2 thorpej struct pthread_rwlock__waitarg {
246 1.2 thorpej pthread_t ptw_thread;
247 1.2 thorpej pthread_rwlock_t *ptw_rwlock;
248 1.2 thorpej struct pthread_queue_t *ptw_queue;
249 1.2 thorpej };
250 1.2 thorpej
251 1.2 thorpej int
252 1.2 thorpej pthread_rwlock_timedrdlock(pthread_rwlock_t *rwlock,
253 1.2 thorpej const struct timespec *abs_timeout)
254 1.2 thorpej {
255 1.2 thorpej pthread_t self;
256 1.2 thorpej struct pthread_rwlock__waitarg wait;
257 1.2 thorpej struct pt_alarm_t alarm;
258 1.2 thorpej int retval;
259 1.12 chs
260 1.2 thorpej #ifdef ERRORCHECK
261 1.2 thorpej if ((rwlock == NULL) || (rwlock->ptr_magic != _PT_RWLOCK_MAGIC))
262 1.2 thorpej return EINVAL;
263 1.10 nathanw if (abs_timeout == NULL)
264 1.2 thorpej return EINVAL;
265 1.2 thorpej #endif
266 1.10 nathanw if ((abs_timeout->tv_nsec >= 1000000000) ||
267 1.10 nathanw (abs_timeout->tv_nsec < 0) ||
268 1.10 nathanw (abs_timeout->tv_sec < 0))
269 1.10 nathanw return EINVAL;
270 1.12 chs
271 1.2 thorpej self = pthread__self();
272 1.2 thorpej pthread_spinlock(self, &rwlock->ptr_interlock);
273 1.2 thorpej #ifdef ERRORCHECK
274 1.2 thorpej if (rwlock->ptr_writer == self) {
275 1.9 yamt pthread_spinunlock(self, &rwlock->ptr_interlock);
276 1.2 thorpej return EDEADLK;
277 1.2 thorpej }
278 1.2 thorpej #endif
279 1.2 thorpej /*
280 1.2 thorpej * Don't get a readlock if there is a writer or if there are waiting
281 1.2 thorpej * writers; i.e. prefer writers to readers. This strategy is dictated
282 1.2 thorpej * by SUSv3.
283 1.2 thorpej */
284 1.2 thorpej retval = 0;
285 1.2 thorpej while ((retval == 0) && ((rwlock->ptr_writer != NULL) ||
286 1.2 thorpej (!PTQ_EMPTY(&rwlock->ptr_wblocked)))) {
287 1.2 thorpej wait.ptw_thread = self;
288 1.2 thorpej wait.ptw_rwlock = rwlock;
289 1.2 thorpej wait.ptw_queue = &rwlock->ptr_rblocked;
290 1.2 thorpej pthread__alarm_add(self, &alarm, abs_timeout,
291 1.2 thorpej pthread_rwlock__callback, &wait);
292 1.2 thorpej PTQ_INSERT_TAIL(&rwlock->ptr_rblocked, self, pt_sleep);
293 1.2 thorpej /* Locking a rwlock is not a cancellation point; don't check */
294 1.2 thorpej pthread_spinlock(self, &self->pt_statelock);
295 1.2 thorpej self->pt_state = PT_STATE_BLOCKED_QUEUE;
296 1.2 thorpej self->pt_sleepobj = rwlock;
297 1.2 thorpej self->pt_sleepq = &rwlock->ptr_rblocked;
298 1.2 thorpej self->pt_sleeplock = &rwlock->ptr_interlock;
299 1.2 thorpej pthread_spinunlock(self, &self->pt_statelock);
300 1.2 thorpej pthread__block(self, &rwlock->ptr_interlock);
301 1.2 thorpej /* interlock is not held when we return */
302 1.2 thorpej pthread__alarm_del(self, &alarm);
303 1.2 thorpej if (pthread__alarm_fired(&alarm))
304 1.2 thorpej retval = ETIMEDOUT;
305 1.2 thorpej pthread_spinlock(self, &rwlock->ptr_interlock);
306 1.2 thorpej }
307 1.2 thorpej
308 1.11 nathanw /* One last chance to get the lock, in case it was released between
309 1.11 nathanw the alarm firing and when this thread got rescheduled, or in case
310 1.11 nathanw a signal handler kept it busy */
311 1.11 nathanw if ((rwlock->ptr_writer == NULL) &&
312 1.11 nathanw (PTQ_EMPTY(&rwlock->ptr_wblocked))) {
313 1.2 thorpej rwlock->ptr_nreaders++;
314 1.11 nathanw retval = 0;
315 1.11 nathanw }
316 1.2 thorpej pthread_spinunlock(self, &rwlock->ptr_interlock);
317 1.2 thorpej
318 1.2 thorpej return retval;
319 1.2 thorpej }
320 1.2 thorpej
321 1.2 thorpej
322 1.2 thorpej int
323 1.2 thorpej pthread_rwlock_timedwrlock(pthread_rwlock_t *rwlock,
324 1.2 thorpej const struct timespec *abs_timeout)
325 1.2 thorpej {
326 1.2 thorpej struct pthread_rwlock__waitarg wait;
327 1.2 thorpej struct pt_alarm_t alarm;
328 1.12 chs pthread_t self;
329 1.2 thorpej int retval;
330 1.12 chs extern int pthread__started;
331 1.12 chs
332 1.2 thorpej #ifdef ERRORCHECK
333 1.2 thorpej if ((rwlock == NULL) || (rwlock->ptr_magic != _PT_RWLOCK_MAGIC))
334 1.2 thorpej return EINVAL;
335 1.10 nathanw if (abs_timeout == NULL)
336 1.10 nathanw return EINVAL;
337 1.2 thorpej #endif
338 1.10 nathanw if ((abs_timeout->tv_nsec >= 1000000000) ||
339 1.10 nathanw (abs_timeout->tv_nsec < 0) ||
340 1.10 nathanw (abs_timeout->tv_sec < 0))
341 1.10 nathanw return EINVAL;
342 1.12 chs
343 1.2 thorpej self = pthread__self();
344 1.2 thorpej pthread_spinlock(self, &rwlock->ptr_interlock);
345 1.7 cl #ifdef ERRORCHECK
346 1.7 cl if (rwlock->ptr_writer == self) {
347 1.9 yamt pthread_spinunlock(self, &rwlock->ptr_interlock);
348 1.7 cl return EDEADLK;
349 1.7 cl }
350 1.7 cl #endif
351 1.2 thorpej /*
352 1.2 thorpej * Prefer writers to readers here; permit writers even if there are
353 1.2 thorpej * waiting readers.
354 1.2 thorpej */
355 1.2 thorpej retval = 0;
356 1.2 thorpej while (retval == 0 &&
357 1.2 thorpej ((rwlock->ptr_nreaders > 0) || (rwlock->ptr_writer != NULL))) {
358 1.13 chs #ifdef ERRORCHECK
359 1.13 chs if (pthread__started == 0) {
360 1.13 chs pthread_spinunlock(self, &rwlock->ptr_interlock);
361 1.13 chs return EDEADLK;
362 1.13 chs }
363 1.13 chs #endif
364 1.2 thorpej wait.ptw_thread = self;
365 1.2 thorpej wait.ptw_rwlock = rwlock;
366 1.2 thorpej wait.ptw_queue = &rwlock->ptr_wblocked;
367 1.2 thorpej pthread__alarm_add(self, &alarm, abs_timeout,
368 1.2 thorpej pthread_rwlock__callback, &wait);
369 1.2 thorpej PTQ_INSERT_TAIL(&rwlock->ptr_wblocked, self, pt_sleep);
370 1.2 thorpej /* Locking a rwlock is not a cancellation point; don't check */
371 1.2 thorpej pthread_spinlock(self, &self->pt_statelock);
372 1.2 thorpej self->pt_state = PT_STATE_BLOCKED_QUEUE;
373 1.2 thorpej self->pt_sleepobj = rwlock;
374 1.2 thorpej self->pt_sleepq = &rwlock->ptr_wblocked;
375 1.2 thorpej self->pt_sleeplock = &rwlock->ptr_interlock;
376 1.2 thorpej pthread_spinunlock(self, &self->pt_statelock);
377 1.2 thorpej pthread__block(self, &rwlock->ptr_interlock);
378 1.2 thorpej /* interlock is not held when we return */
379 1.2 thorpej pthread__alarm_del(self, &alarm);
380 1.2 thorpej if (pthread__alarm_fired(&alarm))
381 1.2 thorpej retval = ETIMEDOUT;
382 1.2 thorpej pthread_spinlock(self, &rwlock->ptr_interlock);
383 1.2 thorpej }
384 1.2 thorpej
385 1.11 nathanw if ((rwlock->ptr_nreaders == 0) && (rwlock->ptr_writer == NULL)) {
386 1.2 thorpej rwlock->ptr_writer = self;
387 1.11 nathanw retval = 0;
388 1.11 nathanw }
389 1.2 thorpej pthread_spinunlock(self, &rwlock->ptr_interlock);
390 1.2 thorpej
391 1.8 yamt return retval;
392 1.2 thorpej }
393 1.2 thorpej
394 1.2 thorpej
395 1.2 thorpej static void
396 1.2 thorpej pthread_rwlock__callback(void *arg)
397 1.2 thorpej {
398 1.2 thorpej struct pthread_rwlock__waitarg *a;
399 1.2 thorpej pthread_t self;
400 1.2 thorpej
401 1.2 thorpej a = arg;
402 1.2 thorpej self = pthread__self();
403 1.2 thorpej
404 1.2 thorpej pthread_spinlock(self, &a->ptw_rwlock->ptr_interlock);
405 1.2 thorpej /*
406 1.2 thorpej * Don't dequeue and schedule the thread if it's already been
407 1.2 thorpej * queued up by a signal or broadcast (but hasn't yet run as far
408 1.2 thorpej * as pthread__alarm_del(), or we wouldn't be here, and hence can't
409 1.2 thorpej * have become blocked on some *other* queue).
410 1.2 thorpej */
411 1.2 thorpej if (a->ptw_thread->pt_state == PT_STATE_BLOCKED_QUEUE) {
412 1.2 thorpej PTQ_REMOVE(a->ptw_queue, a->ptw_thread, pt_sleep);
413 1.2 thorpej pthread__sched(self, a->ptw_thread);
414 1.2 thorpej }
415 1.2 thorpej pthread_spinunlock(self, &a->ptw_rwlock->ptr_interlock);
416 1.2 thorpej
417 1.2 thorpej }
418 1.2 thorpej
419 1.2 thorpej
420 1.2 thorpej int
421 1.2 thorpej pthread_rwlock_unlock(pthread_rwlock_t *rwlock)
422 1.2 thorpej {
423 1.3 nathanw pthread_t self, writer;
424 1.2 thorpej struct pthread_queue_t blockedq;
425 1.2 thorpej #ifdef ERRORCHECK
426 1.2 thorpej if ((rwlock == NULL) || (rwlock->ptr_magic != _PT_RWLOCK_MAGIC))
427 1.2 thorpej return EINVAL;
428 1.2 thorpej #endif
429 1.2 thorpej writer = NULL;
430 1.2 thorpej PTQ_INIT(&blockedq);
431 1.2 thorpej self = pthread__self();
432 1.2 thorpej
433 1.2 thorpej pthread_spinlock(self, &rwlock->ptr_interlock);
434 1.2 thorpej if (rwlock->ptr_writer != NULL) {
435 1.2 thorpej /* Releasing a write lock. */
436 1.2 thorpej #ifdef ERRORCHECK
437 1.2 thorpej if (rwlock->ptr_writer != self) {
438 1.2 thorpej pthread_spinunlock(self, &rwlock->ptr_interlock);
439 1.2 thorpej return EPERM;
440 1.2 thorpej }
441 1.2 thorpej #endif
442 1.2 thorpej rwlock->ptr_writer = NULL;
443 1.2 thorpej writer = PTQ_FIRST(&rwlock->ptr_wblocked);
444 1.2 thorpej if (writer != NULL) {
445 1.2 thorpej PTQ_REMOVE(&rwlock->ptr_wblocked, writer, pt_sleep);
446 1.2 thorpej } else {
447 1.2 thorpej blockedq = rwlock->ptr_rblocked;
448 1.2 thorpej PTQ_INIT(&rwlock->ptr_rblocked);
449 1.2 thorpej }
450 1.7 cl } else
451 1.7 cl #ifdef ERRORCHECK
452 1.7 cl if (rwlock->ptr_nreaders > 0)
453 1.7 cl #endif
454 1.7 cl {
455 1.2 thorpej /* Releasing a read lock. */
456 1.2 thorpej rwlock->ptr_nreaders--;
457 1.2 thorpej if (rwlock->ptr_nreaders == 0) {
458 1.2 thorpej writer = PTQ_FIRST(&rwlock->ptr_wblocked);
459 1.2 thorpej if (writer != NULL)
460 1.2 thorpej PTQ_REMOVE(&rwlock->ptr_wblocked, writer,
461 1.2 thorpej pt_sleep);
462 1.2 thorpej }
463 1.7 cl #ifdef ERRORCHECK
464 1.7 cl } else {
465 1.7 cl pthread_spinunlock(self, &rwlock->ptr_interlock);
466 1.7 cl return EPERM;
467 1.7 cl #endif
468 1.2 thorpej }
469 1.2 thorpej
470 1.2 thorpej if (writer != NULL)
471 1.2 thorpej pthread__sched(self, writer);
472 1.2 thorpej else
473 1.3 nathanw pthread__sched_sleepers(self, &blockedq);
474 1.2 thorpej
475 1.6 cl pthread_spinunlock(self, &rwlock->ptr_interlock);
476 1.6 cl
477 1.2 thorpej return 0;
478 1.2 thorpej }
479 1.2 thorpej
480 1.2 thorpej
481 1.2 thorpej int
482 1.2 thorpej pthread_rwlockattr_init(pthread_rwlockattr_t *attr)
483 1.2 thorpej {
484 1.2 thorpej #ifdef ERRORCHECK
485 1.2 thorpej if (attr == NULL)
486 1.2 thorpej return EINVAL;
487 1.2 thorpej #endif
488 1.2 thorpej attr->ptra_magic = _PT_RWLOCKATTR_MAGIC;
489 1.2 thorpej
490 1.2 thorpej return 0;
491 1.2 thorpej }
492 1.2 thorpej
493 1.2 thorpej
494 1.2 thorpej int
495 1.2 thorpej pthread_rwlockattr_destroy(pthread_rwlockattr_t *attr)
496 1.2 thorpej {
497 1.2 thorpej #ifdef ERRORCHECK
498 1.2 thorpej if ((attr == NULL) ||
499 1.2 thorpej (attr->ptra_magic != _PT_RWLOCKATTR_MAGIC))
500 1.2 thorpej return EINVAL;
501 1.2 thorpej #endif
502 1.2 thorpej attr->ptra_magic = _PT_RWLOCKATTR_DEAD;
503 1.2 thorpej
504 1.2 thorpej return 0;
505 1.2 thorpej }
506