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