pthread_rwlock.c revision 1.21 1 1.21 ad /* $NetBSD: pthread_rwlock.c,v 1.21 2007/09/07 14:09:28 ad 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.21 ad __RCSID("$NetBSD: pthread_rwlock.c,v 1.21 2007/09/07 14:09:28 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.21 ad #ifndef PTHREAD__HAVE_ATOMIC
48 1.21 ad
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.20 ad pthread_spinlock(&rwlock->ptr_interlock);
106 1.2 thorpej #ifdef ERRORCHECK
107 1.2 thorpej if (rwlock->ptr_writer == self) {
108 1.20 ad pthread_spinunlock(&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.17 ad PTQ_INSERT_TAIL(&rwlock->ptr_rblocked, self, pt_sleep);
120 1.17 ad self->pt_sleeponq = 1;
121 1.17 ad self->pt_sleepobj = &rwlock->ptr_rblocked;
122 1.20 ad pthread_spinunlock(&rwlock->ptr_interlock);
123 1.15 ad (void)pthread__park(self, &rwlock->ptr_interlock,
124 1.18 ad &rwlock->ptr_rblocked, NULL, 0, &rwlock->ptr_rblocked);
125 1.20 ad pthread_spinlock(&rwlock->ptr_interlock);
126 1.2 thorpej }
127 1.2 thorpej
128 1.2 thorpej rwlock->ptr_nreaders++;
129 1.20 ad pthread_spinunlock(&rwlock->ptr_interlock);
130 1.2 thorpej
131 1.2 thorpej return 0;
132 1.2 thorpej }
133 1.2 thorpej
134 1.2 thorpej
135 1.2 thorpej int
136 1.2 thorpej pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock)
137 1.2 thorpej {
138 1.20 ad
139 1.2 thorpej #ifdef ERRORCHECK
140 1.2 thorpej if ((rwlock == NULL) || (rwlock->ptr_magic != _PT_RWLOCK_MAGIC))
141 1.2 thorpej return EINVAL;
142 1.2 thorpej #endif
143 1.2 thorpej
144 1.20 ad pthread_spinlock(&rwlock->ptr_interlock);
145 1.2 thorpej /*
146 1.2 thorpej * Don't get a readlock if there is a writer or if there are waiting
147 1.2 thorpej * writers; i.e. prefer writers to readers. This strategy is dictated
148 1.2 thorpej * by SUSv3.
149 1.2 thorpej */
150 1.2 thorpej if ((rwlock->ptr_writer != NULL) ||
151 1.2 thorpej (!PTQ_EMPTY(&rwlock->ptr_wblocked))) {
152 1.20 ad pthread_spinunlock(&rwlock->ptr_interlock);
153 1.2 thorpej return EBUSY;
154 1.2 thorpej }
155 1.2 thorpej
156 1.2 thorpej rwlock->ptr_nreaders++;
157 1.20 ad pthread_spinunlock(&rwlock->ptr_interlock);
158 1.2 thorpej
159 1.2 thorpej return 0;
160 1.2 thorpej }
161 1.2 thorpej
162 1.2 thorpej
163 1.2 thorpej int
164 1.2 thorpej pthread_rwlock_wrlock(pthread_rwlock_t *rwlock)
165 1.2 thorpej {
166 1.2 thorpej pthread_t self;
167 1.13 chs extern int pthread__started;
168 1.13 chs
169 1.2 thorpej #ifdef ERRORCHECK
170 1.2 thorpej if ((rwlock == NULL) || (rwlock->ptr_magic != _PT_RWLOCK_MAGIC))
171 1.2 thorpej return EINVAL;
172 1.2 thorpej #endif
173 1.2 thorpej self = pthread__self();
174 1.2 thorpej
175 1.20 ad pthread_spinlock(&rwlock->ptr_interlock);
176 1.7 cl #ifdef ERRORCHECK
177 1.7 cl if (rwlock->ptr_writer == self) {
178 1.20 ad pthread_spinunlock(&rwlock->ptr_interlock);
179 1.7 cl return EDEADLK;
180 1.7 cl }
181 1.7 cl #endif
182 1.2 thorpej /*
183 1.2 thorpej * Prefer writers to readers here; permit writers even if there are
184 1.2 thorpej * waiting readers.
185 1.2 thorpej */
186 1.2 thorpej while ((rwlock->ptr_nreaders > 0) || (rwlock->ptr_writer != NULL)) {
187 1.13 chs #ifdef ERRORCHECK
188 1.13 chs if (pthread__started == 0) {
189 1.20 ad pthread_spinunlock(&rwlock->ptr_interlock);
190 1.13 chs return EDEADLK;
191 1.13 chs }
192 1.13 chs #endif
193 1.17 ad PTQ_INSERT_TAIL(&rwlock->ptr_wblocked, self, pt_sleep);
194 1.17 ad self->pt_sleeponq = 1;
195 1.17 ad self->pt_sleepobj = &rwlock->ptr_wblocked;
196 1.20 ad pthread_spinunlock(&rwlock->ptr_interlock);
197 1.15 ad (void)pthread__park(self, &rwlock->ptr_interlock,
198 1.18 ad &rwlock->ptr_wblocked, NULL, 0, &rwlock->ptr_wblocked);
199 1.20 ad pthread_spinlock(&rwlock->ptr_interlock);
200 1.2 thorpej }
201 1.2 thorpej
202 1.2 thorpej rwlock->ptr_writer = self;
203 1.20 ad pthread_spinunlock(&rwlock->ptr_interlock);
204 1.2 thorpej
205 1.2 thorpej return 0;
206 1.2 thorpej }
207 1.2 thorpej
208 1.2 thorpej
209 1.2 thorpej int
210 1.2 thorpej pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock)
211 1.2 thorpej {
212 1.2 thorpej pthread_t self;
213 1.2 thorpej #ifdef ERRORCHECK
214 1.2 thorpej if ((rwlock == NULL) || (rwlock->ptr_magic != _PT_RWLOCK_MAGIC))
215 1.2 thorpej return EINVAL;
216 1.2 thorpej #endif
217 1.2 thorpej self = pthread__self();
218 1.2 thorpej
219 1.20 ad pthread_spinlock(&rwlock->ptr_interlock);
220 1.2 thorpej /*
221 1.2 thorpej * Prefer writers to readers here; permit writers even if there are
222 1.2 thorpej * waiting readers.
223 1.2 thorpej */
224 1.2 thorpej if ((rwlock->ptr_nreaders > 0) || (rwlock->ptr_writer != NULL)) {
225 1.20 ad pthread_spinunlock(&rwlock->ptr_interlock);
226 1.2 thorpej return EBUSY;
227 1.2 thorpej }
228 1.2 thorpej
229 1.2 thorpej rwlock->ptr_writer = self;
230 1.20 ad pthread_spinunlock(&rwlock->ptr_interlock);
231 1.2 thorpej
232 1.2 thorpej return 0;
233 1.2 thorpej }
234 1.2 thorpej
235 1.2 thorpej
236 1.2 thorpej int
237 1.2 thorpej pthread_rwlock_timedrdlock(pthread_rwlock_t *rwlock,
238 1.2 thorpej const struct timespec *abs_timeout)
239 1.2 thorpej {
240 1.2 thorpej pthread_t self;
241 1.2 thorpej int retval;
242 1.12 chs
243 1.2 thorpej #ifdef ERRORCHECK
244 1.2 thorpej if ((rwlock == NULL) || (rwlock->ptr_magic != _PT_RWLOCK_MAGIC))
245 1.2 thorpej return EINVAL;
246 1.10 nathanw if (abs_timeout == NULL)
247 1.2 thorpej return EINVAL;
248 1.2 thorpej #endif
249 1.10 nathanw if ((abs_timeout->tv_nsec >= 1000000000) ||
250 1.10 nathanw (abs_timeout->tv_nsec < 0) ||
251 1.10 nathanw (abs_timeout->tv_sec < 0))
252 1.10 nathanw return EINVAL;
253 1.12 chs
254 1.2 thorpej self = pthread__self();
255 1.20 ad pthread_spinlock(&rwlock->ptr_interlock);
256 1.2 thorpej #ifdef ERRORCHECK
257 1.2 thorpej if (rwlock->ptr_writer == self) {
258 1.20 ad pthread_spinunlock(&rwlock->ptr_interlock);
259 1.2 thorpej return EDEADLK;
260 1.2 thorpej }
261 1.2 thorpej #endif
262 1.2 thorpej /*
263 1.2 thorpej * Don't get a readlock if there is a writer or if there are waiting
264 1.2 thorpej * writers; i.e. prefer writers to readers. This strategy is dictated
265 1.2 thorpej * by SUSv3.
266 1.2 thorpej */
267 1.2 thorpej retval = 0;
268 1.2 thorpej while ((retval == 0) && ((rwlock->ptr_writer != NULL) ||
269 1.2 thorpej (!PTQ_EMPTY(&rwlock->ptr_wblocked)))) {
270 1.17 ad PTQ_INSERT_TAIL(&rwlock->ptr_rblocked, self, pt_sleep);
271 1.17 ad self->pt_sleeponq = 1;
272 1.17 ad self->pt_sleepobj = &rwlock->ptr_rblocked;
273 1.20 ad pthread_spinunlock(&rwlock->ptr_interlock);
274 1.15 ad retval = pthread__park(self, &rwlock->ptr_interlock,
275 1.18 ad &rwlock->ptr_rblocked, abs_timeout, 0,
276 1.18 ad &rwlock->ptr_rblocked);
277 1.20 ad pthread_spinlock(&rwlock->ptr_interlock);
278 1.2 thorpej }
279 1.2 thorpej
280 1.11 nathanw /* One last chance to get the lock, in case it was released between
281 1.11 nathanw the alarm firing and when this thread got rescheduled, or in case
282 1.11 nathanw a signal handler kept it busy */
283 1.11 nathanw if ((rwlock->ptr_writer == NULL) &&
284 1.11 nathanw (PTQ_EMPTY(&rwlock->ptr_wblocked))) {
285 1.2 thorpej rwlock->ptr_nreaders++;
286 1.11 nathanw retval = 0;
287 1.11 nathanw }
288 1.20 ad pthread_spinunlock(&rwlock->ptr_interlock);
289 1.2 thorpej
290 1.2 thorpej return retval;
291 1.2 thorpej }
292 1.2 thorpej
293 1.2 thorpej
294 1.2 thorpej int
295 1.2 thorpej pthread_rwlock_timedwrlock(pthread_rwlock_t *rwlock,
296 1.2 thorpej const struct timespec *abs_timeout)
297 1.2 thorpej {
298 1.12 chs pthread_t self;
299 1.2 thorpej int retval;
300 1.12 chs extern int pthread__started;
301 1.12 chs
302 1.2 thorpej #ifdef ERRORCHECK
303 1.2 thorpej if ((rwlock == NULL) || (rwlock->ptr_magic != _PT_RWLOCK_MAGIC))
304 1.2 thorpej return EINVAL;
305 1.10 nathanw if (abs_timeout == NULL)
306 1.10 nathanw return EINVAL;
307 1.2 thorpej #endif
308 1.10 nathanw if ((abs_timeout->tv_nsec >= 1000000000) ||
309 1.10 nathanw (abs_timeout->tv_nsec < 0) ||
310 1.10 nathanw (abs_timeout->tv_sec < 0))
311 1.10 nathanw return EINVAL;
312 1.12 chs
313 1.2 thorpej self = pthread__self();
314 1.20 ad pthread_spinlock(&rwlock->ptr_interlock);
315 1.7 cl #ifdef ERRORCHECK
316 1.7 cl if (rwlock->ptr_writer == self) {
317 1.20 ad pthread_spinunlock(&rwlock->ptr_interlock);
318 1.7 cl return EDEADLK;
319 1.7 cl }
320 1.7 cl #endif
321 1.2 thorpej /*
322 1.2 thorpej * Prefer writers to readers here; permit writers even if there are
323 1.2 thorpej * waiting readers.
324 1.2 thorpej */
325 1.2 thorpej retval = 0;
326 1.2 thorpej while (retval == 0 &&
327 1.2 thorpej ((rwlock->ptr_nreaders > 0) || (rwlock->ptr_writer != NULL))) {
328 1.13 chs #ifdef ERRORCHECK
329 1.13 chs if (pthread__started == 0) {
330 1.20 ad pthread_spinunlock(&rwlock->ptr_interlock);
331 1.13 chs return EDEADLK;
332 1.13 chs }
333 1.13 chs #endif
334 1.17 ad PTQ_INSERT_TAIL(&rwlock->ptr_wblocked, self, pt_sleep);
335 1.17 ad self->pt_sleeponq = 1;
336 1.17 ad self->pt_sleepobj = &rwlock->ptr_wblocked;
337 1.20 ad pthread_spinunlock(&rwlock->ptr_interlock);
338 1.15 ad retval = pthread__park(self, &rwlock->ptr_interlock,
339 1.18 ad &rwlock->ptr_wblocked, abs_timeout, 0,
340 1.18 ad &rwlock->ptr_wblocked);
341 1.20 ad pthread_spinlock(&rwlock->ptr_interlock);
342 1.2 thorpej }
343 1.2 thorpej
344 1.11 nathanw if ((rwlock->ptr_nreaders == 0) && (rwlock->ptr_writer == NULL)) {
345 1.2 thorpej rwlock->ptr_writer = self;
346 1.11 nathanw retval = 0;
347 1.11 nathanw }
348 1.20 ad pthread_spinunlock(&rwlock->ptr_interlock);
349 1.2 thorpej
350 1.8 yamt return retval;
351 1.2 thorpej }
352 1.2 thorpej
353 1.2 thorpej
354 1.2 thorpej int
355 1.2 thorpej pthread_rwlock_unlock(pthread_rwlock_t *rwlock)
356 1.2 thorpej {
357 1.3 nathanw pthread_t self, writer;
358 1.2 thorpej #ifdef ERRORCHECK
359 1.2 thorpej if ((rwlock == NULL) || (rwlock->ptr_magic != _PT_RWLOCK_MAGIC))
360 1.2 thorpej return EINVAL;
361 1.2 thorpej #endif
362 1.2 thorpej writer = NULL;
363 1.2 thorpej self = pthread__self();
364 1.2 thorpej
365 1.20 ad pthread_spinlock(&rwlock->ptr_interlock);
366 1.2 thorpej if (rwlock->ptr_writer != NULL) {
367 1.2 thorpej /* Releasing a write lock. */
368 1.2 thorpej #ifdef ERRORCHECK
369 1.2 thorpej if (rwlock->ptr_writer != self) {
370 1.20 ad pthread_spinunlock(&rwlock->ptr_interlock);
371 1.2 thorpej return EPERM;
372 1.2 thorpej }
373 1.2 thorpej #endif
374 1.2 thorpej rwlock->ptr_writer = NULL;
375 1.2 thorpej writer = PTQ_FIRST(&rwlock->ptr_wblocked);
376 1.2 thorpej if (writer != NULL) {
377 1.2 thorpej PTQ_REMOVE(&rwlock->ptr_wblocked, writer, pt_sleep);
378 1.2 thorpej }
379 1.7 cl } else
380 1.7 cl #ifdef ERRORCHECK
381 1.7 cl if (rwlock->ptr_nreaders > 0)
382 1.7 cl #endif
383 1.7 cl {
384 1.2 thorpej /* Releasing a read lock. */
385 1.2 thorpej rwlock->ptr_nreaders--;
386 1.2 thorpej if (rwlock->ptr_nreaders == 0) {
387 1.2 thorpej writer = PTQ_FIRST(&rwlock->ptr_wblocked);
388 1.2 thorpej if (writer != NULL)
389 1.2 thorpej PTQ_REMOVE(&rwlock->ptr_wblocked, writer,
390 1.2 thorpej pt_sleep);
391 1.2 thorpej }
392 1.7 cl #ifdef ERRORCHECK
393 1.7 cl } else {
394 1.20 ad pthread_spinunlock(&rwlock->ptr_interlock);
395 1.7 cl return EPERM;
396 1.7 cl #endif
397 1.2 thorpej }
398 1.2 thorpej
399 1.14 ad if (writer != NULL)
400 1.17 ad pthread__unpark(self, &rwlock->ptr_interlock,
401 1.17 ad &rwlock->ptr_wblocked, writer);
402 1.14 ad else
403 1.17 ad pthread__unpark_all(self, &rwlock->ptr_interlock,
404 1.15 ad &rwlock->ptr_rblocked);
405 1.6 cl
406 1.2 thorpej return 0;
407 1.2 thorpej }
408 1.2 thorpej
409 1.2 thorpej
410 1.2 thorpej int
411 1.2 thorpej pthread_rwlockattr_init(pthread_rwlockattr_t *attr)
412 1.2 thorpej {
413 1.2 thorpej #ifdef ERRORCHECK
414 1.2 thorpej if (attr == NULL)
415 1.2 thorpej return EINVAL;
416 1.2 thorpej #endif
417 1.2 thorpej attr->ptra_magic = _PT_RWLOCKATTR_MAGIC;
418 1.2 thorpej
419 1.2 thorpej return 0;
420 1.2 thorpej }
421 1.2 thorpej
422 1.2 thorpej
423 1.2 thorpej int
424 1.2 thorpej pthread_rwlockattr_destroy(pthread_rwlockattr_t *attr)
425 1.2 thorpej {
426 1.2 thorpej #ifdef ERRORCHECK
427 1.2 thorpej if ((attr == NULL) ||
428 1.2 thorpej (attr->ptra_magic != _PT_RWLOCKATTR_MAGIC))
429 1.2 thorpej return EINVAL;
430 1.2 thorpej #endif
431 1.2 thorpej attr->ptra_magic = _PT_RWLOCKATTR_DEAD;
432 1.2 thorpej
433 1.2 thorpej return 0;
434 1.2 thorpej }
435 1.21 ad
436 1.21 ad #endif /* !PTHREAD__HAVE_ATOMIC */
437