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