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