pthread_rwlock.c revision 1.24 1 1.24 christos /* $NetBSD: pthread_rwlock.c,v 1.24 2008/01/08 20:55:25 christos Exp $ */
2 1.2 thorpej
3 1.2 thorpej /*-
4 1.16 ad * Copyright (c) 2002, 2006, 2007 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.17 ad * by Nathan J. Williams and Andrew Doran.
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.24 christos __RCSID("$NetBSD: pthread_rwlock.c,v 1.24 2008/01/08 20:55:25 christos 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.21 ad #ifndef PTHREAD__HAVE_ATOMIC
48 1.21 ad
49 1.24 christos __weak_alias(pthread_mutex_held_np,_pthread_rwlock_held_np)
50 1.24 christos __weak_alias(pthread_mutex_rdheld_np,_pthread_rwlock_rdheld_np)
51 1.24 christos __weak_alias(pthread_mutex_wrheld_np,_pthread_rwlock_wrheld_np)
52 1.24 christos
53 1.23 ad int _pthread_rwlock_held_np(pthread_rwlock_t *);
54 1.23 ad int _pthread_rwlock_rdheld_np(pthread_rwlock_t *);
55 1.23 ad int _pthread_rwlock_wrheld_np(pthread_rwlock_t *);
56 1.23 ad
57 1.2 thorpej __strong_alias(__libc_rwlock_init,pthread_rwlock_init)
58 1.2 thorpej __strong_alias(__libc_rwlock_rdlock,pthread_rwlock_rdlock)
59 1.2 thorpej __strong_alias(__libc_rwlock_wrlock,pthread_rwlock_wrlock)
60 1.2 thorpej __strong_alias(__libc_rwlock_tryrdlock,pthread_rwlock_tryrdlock)
61 1.2 thorpej __strong_alias(__libc_rwlock_trywrlock,pthread_rwlock_trywrlock)
62 1.2 thorpej __strong_alias(__libc_rwlock_unlock,pthread_rwlock_unlock)
63 1.2 thorpej __strong_alias(__libc_rwlock_destroy,pthread_rwlock_destroy)
64 1.2 thorpej
65 1.2 thorpej int
66 1.2 thorpej pthread_rwlock_init(pthread_rwlock_t *rwlock,
67 1.2 thorpej const pthread_rwlockattr_t *attr)
68 1.2 thorpej {
69 1.2 thorpej #ifdef ERRORCHECK
70 1.2 thorpej if ((rwlock == NULL) ||
71 1.2 thorpej (attr && (attr->ptra_magic != _PT_RWLOCKATTR_MAGIC)))
72 1.2 thorpej return EINVAL;
73 1.2 thorpej #endif
74 1.2 thorpej rwlock->ptr_magic = _PT_RWLOCK_MAGIC;
75 1.2 thorpej pthread_lockinit(&rwlock->ptr_interlock);
76 1.2 thorpej PTQ_INIT(&rwlock->ptr_rblocked);
77 1.2 thorpej PTQ_INIT(&rwlock->ptr_wblocked);
78 1.2 thorpej rwlock->ptr_nreaders = 0;
79 1.2 thorpej rwlock->ptr_writer = NULL;
80 1.2 thorpej
81 1.2 thorpej return 0;
82 1.2 thorpej }
83 1.2 thorpej
84 1.2 thorpej
85 1.2 thorpej int
86 1.2 thorpej pthread_rwlock_destroy(pthread_rwlock_t *rwlock)
87 1.2 thorpej {
88 1.2 thorpej #ifdef ERRORCHECK
89 1.2 thorpej if ((rwlock == NULL) ||
90 1.2 thorpej (rwlock->ptr_magic != _PT_RWLOCK_MAGIC) ||
91 1.2 thorpej (!PTQ_EMPTY(&rwlock->ptr_rblocked)) ||
92 1.2 thorpej (!PTQ_EMPTY(&rwlock->ptr_wblocked)) ||
93 1.2 thorpej (rwlock->ptr_nreaders != 0) ||
94 1.2 thorpej (rwlock->ptr_writer != NULL))
95 1.2 thorpej return EINVAL;
96 1.2 thorpej #endif
97 1.2 thorpej rwlock->ptr_magic = _PT_RWLOCK_DEAD;
98 1.2 thorpej
99 1.2 thorpej return 0;
100 1.2 thorpej }
101 1.2 thorpej
102 1.2 thorpej
103 1.2 thorpej int
104 1.2 thorpej pthread_rwlock_rdlock(pthread_rwlock_t *rwlock)
105 1.2 thorpej {
106 1.2 thorpej pthread_t self;
107 1.2 thorpej #ifdef ERRORCHECK
108 1.2 thorpej if ((rwlock == NULL) || (rwlock->ptr_magic != _PT_RWLOCK_MAGIC))
109 1.2 thorpej return EINVAL;
110 1.2 thorpej #endif
111 1.2 thorpej self = pthread__self();
112 1.2 thorpej
113 1.22 ad pthread__spinlock(self, &rwlock->ptr_interlock);
114 1.2 thorpej #ifdef ERRORCHECK
115 1.2 thorpej if (rwlock->ptr_writer == self) {
116 1.22 ad pthread__spinunlock(self, &rwlock->ptr_interlock);
117 1.2 thorpej return EDEADLK;
118 1.2 thorpej }
119 1.2 thorpej #endif
120 1.2 thorpej /*
121 1.2 thorpej * Don't get a readlock if there is a writer or if there are waiting
122 1.2 thorpej * writers; i.e. prefer writers to readers. This strategy is dictated
123 1.2 thorpej * by SUSv3.
124 1.2 thorpej */
125 1.2 thorpej while ((rwlock->ptr_writer != NULL) ||
126 1.2 thorpej (!PTQ_EMPTY(&rwlock->ptr_wblocked))) {
127 1.17 ad PTQ_INSERT_TAIL(&rwlock->ptr_rblocked, self, pt_sleep);
128 1.17 ad self->pt_sleeponq = 1;
129 1.17 ad self->pt_sleepobj = &rwlock->ptr_rblocked;
130 1.22 ad pthread__spinunlock(self, &rwlock->ptr_interlock);
131 1.15 ad (void)pthread__park(self, &rwlock->ptr_interlock,
132 1.18 ad &rwlock->ptr_rblocked, NULL, 0, &rwlock->ptr_rblocked);
133 1.22 ad pthread__spinlock(self, &rwlock->ptr_interlock);
134 1.2 thorpej }
135 1.2 thorpej
136 1.2 thorpej rwlock->ptr_nreaders++;
137 1.22 ad pthread__spinunlock(self, &rwlock->ptr_interlock);
138 1.2 thorpej
139 1.2 thorpej return 0;
140 1.2 thorpej }
141 1.2 thorpej
142 1.2 thorpej
143 1.2 thorpej int
144 1.2 thorpej pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock)
145 1.2 thorpej {
146 1.22 ad pthread_t self;
147 1.20 ad
148 1.2 thorpej #ifdef ERRORCHECK
149 1.2 thorpej if ((rwlock == NULL) || (rwlock->ptr_magic != _PT_RWLOCK_MAGIC))
150 1.2 thorpej return EINVAL;
151 1.2 thorpej #endif
152 1.2 thorpej
153 1.22 ad self = pthread__self();
154 1.22 ad pthread__spinlock(self, &rwlock->ptr_interlock);
155 1.2 thorpej /*
156 1.2 thorpej * Don't get a readlock if there is a writer or if there are waiting
157 1.2 thorpej * writers; i.e. prefer writers to readers. This strategy is dictated
158 1.2 thorpej * by SUSv3.
159 1.2 thorpej */
160 1.2 thorpej if ((rwlock->ptr_writer != NULL) ||
161 1.2 thorpej (!PTQ_EMPTY(&rwlock->ptr_wblocked))) {
162 1.22 ad pthread__spinunlock(self, &rwlock->ptr_interlock);
163 1.2 thorpej return EBUSY;
164 1.2 thorpej }
165 1.2 thorpej
166 1.2 thorpej rwlock->ptr_nreaders++;
167 1.22 ad pthread__spinunlock(self, &rwlock->ptr_interlock);
168 1.2 thorpej
169 1.2 thorpej return 0;
170 1.2 thorpej }
171 1.2 thorpej
172 1.2 thorpej
173 1.2 thorpej int
174 1.2 thorpej pthread_rwlock_wrlock(pthread_rwlock_t *rwlock)
175 1.2 thorpej {
176 1.2 thorpej pthread_t self;
177 1.13 chs extern int pthread__started;
178 1.13 chs
179 1.2 thorpej #ifdef ERRORCHECK
180 1.2 thorpej if ((rwlock == NULL) || (rwlock->ptr_magic != _PT_RWLOCK_MAGIC))
181 1.2 thorpej return EINVAL;
182 1.2 thorpej #endif
183 1.2 thorpej self = pthread__self();
184 1.2 thorpej
185 1.22 ad pthread__spinlock(self, &rwlock->ptr_interlock);
186 1.7 cl #ifdef ERRORCHECK
187 1.7 cl if (rwlock->ptr_writer == self) {
188 1.22 ad pthread__spinunlock(self, &rwlock->ptr_interlock);
189 1.7 cl return EDEADLK;
190 1.7 cl }
191 1.7 cl #endif
192 1.2 thorpej /*
193 1.2 thorpej * Prefer writers to readers here; permit writers even if there are
194 1.2 thorpej * waiting readers.
195 1.2 thorpej */
196 1.2 thorpej while ((rwlock->ptr_nreaders > 0) || (rwlock->ptr_writer != NULL)) {
197 1.13 chs #ifdef ERRORCHECK
198 1.13 chs if (pthread__started == 0) {
199 1.22 ad pthread__spinunlock(self, &rwlock->ptr_interlock);
200 1.13 chs return EDEADLK;
201 1.13 chs }
202 1.13 chs #endif
203 1.17 ad PTQ_INSERT_TAIL(&rwlock->ptr_wblocked, self, pt_sleep);
204 1.17 ad self->pt_sleeponq = 1;
205 1.17 ad self->pt_sleepobj = &rwlock->ptr_wblocked;
206 1.22 ad pthread__spinunlock(self, &rwlock->ptr_interlock);
207 1.15 ad (void)pthread__park(self, &rwlock->ptr_interlock,
208 1.18 ad &rwlock->ptr_wblocked, NULL, 0, &rwlock->ptr_wblocked);
209 1.22 ad pthread__spinlock(self, &rwlock->ptr_interlock);
210 1.2 thorpej }
211 1.2 thorpej
212 1.2 thorpej rwlock->ptr_writer = self;
213 1.22 ad pthread__spinunlock(self, &rwlock->ptr_interlock);
214 1.2 thorpej
215 1.2 thorpej return 0;
216 1.2 thorpej }
217 1.2 thorpej
218 1.2 thorpej
219 1.2 thorpej int
220 1.2 thorpej pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock)
221 1.2 thorpej {
222 1.2 thorpej pthread_t self;
223 1.2 thorpej #ifdef ERRORCHECK
224 1.2 thorpej if ((rwlock == NULL) || (rwlock->ptr_magic != _PT_RWLOCK_MAGIC))
225 1.2 thorpej return EINVAL;
226 1.2 thorpej #endif
227 1.2 thorpej self = pthread__self();
228 1.2 thorpej
229 1.22 ad pthread__spinlock(self, &rwlock->ptr_interlock);
230 1.2 thorpej /*
231 1.2 thorpej * Prefer writers to readers here; permit writers even if there are
232 1.2 thorpej * waiting readers.
233 1.2 thorpej */
234 1.2 thorpej if ((rwlock->ptr_nreaders > 0) || (rwlock->ptr_writer != NULL)) {
235 1.22 ad pthread__spinunlock(self, &rwlock->ptr_interlock);
236 1.2 thorpej return EBUSY;
237 1.2 thorpej }
238 1.2 thorpej
239 1.2 thorpej rwlock->ptr_writer = self;
240 1.22 ad pthread__spinunlock(self, &rwlock->ptr_interlock);
241 1.2 thorpej
242 1.2 thorpej return 0;
243 1.2 thorpej }
244 1.2 thorpej
245 1.2 thorpej
246 1.2 thorpej int
247 1.2 thorpej pthread_rwlock_timedrdlock(pthread_rwlock_t *rwlock,
248 1.2 thorpej const struct timespec *abs_timeout)
249 1.2 thorpej {
250 1.2 thorpej pthread_t self;
251 1.2 thorpej int retval;
252 1.12 chs
253 1.2 thorpej #ifdef ERRORCHECK
254 1.2 thorpej if ((rwlock == NULL) || (rwlock->ptr_magic != _PT_RWLOCK_MAGIC))
255 1.2 thorpej return EINVAL;
256 1.10 nathanw if (abs_timeout == NULL)
257 1.2 thorpej return EINVAL;
258 1.2 thorpej #endif
259 1.10 nathanw if ((abs_timeout->tv_nsec >= 1000000000) ||
260 1.10 nathanw (abs_timeout->tv_nsec < 0) ||
261 1.10 nathanw (abs_timeout->tv_sec < 0))
262 1.10 nathanw return EINVAL;
263 1.12 chs
264 1.2 thorpej self = pthread__self();
265 1.22 ad pthread__spinlock(self, &rwlock->ptr_interlock);
266 1.2 thorpej #ifdef ERRORCHECK
267 1.2 thorpej if (rwlock->ptr_writer == self) {
268 1.22 ad pthread__spinunlock(self, &rwlock->ptr_interlock);
269 1.2 thorpej return EDEADLK;
270 1.2 thorpej }
271 1.2 thorpej #endif
272 1.2 thorpej /*
273 1.2 thorpej * Don't get a readlock if there is a writer or if there are waiting
274 1.2 thorpej * writers; i.e. prefer writers to readers. This strategy is dictated
275 1.2 thorpej * by SUSv3.
276 1.2 thorpej */
277 1.2 thorpej retval = 0;
278 1.2 thorpej while ((retval == 0) && ((rwlock->ptr_writer != NULL) ||
279 1.2 thorpej (!PTQ_EMPTY(&rwlock->ptr_wblocked)))) {
280 1.17 ad PTQ_INSERT_TAIL(&rwlock->ptr_rblocked, self, pt_sleep);
281 1.17 ad self->pt_sleeponq = 1;
282 1.17 ad self->pt_sleepobj = &rwlock->ptr_rblocked;
283 1.22 ad pthread__spinunlock(self, &rwlock->ptr_interlock);
284 1.15 ad retval = pthread__park(self, &rwlock->ptr_interlock,
285 1.18 ad &rwlock->ptr_rblocked, abs_timeout, 0,
286 1.18 ad &rwlock->ptr_rblocked);
287 1.22 ad pthread__spinlock(self, &rwlock->ptr_interlock);
288 1.2 thorpej }
289 1.2 thorpej
290 1.11 nathanw /* One last chance to get the lock, in case it was released between
291 1.11 nathanw the alarm firing and when this thread got rescheduled, or in case
292 1.11 nathanw a signal handler kept it busy */
293 1.11 nathanw if ((rwlock->ptr_writer == NULL) &&
294 1.11 nathanw (PTQ_EMPTY(&rwlock->ptr_wblocked))) {
295 1.2 thorpej rwlock->ptr_nreaders++;
296 1.11 nathanw retval = 0;
297 1.11 nathanw }
298 1.22 ad pthread__spinunlock(self, &rwlock->ptr_interlock);
299 1.2 thorpej
300 1.2 thorpej return retval;
301 1.2 thorpej }
302 1.2 thorpej
303 1.2 thorpej
304 1.2 thorpej int
305 1.2 thorpej pthread_rwlock_timedwrlock(pthread_rwlock_t *rwlock,
306 1.2 thorpej const struct timespec *abs_timeout)
307 1.2 thorpej {
308 1.12 chs pthread_t self;
309 1.2 thorpej int retval;
310 1.12 chs extern int pthread__started;
311 1.12 chs
312 1.2 thorpej #ifdef ERRORCHECK
313 1.2 thorpej if ((rwlock == NULL) || (rwlock->ptr_magic != _PT_RWLOCK_MAGIC))
314 1.2 thorpej return EINVAL;
315 1.10 nathanw if (abs_timeout == NULL)
316 1.10 nathanw return EINVAL;
317 1.2 thorpej #endif
318 1.10 nathanw if ((abs_timeout->tv_nsec >= 1000000000) ||
319 1.10 nathanw (abs_timeout->tv_nsec < 0) ||
320 1.10 nathanw (abs_timeout->tv_sec < 0))
321 1.10 nathanw return EINVAL;
322 1.12 chs
323 1.2 thorpej self = pthread__self();
324 1.22 ad pthread__spinlock(self, &rwlock->ptr_interlock);
325 1.7 cl #ifdef ERRORCHECK
326 1.7 cl if (rwlock->ptr_writer == self) {
327 1.22 ad pthread__spinunlock(self, &rwlock->ptr_interlock);
328 1.7 cl return EDEADLK;
329 1.7 cl }
330 1.7 cl #endif
331 1.2 thorpej /*
332 1.2 thorpej * Prefer writers to readers here; permit writers even if there are
333 1.2 thorpej * waiting readers.
334 1.2 thorpej */
335 1.2 thorpej retval = 0;
336 1.2 thorpej while (retval == 0 &&
337 1.2 thorpej ((rwlock->ptr_nreaders > 0) || (rwlock->ptr_writer != NULL))) {
338 1.13 chs #ifdef ERRORCHECK
339 1.13 chs if (pthread__started == 0) {
340 1.22 ad pthread__spinunlock(self, &rwlock->ptr_interlock);
341 1.13 chs return EDEADLK;
342 1.13 chs }
343 1.13 chs #endif
344 1.17 ad PTQ_INSERT_TAIL(&rwlock->ptr_wblocked, self, pt_sleep);
345 1.17 ad self->pt_sleeponq = 1;
346 1.17 ad self->pt_sleepobj = &rwlock->ptr_wblocked;
347 1.22 ad pthread__spinunlock(self, &rwlock->ptr_interlock);
348 1.15 ad retval = pthread__park(self, &rwlock->ptr_interlock,
349 1.18 ad &rwlock->ptr_wblocked, abs_timeout, 0,
350 1.18 ad &rwlock->ptr_wblocked);
351 1.22 ad pthread__spinlock(self, &rwlock->ptr_interlock);
352 1.2 thorpej }
353 1.2 thorpej
354 1.11 nathanw if ((rwlock->ptr_nreaders == 0) && (rwlock->ptr_writer == NULL)) {
355 1.2 thorpej rwlock->ptr_writer = self;
356 1.11 nathanw retval = 0;
357 1.11 nathanw }
358 1.22 ad pthread__spinunlock(self, &rwlock->ptr_interlock);
359 1.2 thorpej
360 1.8 yamt return retval;
361 1.2 thorpej }
362 1.2 thorpej
363 1.2 thorpej
364 1.2 thorpej int
365 1.2 thorpej pthread_rwlock_unlock(pthread_rwlock_t *rwlock)
366 1.2 thorpej {
367 1.3 nathanw pthread_t self, writer;
368 1.2 thorpej #ifdef ERRORCHECK
369 1.2 thorpej if ((rwlock == NULL) || (rwlock->ptr_magic != _PT_RWLOCK_MAGIC))
370 1.2 thorpej return EINVAL;
371 1.2 thorpej #endif
372 1.2 thorpej writer = NULL;
373 1.2 thorpej self = pthread__self();
374 1.2 thorpej
375 1.22 ad pthread__spinlock(self, &rwlock->ptr_interlock);
376 1.2 thorpej if (rwlock->ptr_writer != NULL) {
377 1.2 thorpej /* Releasing a write lock. */
378 1.2 thorpej #ifdef ERRORCHECK
379 1.2 thorpej if (rwlock->ptr_writer != self) {
380 1.22 ad pthread__spinunlock(self, &rwlock->ptr_interlock);
381 1.2 thorpej return EPERM;
382 1.2 thorpej }
383 1.2 thorpej #endif
384 1.2 thorpej rwlock->ptr_writer = NULL;
385 1.2 thorpej writer = PTQ_FIRST(&rwlock->ptr_wblocked);
386 1.2 thorpej if (writer != NULL) {
387 1.2 thorpej PTQ_REMOVE(&rwlock->ptr_wblocked, writer, pt_sleep);
388 1.2 thorpej }
389 1.7 cl } else
390 1.7 cl #ifdef ERRORCHECK
391 1.7 cl if (rwlock->ptr_nreaders > 0)
392 1.7 cl #endif
393 1.7 cl {
394 1.2 thorpej /* Releasing a read lock. */
395 1.2 thorpej rwlock->ptr_nreaders--;
396 1.2 thorpej if (rwlock->ptr_nreaders == 0) {
397 1.2 thorpej writer = PTQ_FIRST(&rwlock->ptr_wblocked);
398 1.2 thorpej if (writer != NULL)
399 1.2 thorpej PTQ_REMOVE(&rwlock->ptr_wblocked, writer,
400 1.2 thorpej pt_sleep);
401 1.2 thorpej }
402 1.7 cl #ifdef ERRORCHECK
403 1.7 cl } else {
404 1.22 ad pthread__spinunlock(self, &rwlock->ptr_interlock);
405 1.7 cl return EPERM;
406 1.7 cl #endif
407 1.2 thorpej }
408 1.2 thorpej
409 1.14 ad if (writer != NULL)
410 1.17 ad pthread__unpark(self, &rwlock->ptr_interlock,
411 1.17 ad &rwlock->ptr_wblocked, writer);
412 1.14 ad else
413 1.17 ad pthread__unpark_all(self, &rwlock->ptr_interlock,
414 1.15 ad &rwlock->ptr_rblocked);
415 1.6 cl
416 1.2 thorpej return 0;
417 1.2 thorpej }
418 1.2 thorpej
419 1.2 thorpej
420 1.2 thorpej int
421 1.2 thorpej pthread_rwlockattr_init(pthread_rwlockattr_t *attr)
422 1.2 thorpej {
423 1.2 thorpej #ifdef ERRORCHECK
424 1.2 thorpej if (attr == NULL)
425 1.2 thorpej return EINVAL;
426 1.2 thorpej #endif
427 1.2 thorpej attr->ptra_magic = _PT_RWLOCKATTR_MAGIC;
428 1.2 thorpej
429 1.2 thorpej return 0;
430 1.2 thorpej }
431 1.2 thorpej
432 1.2 thorpej
433 1.2 thorpej int
434 1.2 thorpej pthread_rwlockattr_destroy(pthread_rwlockattr_t *attr)
435 1.2 thorpej {
436 1.2 thorpej #ifdef ERRORCHECK
437 1.2 thorpej if ((attr == NULL) ||
438 1.2 thorpej (attr->ptra_magic != _PT_RWLOCKATTR_MAGIC))
439 1.2 thorpej return EINVAL;
440 1.2 thorpej #endif
441 1.2 thorpej attr->ptra_magic = _PT_RWLOCKATTR_DEAD;
442 1.2 thorpej
443 1.2 thorpej return 0;
444 1.2 thorpej }
445 1.21 ad
446 1.23 ad int
447 1.23 ad _pthread_rwlock_held_np(pthread_rwlock_t *ptr)
448 1.23 ad {
449 1.23 ad
450 1.23 ad return ptr->ptr_writer != NULL || ptr->ptr_nreaders != 0;
451 1.23 ad }
452 1.23 ad
453 1.23 ad int
454 1.23 ad _pthread_rwlock_rdheld_np(pthread_rwlock_t *ptr)
455 1.23 ad {
456 1.23 ad
457 1.23 ad return ptr->ptr_nreaders != 0;
458 1.23 ad }
459 1.23 ad
460 1.23 ad int
461 1.23 ad _pthread_rwlock_wrheld_np(pthread_rwlock_t *ptr)
462 1.23 ad {
463 1.23 ad
464 1.23 ad return ptr->ptr_writer != 0;
465 1.23 ad }
466 1.23 ad
467 1.21 ad #endif /* !PTHREAD__HAVE_ATOMIC */
468