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