]> git.saurik.com Git - apple/libc.git/blame - pthreads/pthread_rwlock.c
Libc-498.1.7.tar.gz
[apple/libc.git] / pthreads / pthread_rwlock.c
CommitLineData
9385eb3d 1/*
b5d655f7 2 * Copyright (c) 2000-2003, 2007, 2008 Apple Inc. All rights reserved.
9385eb3d
A
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
9385eb3d
A
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
5b2abdfb
A
23/*-
24 * Copyright (c) 1998 Alex Nash
25 * All rights reserved.
26 *
27 * Redistribution and use in source and binary forms, with or without
28 * modification, are permitted provided that the following conditions
29 * are met:
30 * 1. Redistributions of source code must retain the above copyright
31 * notice, this list of conditions and the following disclaimer.
32 * 2. Redistributions in binary form must reproduce the above copyright
33 * notice, this list of conditions and the following disclaimer in the
34 * documentation and/or other materials provided with the distribution.
35 *
36 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
37 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
38 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
39 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
40 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
41 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
42 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
43 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
44 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
45 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
46 * SUCH DAMAGE.
47 *
48 * $FreeBSD: src/lib/libc_r/uthread/uthread_rwlock.c,v 1.6 2001/04/10 04:19:20 deischen Exp $
49 */
50
51/*
52 * POSIX Pthread Library
53 * -- Read Write Lock support
54 * 4/24/02: A. Ramesh
55 * Ported from FreeBSD
56 */
57
58#include "pthread_internals.h"
224c7076
A
59extern int __unix_conforming;
60
b5d655f7 61#ifdef PLOCKSTAT
224c7076 62#include "plockstat.h"
b5d655f7
A
63#else /* !PLOCKSTAT */
64#define PLOCKSTAT_RW_ERROR(x, y, z)
65#define PLOCKSTAT_RW_BLOCK(x, y)
66#define PLOCKSTAT_RW_BLOCKED(x, y, z)
67#define PLOCKSTAT_RW_ACQUIRE(x, y)
68#define PLOCKSTAT_RW_RELEASE(x, y)
69#endif /* PLOCKSTAT */
70
224c7076
A
71#define READ_LOCK_PLOCKSTAT 0
72#define WRITE_LOCK_PLOCKSTAT 1
73
74#define BLOCK_FAIL_PLOCKSTAT 0
75#define BLOCK_SUCCESS_PLOCKSTAT 1
5b2abdfb
A
76
77/* maximum number of times a read lock may be obtained */
224c7076
A
78#define MAX_READ_LOCKS (INT_MAX - 1)
79
80
81#ifndef BUILDING_VARIANT /* [ */
82
83
84int
85pthread_rwlockattr_init(pthread_rwlockattr_t *attr)
86{
87 attr->sig = _PTHREAD_RWLOCK_ATTR_SIG;
88 attr->pshared = _PTHREAD_DEFAULT_PSHARED;
89 return (0);
90}
91
92int
93pthread_rwlockattr_destroy(pthread_rwlockattr_t *attr)
94{
95 attr->sig = _PTHREAD_NO_SIG; /* Uninitialized */
96 attr->pshared = 0;
97 return (0);
98}
99
100int
101pthread_rwlockattr_getpshared(const pthread_rwlockattr_t *attr,
102 int *pshared)
103{
104 if (attr->sig == _PTHREAD_RWLOCK_ATTR_SIG)
105 {
106 *pshared = (int)attr->pshared;
107 return (0);
108 } else
109 {
110 return (EINVAL); /* Not an initialized 'attribute' structure */
111 }
112}
113
114/* Temp: untill pshared is fixed right */
115#ifdef PR_5243343
116/* 5243343 - temporary hack to detect if we are running the conformance test */
117extern int PR_5243343_flag;
118#endif /* PR_5243343 */
119
120int
121pthread_rwlockattr_setpshared(pthread_rwlockattr_t * attr, int pshared)
122{
123 if (attr->sig == _PTHREAD_RWLOCK_ATTR_SIG)
124 {
125#if __DARWIN_UNIX03
126#ifdef PR_5243343
127 if (( pshared == PTHREAD_PROCESS_PRIVATE) || (pshared == PTHREAD_PROCESS_SHARED && PR_5243343_flag))
128#else /* !PR_5243343 */
129 if (( pshared == PTHREAD_PROCESS_PRIVATE) || (pshared == PTHREAD_PROCESS_SHARED))
130#endif /* PR_5243343 */
131#else /* __DARWIN_UNIX03 */
132 if ( pshared == PTHREAD_PROCESS_PRIVATE)
133#endif /* __DARWIN_UNIX03 */
134 {
135 attr->pshared = pshared ;
136 return (0);
137 } else
138 {
139 return (EINVAL); /* Invalid parameter */
140 }
141 } else
142 {
143 return (EINVAL); /* Not an initialized 'attribute' structure */
144 }
145
146}
147
148#endif /* !BUILDING_VARIANT ] */
5b2abdfb
A
149
150int
151pthread_rwlock_destroy(pthread_rwlock_t *rwlock)
152{
224c7076 153 int ret;
5b2abdfb
A
154
155 if (rwlock->sig != _PTHREAD_RWLOCK_SIG) {
156 return(EINVAL);
157 } else {
224c7076
A
158#if __DARWIN_UNIX03
159 /* grab the monitor lock */
160 if ((ret = pthread_mutex_lock(&rwlock->lock)) != 0)
161 return(ret);
162
163 if (rwlock->state != 0) {
164 pthread_mutex_unlock(&rwlock->lock);
165 return(EBUSY);
166 }
167 pthread_mutex_unlock(&rwlock->lock);
168#endif /* __DARWIN_UNIX03 */
169
5b2abdfb
A
170 pthread_mutex_destroy(&rwlock->lock);
171 pthread_cond_destroy(&rwlock->read_signal);
172 pthread_cond_destroy(&rwlock->write_signal);
173 rwlock->sig = _PTHREAD_NO_SIG;
224c7076 174 return(0);
5b2abdfb
A
175 }
176}
177
178int
179pthread_rwlock_init(pthread_rwlock_t *rwlock, const pthread_rwlockattr_t *attr)
180{
181 int ret;
224c7076
A
182#if __DARWIN_UNIX03
183 if (attr && (attr->sig != _PTHREAD_RWLOCK_ATTR_SIG)) {
184 return(EINVAL);
185 }
186 /* if already inited check whether it is in use, then return EBUSY */
187 if ((rwlock->sig == _PTHREAD_RWLOCK_SIG) && (rwlock->state !=0 )) {
188 return(EBUSY);
189 }
190#endif /* __DARWIN_UNIX03 */
5b2abdfb
A
191
192 /* initialize the lock */
193 if ((ret = pthread_mutex_init(&rwlock->lock, NULL)) != 0)
194 return(ret);
195 else {
196 /* initialize the read condition signal */
197 ret = pthread_cond_init(&rwlock->read_signal, NULL);
198
199 if (ret != 0) {
200 pthread_mutex_destroy(&rwlock->lock);
201 return(ret);
202 } else {
203 /* initialize the write condition signal */
204 ret = pthread_cond_init(&rwlock->write_signal, NULL);
205
206 if (ret != 0) {
207 pthread_cond_destroy(&rwlock->read_signal);
208 pthread_mutex_destroy(&rwlock->lock);
209 return(ret);
210 } else {
211 /* success */
212 rwlock->state = 0;
224c7076 213 rwlock->owner = (pthread_t)0;
5b2abdfb 214 rwlock->blocked_writers = 0;
224c7076
A
215 if (attr)
216 rwlock->pshared = attr->pshared;
217 else
218 rwlock->pshared = _PTHREAD_DEFAULT_PSHARED;
219
5b2abdfb 220 rwlock->sig = _PTHREAD_RWLOCK_SIG;
224c7076 221 return(0);
5b2abdfb
A
222 }
223 }
224 }
225}
226
227int
228pthread_rwlock_rdlock(pthread_rwlock_t *rwlock)
229{
230 int ret;
224c7076
A
231#if __DARWIN_UNIX03
232 pthread_t self = pthread_self();
233#endif
5b2abdfb
A
234
235 if (rwlock->sig == _PTHREAD_RWLOCK_SIG_init) {
236 if ((ret = pthread_rwlock_init(rwlock, NULL)) != 0) {
224c7076 237 PLOCKSTAT_RW_ERROR(rwlock, READ_LOCK_PLOCKSTAT, ret);
5b2abdfb
A
238 return(ret);
239 }
240 }
241
224c7076
A
242 if (rwlock->sig != _PTHREAD_RWLOCK_SIG) {
243 PLOCKSTAT_RW_ERROR(rwlock, READ_LOCK_PLOCKSTAT, EINVAL);
5b2abdfb 244 return(EINVAL);
224c7076 245 }
5b2abdfb 246 /* grab the monitor lock */
224c7076
A
247 if ((ret = pthread_mutex_lock(&rwlock->lock)) != 0) {
248 PLOCKSTAT_RW_ERROR(rwlock, READ_LOCK_PLOCKSTAT, ret);
5b2abdfb 249 return(ret);
224c7076
A
250 }
251
252#if __DARWIN_UNIX03
253 if ((rwlock->state < 0) && (rwlock->owner == self)) {
254 pthread_mutex_unlock(&rwlock->lock);
255 PLOCKSTAT_RW_ERROR(rwlock, READ_LOCK_PLOCKSTAT, EDEADLK);
256 return(EDEADLK);
257 }
258#endif /* __DARWIN_UNIX03 */
259
260#if __DARWIN_UNIX03
261 while (rwlock->blocked_writers || ((rwlock->state < 0) && (rwlock->owner != self)))
262#else /* __DARWIN_UNIX03 */
263 while (rwlock->blocked_writers || rwlock->state < 0)
5b2abdfb 264
224c7076
A
265#endif /* __DARWIN_UNIX03 */
266 {
5b2abdfb 267 /* give writers priority over readers */
224c7076 268 PLOCKSTAT_RW_BLOCK(rwlock, READ_LOCK_PLOCKSTAT);
5b2abdfb
A
269 ret = pthread_cond_wait(&rwlock->read_signal, &rwlock->lock);
270
271 if (ret != 0) {
272 /* can't do a whole lot if this fails */
273 pthread_mutex_unlock(&rwlock->lock);
224c7076
A
274 PLOCKSTAT_RW_BLOCKED(rwlock, READ_LOCK_PLOCKSTAT, BLOCK_FAIL_PLOCKSTAT);
275 PLOCKSTAT_RW_ERROR(rwlock, READ_LOCK_PLOCKSTAT, ret);
5b2abdfb
A
276 return(ret);
277 }
224c7076
A
278
279 PLOCKSTAT_RW_BLOCKED(rwlock, READ_LOCK_PLOCKSTAT, BLOCK_SUCCESS_PLOCKSTAT);
5b2abdfb
A
280 }
281
282 /* check lock count */
224c7076 283 if (rwlock->state == MAX_READ_LOCKS) {
5b2abdfb 284 ret = EAGAIN;
224c7076
A
285 PLOCKSTAT_RW_ERROR(rwlock, READ_LOCK_PLOCKSTAT, ret);
286 }
287 else {
5b2abdfb 288 ++rwlock->state; /* indicate we are locked for reading */
224c7076
A
289 PLOCKSTAT_RW_ACQUIRE(rwlock, READ_LOCK_PLOCKSTAT);
290 }
5b2abdfb
A
291
292 /*
293 * Something is really wrong if this call fails. Returning
294 * error won't do because we've already obtained the read
295 * lock. Decrementing 'state' is no good because we probably
296 * don't have the monitor lock.
297 */
298 pthread_mutex_unlock(&rwlock->lock);
299
300 return(ret);
301}
302
303int
304pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock)
305{
306 int ret;
224c7076
A
307#if __DARWIN_UNIX03
308 pthread_t self = pthread_self();
309#endif
5b2abdfb
A
310
311 /* check for static initialization */
312 if (rwlock->sig == _PTHREAD_RWLOCK_SIG_init) {
313 if ((ret = pthread_rwlock_init(rwlock, NULL)) != 0) {
224c7076 314 PLOCKSTAT_RW_ERROR(rwlock, READ_LOCK_PLOCKSTAT, ret);
5b2abdfb
A
315 return(ret);
316 }
317 }
318
224c7076
A
319 if (rwlock->sig != _PTHREAD_RWLOCK_SIG) {
320 PLOCKSTAT_RW_ERROR(rwlock, READ_LOCK_PLOCKSTAT, EINVAL);
5b2abdfb 321 return(EINVAL);
224c7076 322 }
5b2abdfb 323 /* grab the monitor lock */
224c7076
A
324 if ((ret = pthread_mutex_lock(&rwlock->lock)) != 0) {
325 PLOCKSTAT_RW_ERROR(rwlock, READ_LOCK_PLOCKSTAT, ret);
5b2abdfb 326 return(ret);
224c7076 327 }
5b2abdfb
A
328
329 /* give writers priority over readers */
224c7076 330 if (rwlock->blocked_writers || rwlock->state < 0) {
5b2abdfb 331 ret = EBUSY;
224c7076
A
332 PLOCKSTAT_RW_ERROR(rwlock, READ_LOCK_PLOCKSTAT, ret);
333 }
334 else if (rwlock->state == MAX_READ_LOCKS) {
5b2abdfb 335 ret = EAGAIN; /* too many read locks acquired */
224c7076
A
336 PLOCKSTAT_RW_ERROR(rwlock, READ_LOCK_PLOCKSTAT, ret);
337 }
338 else {
5b2abdfb 339 ++rwlock->state; /* indicate we are locked for reading */
224c7076
A
340 PLOCKSTAT_RW_ACQUIRE(rwlock, READ_LOCK_PLOCKSTAT);
341 }
5b2abdfb
A
342
343 /* see the comment on this in pthread_rwlock_rdlock */
344 pthread_mutex_unlock(&rwlock->lock);
345
346 return(ret);
347}
348
349int
350pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock)
351{
352 int ret;
224c7076
A
353#if __DARWIN_UNIX03
354 pthread_t self = pthread_self();
355#endif /* __DARWIN_UNIX03 */
5b2abdfb
A
356
357 /* check for static initialization */
358 if (rwlock->sig == _PTHREAD_RWLOCK_SIG_init) {
359 if ((ret = pthread_rwlock_init(rwlock, NULL)) != 0) {
224c7076 360 PLOCKSTAT_RW_ERROR(rwlock, WRITE_LOCK_PLOCKSTAT, ret);
5b2abdfb
A
361 return(ret);
362 }
363 }
364
224c7076
A
365 if (rwlock->sig != _PTHREAD_RWLOCK_SIG) {
366 PLOCKSTAT_RW_ERROR(rwlock, WRITE_LOCK_PLOCKSTAT, EINVAL);
5b2abdfb 367 return(EINVAL);
224c7076 368 }
5b2abdfb 369 /* grab the monitor lock */
224c7076
A
370 if ((ret = pthread_mutex_lock(&rwlock->lock)) != 0) {
371 PLOCKSTAT_RW_ERROR(rwlock, WRITE_LOCK_PLOCKSTAT, ret);
5b2abdfb 372 return(ret);
224c7076
A
373 }
374
5b2abdfb 375
224c7076 376 if (rwlock->state != 0) {
5b2abdfb 377 ret = EBUSY;
224c7076
A
378 PLOCKSTAT_RW_ERROR(rwlock, WRITE_LOCK_PLOCKSTAT, ret);
379 }
380 else {
5b2abdfb
A
381 /* indicate we are locked for writing */
382 rwlock->state = -1;
224c7076
A
383#if __DARWIN_UNIX03
384 rwlock->owner = self;
385#endif /* __DARWIN_UNIX03 */
386 PLOCKSTAT_RW_ACQUIRE(rwlock, WRITE_LOCK_PLOCKSTAT);
387 }
5b2abdfb
A
388
389 /* see the comment on this in pthread_rwlock_rdlock */
390 pthread_mutex_unlock(&rwlock->lock);
391
392 return(ret);
393}
394
395int
396pthread_rwlock_unlock(pthread_rwlock_t *rwlock)
397{
398 int ret;
224c7076
A
399 int writer = (rwlock < 0) ? 1:0;
400#if __DARWIN_UNIX03
401 pthread_t self = pthread_self();
402#endif /* __DARWIN_UNIX03 */
5b2abdfb 403
224c7076
A
404 if (rwlock->sig != _PTHREAD_RWLOCK_SIG) {
405 PLOCKSTAT_RW_ERROR(rwlock, writer, EINVAL);
5b2abdfb 406 return(EINVAL);
224c7076 407 }
5b2abdfb 408 /* grab the monitor lock */
224c7076
A
409 if ((ret = pthread_mutex_lock(&rwlock->lock)) != 0) {
410 PLOCKSTAT_RW_ERROR(rwlock, writer, ret);
5b2abdfb 411 return(ret);
224c7076 412 }
5b2abdfb
A
413
414 if (rwlock->state > 0) {
415 if (--rwlock->state == 0 && rwlock->blocked_writers)
416 ret = pthread_cond_signal(&rwlock->write_signal);
417 } else if (rwlock->state < 0) {
418 rwlock->state = 0;
224c7076
A
419#if __DARWIN_UNIX03
420 rwlock->owner = (pthread_t)0;
421#endif /* __DARWIN_UNIX03 */
5b2abdfb
A
422
423 if (rwlock->blocked_writers)
424 ret = pthread_cond_signal(&rwlock->write_signal);
425 else
426 ret = pthread_cond_broadcast(&rwlock->read_signal);
427 } else
428 ret = EINVAL;
429
224c7076
A
430 if (ret == 0) {
431 PLOCKSTAT_RW_RELEASE(rwlock, writer);
432 } else {
433 PLOCKSTAT_RW_ERROR(rwlock, writer, ret);
434 }
435
5b2abdfb
A
436 /* see the comment on this in pthread_rwlock_rdlock */
437 pthread_mutex_unlock(&rwlock->lock);
438
439 return(ret);
440}
441
442int
443pthread_rwlock_wrlock(pthread_rwlock_t *rwlock)
444{
445 int ret;
224c7076
A
446#if __DARWIN_UNIX03
447 pthread_t self = pthread_self();
448#endif /* __DARWIN_UNIX03 */
5b2abdfb
A
449
450 /* check for static initialization */
451 if (rwlock->sig == _PTHREAD_RWLOCK_SIG_init) {
452 if ((ret = pthread_rwlock_init(rwlock, NULL)) != 0) {
224c7076 453 PLOCKSTAT_RW_ERROR(rwlock, WRITE_LOCK_PLOCKSTAT, ret);
5b2abdfb
A
454 return(ret);
455 }
456 }
457
224c7076
A
458 if (rwlock->sig != _PTHREAD_RWLOCK_SIG) {
459 PLOCKSTAT_RW_ERROR(rwlock, WRITE_LOCK_PLOCKSTAT, EINVAL);
5b2abdfb 460 return(EINVAL);
224c7076 461 }
5b2abdfb 462 /* grab the monitor lock */
224c7076
A
463 if ((ret = pthread_mutex_lock(&rwlock->lock)) != 0) {
464 PLOCKSTAT_RW_ERROR(rwlock, WRITE_LOCK_PLOCKSTAT, ret);
5b2abdfb 465 return(ret);
224c7076 466 }
5b2abdfb 467
224c7076
A
468#if __DARWIN_UNIX03
469 if ((rwlock->state < 0) && (rwlock->owner == self)) {
470 pthread_mutex_unlock(&rwlock->lock);
471 PLOCKSTAT_RW_ERROR(rwlock, WRITE_LOCK_PLOCKSTAT, EDEADLK);
472 return(EDEADLK);
473 }
474#endif /* __DARWIN_UNIX03 */
5b2abdfb
A
475 while (rwlock->state != 0) {
476 ++rwlock->blocked_writers;
477
224c7076 478 PLOCKSTAT_RW_BLOCK(rwlock, WRITE_LOCK_PLOCKSTAT);
5b2abdfb
A
479 ret = pthread_cond_wait(&rwlock->write_signal, &rwlock->lock);
480
481 if (ret != 0) {
482 --rwlock->blocked_writers;
483 pthread_mutex_unlock(&rwlock->lock);
224c7076
A
484 PLOCKSTAT_RW_BLOCKED(rwlock, WRITE_LOCK_PLOCKSTAT, BLOCK_FAIL_PLOCKSTAT);
485 PLOCKSTAT_RW_ERROR(rwlock, WRITE_LOCK_PLOCKSTAT, ret);
5b2abdfb
A
486 return(ret);
487 }
488
224c7076
A
489 PLOCKSTAT_RW_BLOCKED(rwlock, WRITE_LOCK_PLOCKSTAT, BLOCK_SUCCESS_PLOCKSTAT);
490
5b2abdfb
A
491 --rwlock->blocked_writers;
492 }
493
494 /* indicate we are locked for writing */
495 rwlock->state = -1;
224c7076
A
496#if __DARWIN_UNIX03
497 rwlock->owner = self;
498#endif /* __DARWIN_UNIX03 */
499 PLOCKSTAT_RW_ACQUIRE(rwlock, WRITE_LOCK_PLOCKSTAT);
5b2abdfb
A
500
501 /* see the comment on this in pthread_rwlock_rdlock */
502 pthread_mutex_unlock(&rwlock->lock);
503
504 return(ret);
505}
506
5b2abdfb 507