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