pthread_rwlock.c revision 1.17 1 1.17 ad /* $NetBSD: pthread_rwlock.c,v 1.17 2007/03/05 23:56:18 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.17 ad __RCSID("$NetBSD: pthread_rwlock.c,v 1.17 2007/03/05 23:56:18 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.2 thorpej pthread_spinlock(self, &rwlock->ptr_interlock);
104 1.2 thorpej #ifdef ERRORCHECK
105 1.2 thorpej if (rwlock->ptr_writer == self) {
106 1.2 thorpej pthread_spinunlock(self, &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.15 ad (void)pthread__park(self, &rwlock->ptr_interlock,
121 1.17 ad &rwlock->ptr_rblocked, NULL, 0);
122 1.2 thorpej }
123 1.2 thorpej
124 1.2 thorpej rwlock->ptr_nreaders++;
125 1.2 thorpej pthread_spinunlock(self, &rwlock->ptr_interlock);
126 1.2 thorpej
127 1.2 thorpej return 0;
128 1.2 thorpej }
129 1.2 thorpej
130 1.2 thorpej
131 1.2 thorpej int
132 1.2 thorpej pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock)
133 1.2 thorpej {
134 1.2 thorpej pthread_t self;
135 1.2 thorpej #ifdef ERRORCHECK
136 1.2 thorpej if ((rwlock == NULL) || (rwlock->ptr_magic != _PT_RWLOCK_MAGIC))
137 1.2 thorpej return EINVAL;
138 1.2 thorpej #endif
139 1.2 thorpej self = pthread__self();
140 1.2 thorpej
141 1.2 thorpej pthread_spinlock(self, &rwlock->ptr_interlock);
142 1.2 thorpej /*
143 1.2 thorpej * Don't get a readlock if there is a writer or if there are waiting
144 1.2 thorpej * writers; i.e. prefer writers to readers. This strategy is dictated
145 1.2 thorpej * by SUSv3.
146 1.2 thorpej */
147 1.2 thorpej if ((rwlock->ptr_writer != NULL) ||
148 1.2 thorpej (!PTQ_EMPTY(&rwlock->ptr_wblocked))) {
149 1.2 thorpej pthread_spinunlock(self, &rwlock->ptr_interlock);
150 1.2 thorpej return EBUSY;
151 1.2 thorpej }
152 1.2 thorpej
153 1.2 thorpej rwlock->ptr_nreaders++;
154 1.2 thorpej pthread_spinunlock(self, &rwlock->ptr_interlock);
155 1.2 thorpej
156 1.2 thorpej return 0;
157 1.2 thorpej }
158 1.2 thorpej
159 1.2 thorpej
160 1.2 thorpej int
161 1.2 thorpej pthread_rwlock_wrlock(pthread_rwlock_t *rwlock)
162 1.2 thorpej {
163 1.2 thorpej pthread_t self;
164 1.13 chs extern int pthread__started;
165 1.13 chs
166 1.2 thorpej #ifdef ERRORCHECK
167 1.2 thorpej if ((rwlock == NULL) || (rwlock->ptr_magic != _PT_RWLOCK_MAGIC))
168 1.2 thorpej return EINVAL;
169 1.2 thorpej #endif
170 1.2 thorpej self = pthread__self();
171 1.2 thorpej
172 1.2 thorpej pthread_spinlock(self, &rwlock->ptr_interlock);
173 1.7 cl #ifdef ERRORCHECK
174 1.7 cl if (rwlock->ptr_writer == self) {
175 1.7 cl pthread_spinunlock(self, &rwlock->ptr_interlock);
176 1.7 cl return EDEADLK;
177 1.7 cl }
178 1.7 cl #endif
179 1.2 thorpej /*
180 1.2 thorpej * Prefer writers to readers here; permit writers even if there are
181 1.2 thorpej * waiting readers.
182 1.2 thorpej */
183 1.2 thorpej while ((rwlock->ptr_nreaders > 0) || (rwlock->ptr_writer != NULL)) {
184 1.13 chs #ifdef ERRORCHECK
185 1.13 chs if (pthread__started == 0) {
186 1.13 chs pthread_spinunlock(self, &rwlock->ptr_interlock);
187 1.13 chs return EDEADLK;
188 1.13 chs }
189 1.13 chs #endif
190 1.17 ad PTQ_INSERT_TAIL(&rwlock->ptr_wblocked, self, pt_sleep);
191 1.17 ad self->pt_sleeponq = 1;
192 1.17 ad self->pt_sleepobj = &rwlock->ptr_wblocked;
193 1.15 ad (void)pthread__park(self, &rwlock->ptr_interlock,
194 1.17 ad &rwlock->ptr_wblocked, NULL, 0);
195 1.2 thorpej }
196 1.2 thorpej
197 1.2 thorpej rwlock->ptr_writer = self;
198 1.2 thorpej pthread_spinunlock(self, &rwlock->ptr_interlock);
199 1.2 thorpej
200 1.2 thorpej return 0;
201 1.2 thorpej }
202 1.2 thorpej
203 1.2 thorpej
204 1.2 thorpej int
205 1.2 thorpej pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock)
206 1.2 thorpej {
207 1.2 thorpej pthread_t self;
208 1.2 thorpej #ifdef ERRORCHECK
209 1.2 thorpej if ((rwlock == NULL) || (rwlock->ptr_magic != _PT_RWLOCK_MAGIC))
210 1.2 thorpej return EINVAL;
211 1.2 thorpej #endif
212 1.2 thorpej self = pthread__self();
213 1.2 thorpej
214 1.2 thorpej pthread_spinlock(self, &rwlock->ptr_interlock);
215 1.2 thorpej /*
216 1.2 thorpej * Prefer writers to readers here; permit writers even if there are
217 1.2 thorpej * waiting readers.
218 1.2 thorpej */
219 1.2 thorpej if ((rwlock->ptr_nreaders > 0) || (rwlock->ptr_writer != NULL)) {
220 1.2 thorpej pthread_spinunlock(self, &rwlock->ptr_interlock);
221 1.2 thorpej return EBUSY;
222 1.2 thorpej }
223 1.2 thorpej
224 1.2 thorpej rwlock->ptr_writer = self;
225 1.2 thorpej pthread_spinunlock(self, &rwlock->ptr_interlock);
226 1.2 thorpej
227 1.2 thorpej return 0;
228 1.2 thorpej }
229 1.2 thorpej
230 1.2 thorpej
231 1.2 thorpej struct pthread_rwlock__waitarg {
232 1.2 thorpej pthread_t ptw_thread;
233 1.2 thorpej pthread_rwlock_t *ptw_rwlock;
234 1.2 thorpej struct pthread_queue_t *ptw_queue;
235 1.2 thorpej };
236 1.2 thorpej
237 1.2 thorpej int
238 1.2 thorpej pthread_rwlock_timedrdlock(pthread_rwlock_t *rwlock,
239 1.2 thorpej const struct timespec *abs_timeout)
240 1.2 thorpej {
241 1.2 thorpej pthread_t self;
242 1.2 thorpej int retval;
243 1.12 chs
244 1.2 thorpej #ifdef ERRORCHECK
245 1.2 thorpej if ((rwlock == NULL) || (rwlock->ptr_magic != _PT_RWLOCK_MAGIC))
246 1.2 thorpej return EINVAL;
247 1.10 nathanw if (abs_timeout == NULL)
248 1.2 thorpej return EINVAL;
249 1.2 thorpej #endif
250 1.10 nathanw if ((abs_timeout->tv_nsec >= 1000000000) ||
251 1.10 nathanw (abs_timeout->tv_nsec < 0) ||
252 1.10 nathanw (abs_timeout->tv_sec < 0))
253 1.10 nathanw return EINVAL;
254 1.12 chs
255 1.2 thorpej self = pthread__self();
256 1.2 thorpej pthread_spinlock(self, &rwlock->ptr_interlock);
257 1.2 thorpej #ifdef ERRORCHECK
258 1.2 thorpej if (rwlock->ptr_writer == self) {
259 1.9 yamt pthread_spinunlock(self, &rwlock->ptr_interlock);
260 1.2 thorpej return EDEADLK;
261 1.2 thorpej }
262 1.2 thorpej #endif
263 1.2 thorpej /*
264 1.2 thorpej * Don't get a readlock if there is a writer or if there are waiting
265 1.2 thorpej * writers; i.e. prefer writers to readers. This strategy is dictated
266 1.2 thorpej * by SUSv3.
267 1.2 thorpej */
268 1.2 thorpej retval = 0;
269 1.2 thorpej while ((retval == 0) && ((rwlock->ptr_writer != NULL) ||
270 1.2 thorpej (!PTQ_EMPTY(&rwlock->ptr_wblocked)))) {
271 1.17 ad PTQ_INSERT_TAIL(&rwlock->ptr_rblocked, self, pt_sleep);
272 1.17 ad self->pt_sleeponq = 1;
273 1.17 ad self->pt_sleepobj = &rwlock->ptr_rblocked;
274 1.15 ad retval = pthread__park(self, &rwlock->ptr_interlock,
275 1.17 ad &rwlock->ptr_rblocked, abs_timeout, 0);
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.2 thorpej pthread_spinunlock(self, &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.2 thorpej pthread_spinlock(self, &rwlock->ptr_interlock);
313 1.7 cl #ifdef ERRORCHECK
314 1.7 cl if (rwlock->ptr_writer == self) {
315 1.9 yamt pthread_spinunlock(self, &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.13 chs pthread_spinunlock(self, &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.15 ad retval = pthread__park(self, &rwlock->ptr_interlock,
336 1.17 ad &rwlock->ptr_wblocked, abs_timeout, 0);
337 1.2 thorpej }
338 1.2 thorpej
339 1.11 nathanw if ((rwlock->ptr_nreaders == 0) && (rwlock->ptr_writer == NULL)) {
340 1.2 thorpej rwlock->ptr_writer = self;
341 1.11 nathanw retval = 0;
342 1.11 nathanw }
343 1.2 thorpej pthread_spinunlock(self, &rwlock->ptr_interlock);
344 1.2 thorpej
345 1.8 yamt return retval;
346 1.2 thorpej }
347 1.2 thorpej
348 1.2 thorpej
349 1.2 thorpej int
350 1.2 thorpej pthread_rwlock_unlock(pthread_rwlock_t *rwlock)
351 1.2 thorpej {
352 1.3 nathanw pthread_t self, writer;
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.2 thorpej #endif
357 1.2 thorpej writer = NULL;
358 1.2 thorpej self = pthread__self();
359 1.2 thorpej
360 1.2 thorpej pthread_spinlock(self, &rwlock->ptr_interlock);
361 1.2 thorpej if (rwlock->ptr_writer != NULL) {
362 1.2 thorpej /* Releasing a write lock. */
363 1.2 thorpej #ifdef ERRORCHECK
364 1.2 thorpej if (rwlock->ptr_writer != self) {
365 1.2 thorpej pthread_spinunlock(self, &rwlock->ptr_interlock);
366 1.2 thorpej return EPERM;
367 1.2 thorpej }
368 1.2 thorpej #endif
369 1.2 thorpej rwlock->ptr_writer = NULL;
370 1.2 thorpej writer = PTQ_FIRST(&rwlock->ptr_wblocked);
371 1.2 thorpej if (writer != NULL) {
372 1.2 thorpej PTQ_REMOVE(&rwlock->ptr_wblocked, writer, pt_sleep);
373 1.2 thorpej }
374 1.7 cl } else
375 1.7 cl #ifdef ERRORCHECK
376 1.7 cl if (rwlock->ptr_nreaders > 0)
377 1.7 cl #endif
378 1.7 cl {
379 1.2 thorpej /* Releasing a read lock. */
380 1.2 thorpej rwlock->ptr_nreaders--;
381 1.2 thorpej if (rwlock->ptr_nreaders == 0) {
382 1.2 thorpej writer = PTQ_FIRST(&rwlock->ptr_wblocked);
383 1.2 thorpej if (writer != NULL)
384 1.2 thorpej PTQ_REMOVE(&rwlock->ptr_wblocked, writer,
385 1.2 thorpej pt_sleep);
386 1.2 thorpej }
387 1.7 cl #ifdef ERRORCHECK
388 1.7 cl } else {
389 1.7 cl pthread_spinunlock(self, &rwlock->ptr_interlock);
390 1.7 cl return EPERM;
391 1.7 cl #endif
392 1.2 thorpej }
393 1.2 thorpej
394 1.14 ad if (writer != NULL)
395 1.17 ad pthread__unpark(self, &rwlock->ptr_interlock,
396 1.17 ad &rwlock->ptr_wblocked, writer);
397 1.14 ad else
398 1.17 ad pthread__unpark_all(self, &rwlock->ptr_interlock,
399 1.15 ad &rwlock->ptr_rblocked);
400 1.6 cl
401 1.2 thorpej return 0;
402 1.2 thorpej }
403 1.2 thorpej
404 1.2 thorpej
405 1.2 thorpej int
406 1.2 thorpej pthread_rwlockattr_init(pthread_rwlockattr_t *attr)
407 1.2 thorpej {
408 1.2 thorpej #ifdef ERRORCHECK
409 1.2 thorpej if (attr == NULL)
410 1.2 thorpej return EINVAL;
411 1.2 thorpej #endif
412 1.2 thorpej attr->ptra_magic = _PT_RWLOCKATTR_MAGIC;
413 1.2 thorpej
414 1.2 thorpej return 0;
415 1.2 thorpej }
416 1.2 thorpej
417 1.2 thorpej
418 1.2 thorpej int
419 1.2 thorpej pthread_rwlockattr_destroy(pthread_rwlockattr_t *attr)
420 1.2 thorpej {
421 1.2 thorpej #ifdef ERRORCHECK
422 1.2 thorpej if ((attr == NULL) ||
423 1.2 thorpej (attr->ptra_magic != _PT_RWLOCKATTR_MAGIC))
424 1.2 thorpej return EINVAL;
425 1.2 thorpej #endif
426 1.2 thorpej attr->ptra_magic = _PT_RWLOCKATTR_DEAD;
427 1.2 thorpej
428 1.2 thorpej return 0;
429 1.2 thorpej }
430