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