pthread_rwlock.c revision 1.12 1 1.12 chs /* $NetBSD: pthread_rwlock.c,v 1.12 2005/10/16 00:07:24 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.12 chs __RCSID("$NetBSD: pthread_rwlock.c,v 1.12 2005/10/16 00:07:24 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.2 thorpej #ifdef ERRORCHECK
173 1.2 thorpej if ((rwlock == NULL) || (rwlock->ptr_magic != _PT_RWLOCK_MAGIC))
174 1.2 thorpej return EINVAL;
175 1.2 thorpej #endif
176 1.2 thorpej self = pthread__self();
177 1.2 thorpej
178 1.2 thorpej pthread_spinlock(self, &rwlock->ptr_interlock);
179 1.7 cl #ifdef ERRORCHECK
180 1.7 cl if (rwlock->ptr_writer == self) {
181 1.7 cl pthread_spinunlock(self, &rwlock->ptr_interlock);
182 1.7 cl return EDEADLK;
183 1.7 cl }
184 1.7 cl #endif
185 1.2 thorpej /*
186 1.2 thorpej * Prefer writers to readers here; permit writers even if there are
187 1.2 thorpej * waiting readers.
188 1.2 thorpej */
189 1.2 thorpej while ((rwlock->ptr_nreaders > 0) || (rwlock->ptr_writer != NULL)) {
190 1.2 thorpej PTQ_INSERT_TAIL(&rwlock->ptr_wblocked, self, pt_sleep);
191 1.2 thorpej /* Locking a rwlock is not a cancellation point; don't check */
192 1.2 thorpej pthread_spinlock(self, &self->pt_statelock);
193 1.2 thorpej self->pt_state = PT_STATE_BLOCKED_QUEUE;
194 1.2 thorpej self->pt_sleepobj = rwlock;
195 1.2 thorpej self->pt_sleepq = &rwlock->ptr_wblocked;
196 1.2 thorpej self->pt_sleeplock = &rwlock->ptr_interlock;
197 1.2 thorpej pthread_spinunlock(self, &self->pt_statelock);
198 1.2 thorpej pthread__block(self, &rwlock->ptr_interlock);
199 1.2 thorpej /* interlock is not held when we return */
200 1.2 thorpej pthread_spinlock(self, &rwlock->ptr_interlock);
201 1.2 thorpej }
202 1.2 thorpej
203 1.2 thorpej rwlock->ptr_writer = self;
204 1.2 thorpej pthread_spinunlock(self, &rwlock->ptr_interlock);
205 1.2 thorpej
206 1.2 thorpej return 0;
207 1.2 thorpej }
208 1.2 thorpej
209 1.2 thorpej
210 1.2 thorpej int
211 1.2 thorpej pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock)
212 1.2 thorpej {
213 1.2 thorpej pthread_t self;
214 1.2 thorpej #ifdef ERRORCHECK
215 1.2 thorpej if ((rwlock == NULL) || (rwlock->ptr_magic != _PT_RWLOCK_MAGIC))
216 1.2 thorpej return EINVAL;
217 1.2 thorpej #endif
218 1.2 thorpej self = pthread__self();
219 1.2 thorpej
220 1.2 thorpej pthread_spinlock(self, &rwlock->ptr_interlock);
221 1.2 thorpej /*
222 1.2 thorpej * Prefer writers to readers here; permit writers even if there are
223 1.2 thorpej * waiting readers.
224 1.2 thorpej */
225 1.2 thorpej if ((rwlock->ptr_nreaders > 0) || (rwlock->ptr_writer != NULL)) {
226 1.2 thorpej pthread_spinunlock(self, &rwlock->ptr_interlock);
227 1.2 thorpej return EBUSY;
228 1.2 thorpej }
229 1.2 thorpej
230 1.2 thorpej rwlock->ptr_writer = self;
231 1.2 thorpej pthread_spinunlock(self, &rwlock->ptr_interlock);
232 1.2 thorpej
233 1.2 thorpej return 0;
234 1.2 thorpej }
235 1.2 thorpej
236 1.2 thorpej
237 1.2 thorpej struct pthread_rwlock__waitarg {
238 1.2 thorpej pthread_t ptw_thread;
239 1.2 thorpej pthread_rwlock_t *ptw_rwlock;
240 1.2 thorpej struct pthread_queue_t *ptw_queue;
241 1.2 thorpej };
242 1.2 thorpej
243 1.2 thorpej int
244 1.2 thorpej pthread_rwlock_timedrdlock(pthread_rwlock_t *rwlock,
245 1.2 thorpej const struct timespec *abs_timeout)
246 1.2 thorpej {
247 1.2 thorpej pthread_t self;
248 1.2 thorpej struct pthread_rwlock__waitarg wait;
249 1.2 thorpej struct pt_alarm_t alarm;
250 1.2 thorpej int retval;
251 1.12 chs
252 1.2 thorpej #ifdef ERRORCHECK
253 1.2 thorpej if ((rwlock == NULL) || (rwlock->ptr_magic != _PT_RWLOCK_MAGIC))
254 1.2 thorpej return EINVAL;
255 1.10 nathanw if (abs_timeout == NULL)
256 1.2 thorpej return EINVAL;
257 1.2 thorpej #endif
258 1.10 nathanw if ((abs_timeout->tv_nsec >= 1000000000) ||
259 1.10 nathanw (abs_timeout->tv_nsec < 0) ||
260 1.10 nathanw (abs_timeout->tv_sec < 0))
261 1.10 nathanw return EINVAL;
262 1.12 chs
263 1.2 thorpej self = pthread__self();
264 1.2 thorpej pthread_spinlock(self, &rwlock->ptr_interlock);
265 1.2 thorpej #ifdef ERRORCHECK
266 1.2 thorpej if (rwlock->ptr_writer == self) {
267 1.9 yamt pthread_spinunlock(self, &rwlock->ptr_interlock);
268 1.2 thorpej return EDEADLK;
269 1.2 thorpej }
270 1.2 thorpej #endif
271 1.2 thorpej /*
272 1.2 thorpej * Don't get a readlock if there is a writer or if there are waiting
273 1.2 thorpej * writers; i.e. prefer writers to readers. This strategy is dictated
274 1.2 thorpej * by SUSv3.
275 1.2 thorpej */
276 1.2 thorpej retval = 0;
277 1.2 thorpej while ((retval == 0) && ((rwlock->ptr_writer != NULL) ||
278 1.2 thorpej (!PTQ_EMPTY(&rwlock->ptr_wblocked)))) {
279 1.2 thorpej wait.ptw_thread = self;
280 1.2 thorpej wait.ptw_rwlock = rwlock;
281 1.2 thorpej wait.ptw_queue = &rwlock->ptr_rblocked;
282 1.2 thorpej pthread__alarm_add(self, &alarm, abs_timeout,
283 1.2 thorpej pthread_rwlock__callback, &wait);
284 1.2 thorpej PTQ_INSERT_TAIL(&rwlock->ptr_rblocked, self, pt_sleep);
285 1.2 thorpej /* Locking a rwlock is not a cancellation point; don't check */
286 1.2 thorpej pthread_spinlock(self, &self->pt_statelock);
287 1.2 thorpej self->pt_state = PT_STATE_BLOCKED_QUEUE;
288 1.2 thorpej self->pt_sleepobj = rwlock;
289 1.2 thorpej self->pt_sleepq = &rwlock->ptr_rblocked;
290 1.2 thorpej self->pt_sleeplock = &rwlock->ptr_interlock;
291 1.2 thorpej pthread_spinunlock(self, &self->pt_statelock);
292 1.2 thorpej pthread__block(self, &rwlock->ptr_interlock);
293 1.2 thorpej /* interlock is not held when we return */
294 1.2 thorpej pthread__alarm_del(self, &alarm);
295 1.2 thorpej if (pthread__alarm_fired(&alarm))
296 1.2 thorpej retval = ETIMEDOUT;
297 1.2 thorpej pthread_spinlock(self, &rwlock->ptr_interlock);
298 1.2 thorpej }
299 1.2 thorpej
300 1.11 nathanw /* One last chance to get the lock, in case it was released between
301 1.11 nathanw the alarm firing and when this thread got rescheduled, or in case
302 1.11 nathanw a signal handler kept it busy */
303 1.11 nathanw if ((rwlock->ptr_writer == NULL) &&
304 1.11 nathanw (PTQ_EMPTY(&rwlock->ptr_wblocked))) {
305 1.2 thorpej rwlock->ptr_nreaders++;
306 1.11 nathanw retval = 0;
307 1.11 nathanw }
308 1.2 thorpej pthread_spinunlock(self, &rwlock->ptr_interlock);
309 1.2 thorpej
310 1.2 thorpej return retval;
311 1.2 thorpej }
312 1.2 thorpej
313 1.2 thorpej
314 1.2 thorpej int
315 1.2 thorpej pthread_rwlock_timedwrlock(pthread_rwlock_t *rwlock,
316 1.2 thorpej const struct timespec *abs_timeout)
317 1.2 thorpej {
318 1.2 thorpej struct pthread_rwlock__waitarg wait;
319 1.2 thorpej struct pt_alarm_t alarm;
320 1.12 chs pthread_t self;
321 1.2 thorpej int retval;
322 1.12 chs extern int pthread__started;
323 1.12 chs
324 1.2 thorpej #ifdef ERRORCHECK
325 1.2 thorpej if ((rwlock == NULL) || (rwlock->ptr_magic != _PT_RWLOCK_MAGIC))
326 1.2 thorpej return EINVAL;
327 1.10 nathanw if (abs_timeout == NULL)
328 1.10 nathanw return EINVAL;
329 1.2 thorpej #endif
330 1.10 nathanw if ((abs_timeout->tv_nsec >= 1000000000) ||
331 1.10 nathanw (abs_timeout->tv_nsec < 0) ||
332 1.10 nathanw (abs_timeout->tv_sec < 0))
333 1.10 nathanw return EINVAL;
334 1.12 chs
335 1.12 chs if (pthread__started == 0) {
336 1.12 chs pthread__start();
337 1.12 chs pthread__started = 1;
338 1.12 chs }
339 1.12 chs
340 1.2 thorpej self = pthread__self();
341 1.2 thorpej pthread_spinlock(self, &rwlock->ptr_interlock);
342 1.7 cl #ifdef ERRORCHECK
343 1.7 cl if (rwlock->ptr_writer == self) {
344 1.9 yamt pthread_spinunlock(self, &rwlock->ptr_interlock);
345 1.7 cl return EDEADLK;
346 1.7 cl }
347 1.7 cl #endif
348 1.2 thorpej /*
349 1.2 thorpej * Prefer writers to readers here; permit writers even if there are
350 1.2 thorpej * waiting readers.
351 1.2 thorpej */
352 1.2 thorpej retval = 0;
353 1.2 thorpej while (retval == 0 &&
354 1.2 thorpej ((rwlock->ptr_nreaders > 0) || (rwlock->ptr_writer != NULL))) {
355 1.2 thorpej wait.ptw_thread = self;
356 1.2 thorpej wait.ptw_rwlock = rwlock;
357 1.2 thorpej wait.ptw_queue = &rwlock->ptr_wblocked;
358 1.2 thorpej pthread__alarm_add(self, &alarm, abs_timeout,
359 1.2 thorpej pthread_rwlock__callback, &wait);
360 1.2 thorpej PTQ_INSERT_TAIL(&rwlock->ptr_wblocked, self, pt_sleep);
361 1.2 thorpej /* Locking a rwlock is not a cancellation point; don't check */
362 1.2 thorpej pthread_spinlock(self, &self->pt_statelock);
363 1.2 thorpej self->pt_state = PT_STATE_BLOCKED_QUEUE;
364 1.2 thorpej self->pt_sleepobj = rwlock;
365 1.2 thorpej self->pt_sleepq = &rwlock->ptr_wblocked;
366 1.2 thorpej self->pt_sleeplock = &rwlock->ptr_interlock;
367 1.2 thorpej pthread_spinunlock(self, &self->pt_statelock);
368 1.2 thorpej pthread__block(self, &rwlock->ptr_interlock);
369 1.2 thorpej /* interlock is not held when we return */
370 1.2 thorpej pthread__alarm_del(self, &alarm);
371 1.2 thorpej if (pthread__alarm_fired(&alarm))
372 1.2 thorpej retval = ETIMEDOUT;
373 1.2 thorpej pthread_spinlock(self, &rwlock->ptr_interlock);
374 1.2 thorpej }
375 1.2 thorpej
376 1.11 nathanw if ((rwlock->ptr_nreaders == 0) && (rwlock->ptr_writer == NULL)) {
377 1.2 thorpej rwlock->ptr_writer = self;
378 1.11 nathanw retval = 0;
379 1.11 nathanw }
380 1.2 thorpej pthread_spinunlock(self, &rwlock->ptr_interlock);
381 1.2 thorpej
382 1.8 yamt return retval;
383 1.2 thorpej }
384 1.2 thorpej
385 1.2 thorpej
386 1.2 thorpej static void
387 1.2 thorpej pthread_rwlock__callback(void *arg)
388 1.2 thorpej {
389 1.2 thorpej struct pthread_rwlock__waitarg *a;
390 1.2 thorpej pthread_t self;
391 1.2 thorpej
392 1.2 thorpej a = arg;
393 1.2 thorpej self = pthread__self();
394 1.2 thorpej
395 1.2 thorpej pthread_spinlock(self, &a->ptw_rwlock->ptr_interlock);
396 1.2 thorpej /*
397 1.2 thorpej * Don't dequeue and schedule the thread if it's already been
398 1.2 thorpej * queued up by a signal or broadcast (but hasn't yet run as far
399 1.2 thorpej * as pthread__alarm_del(), or we wouldn't be here, and hence can't
400 1.2 thorpej * have become blocked on some *other* queue).
401 1.2 thorpej */
402 1.2 thorpej if (a->ptw_thread->pt_state == PT_STATE_BLOCKED_QUEUE) {
403 1.2 thorpej PTQ_REMOVE(a->ptw_queue, a->ptw_thread, pt_sleep);
404 1.2 thorpej pthread__sched(self, a->ptw_thread);
405 1.2 thorpej }
406 1.2 thorpej pthread_spinunlock(self, &a->ptw_rwlock->ptr_interlock);
407 1.2 thorpej
408 1.2 thorpej }
409 1.2 thorpej
410 1.2 thorpej
411 1.2 thorpej int
412 1.2 thorpej pthread_rwlock_unlock(pthread_rwlock_t *rwlock)
413 1.2 thorpej {
414 1.3 nathanw pthread_t self, writer;
415 1.2 thorpej struct pthread_queue_t blockedq;
416 1.2 thorpej #ifdef ERRORCHECK
417 1.2 thorpej if ((rwlock == NULL) || (rwlock->ptr_magic != _PT_RWLOCK_MAGIC))
418 1.2 thorpej return EINVAL;
419 1.2 thorpej #endif
420 1.2 thorpej writer = NULL;
421 1.2 thorpej PTQ_INIT(&blockedq);
422 1.2 thorpej self = pthread__self();
423 1.2 thorpej
424 1.2 thorpej pthread_spinlock(self, &rwlock->ptr_interlock);
425 1.2 thorpej if (rwlock->ptr_writer != NULL) {
426 1.2 thorpej /* Releasing a write lock. */
427 1.2 thorpej #ifdef ERRORCHECK
428 1.2 thorpej if (rwlock->ptr_writer != self) {
429 1.2 thorpej pthread_spinunlock(self, &rwlock->ptr_interlock);
430 1.2 thorpej return EPERM;
431 1.2 thorpej }
432 1.2 thorpej #endif
433 1.2 thorpej rwlock->ptr_writer = NULL;
434 1.2 thorpej writer = PTQ_FIRST(&rwlock->ptr_wblocked);
435 1.2 thorpej if (writer != NULL) {
436 1.2 thorpej PTQ_REMOVE(&rwlock->ptr_wblocked, writer, pt_sleep);
437 1.2 thorpej } else {
438 1.2 thorpej blockedq = rwlock->ptr_rblocked;
439 1.2 thorpej PTQ_INIT(&rwlock->ptr_rblocked);
440 1.2 thorpej }
441 1.7 cl } else
442 1.7 cl #ifdef ERRORCHECK
443 1.7 cl if (rwlock->ptr_nreaders > 0)
444 1.7 cl #endif
445 1.7 cl {
446 1.2 thorpej /* Releasing a read lock. */
447 1.2 thorpej rwlock->ptr_nreaders--;
448 1.2 thorpej if (rwlock->ptr_nreaders == 0) {
449 1.2 thorpej writer = PTQ_FIRST(&rwlock->ptr_wblocked);
450 1.2 thorpej if (writer != NULL)
451 1.2 thorpej PTQ_REMOVE(&rwlock->ptr_wblocked, writer,
452 1.2 thorpej pt_sleep);
453 1.2 thorpej }
454 1.7 cl #ifdef ERRORCHECK
455 1.7 cl } else {
456 1.7 cl pthread_spinunlock(self, &rwlock->ptr_interlock);
457 1.7 cl return EPERM;
458 1.7 cl #endif
459 1.2 thorpej }
460 1.2 thorpej
461 1.2 thorpej if (writer != NULL)
462 1.2 thorpej pthread__sched(self, writer);
463 1.2 thorpej else
464 1.3 nathanw pthread__sched_sleepers(self, &blockedq);
465 1.2 thorpej
466 1.6 cl pthread_spinunlock(self, &rwlock->ptr_interlock);
467 1.6 cl
468 1.2 thorpej return 0;
469 1.2 thorpej }
470 1.2 thorpej
471 1.2 thorpej
472 1.2 thorpej int
473 1.2 thorpej pthread_rwlockattr_init(pthread_rwlockattr_t *attr)
474 1.2 thorpej {
475 1.2 thorpej #ifdef ERRORCHECK
476 1.2 thorpej if (attr == NULL)
477 1.2 thorpej return EINVAL;
478 1.2 thorpej #endif
479 1.2 thorpej attr->ptra_magic = _PT_RWLOCKATTR_MAGIC;
480 1.2 thorpej
481 1.2 thorpej return 0;
482 1.2 thorpej }
483 1.2 thorpej
484 1.2 thorpej
485 1.2 thorpej int
486 1.2 thorpej pthread_rwlockattr_destroy(pthread_rwlockattr_t *attr)
487 1.2 thorpej {
488 1.2 thorpej #ifdef ERRORCHECK
489 1.2 thorpej if ((attr == NULL) ||
490 1.2 thorpej (attr->ptra_magic != _PT_RWLOCKATTR_MAGIC))
491 1.2 thorpej return EINVAL;
492 1.2 thorpej #endif
493 1.2 thorpej attr->ptra_magic = _PT_RWLOCKATTR_DEAD;
494 1.2 thorpej
495 1.2 thorpej return 0;
496 1.2 thorpej }
497