]> git.saurik.com Git - apple/libc.git/blame - pthreads/pthread_rwlock.c
Libc-498.tar.gz
[apple/libc.git] / pthreads / pthread_rwlock.c
CommitLineData
9385eb3d 1/*
224c7076 2 * Copyright (c) 2000-2003, 2007 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
61#include "plockstat.h"
62#define READ_LOCK_PLOCKSTAT 0
63#define WRITE_LOCK_PLOCKSTAT 1
64
65#define BLOCK_FAIL_PLOCKSTAT 0
66#define BLOCK_SUCCESS_PLOCKSTAT 1
5b2abdfb
A
67
68/* maximum number of times a read lock may be obtained */
224c7076
A
69#define MAX_READ_LOCKS (INT_MAX - 1)
70
71
72#ifndef BUILDING_VARIANT /* [ */
73
74
75int
76pthread_rwlockattr_init(pthread_rwlockattr_t *attr)
77{
78 attr->sig = _PTHREAD_RWLOCK_ATTR_SIG;
79 attr->pshared = _PTHREAD_DEFAULT_PSHARED;
80 return (0);
81}
82
83int
84pthread_rwlockattr_destroy(pthread_rwlockattr_t *attr)
85{
86 attr->sig = _PTHREAD_NO_SIG; /* Uninitialized */
87 attr->pshared = 0;
88 return (0);
89}
90
91int
92pthread_rwlockattr_getpshared(const pthread_rwlockattr_t *attr,
93 int *pshared)
94{
95 if (attr->sig == _PTHREAD_RWLOCK_ATTR_SIG)
96 {
97 *pshared = (int)attr->pshared;
98 return (0);
99 } else
100 {
101 return (EINVAL); /* Not an initialized 'attribute' structure */
102 }
103}
104
105/* Temp: untill pshared is fixed right */
106#ifdef PR_5243343
107/* 5243343 - temporary hack to detect if we are running the conformance test */
108extern int PR_5243343_flag;
109#endif /* PR_5243343 */
110
111int
112pthread_rwlockattr_setpshared(pthread_rwlockattr_t * attr, int pshared)
113{
114 if (attr->sig == _PTHREAD_RWLOCK_ATTR_SIG)
115 {
116#if __DARWIN_UNIX03
117#ifdef PR_5243343
118 if (( pshared == PTHREAD_PROCESS_PRIVATE) || (pshared == PTHREAD_PROCESS_SHARED && PR_5243343_flag))
119#else /* !PR_5243343 */
120 if (( pshared == PTHREAD_PROCESS_PRIVATE) || (pshared == PTHREAD_PROCESS_SHARED))
121#endif /* PR_5243343 */
122#else /* __DARWIN_UNIX03 */
123 if ( pshared == PTHREAD_PROCESS_PRIVATE)
124#endif /* __DARWIN_UNIX03 */
125 {
126 attr->pshared = pshared ;
127 return (0);
128 } else
129 {
130 return (EINVAL); /* Invalid parameter */
131 }
132 } else
133 {
134 return (EINVAL); /* Not an initialized 'attribute' structure */
135 }
136
137}
138
139#endif /* !BUILDING_VARIANT ] */
5b2abdfb
A
140
141int
142pthread_rwlock_destroy(pthread_rwlock_t *rwlock)
143{
224c7076 144 int ret;
5b2abdfb
A
145
146 if (rwlock->sig != _PTHREAD_RWLOCK_SIG) {
147 return(EINVAL);
148 } else {
224c7076
A
149#if __DARWIN_UNIX03
150 /* grab the monitor lock */
151 if ((ret = pthread_mutex_lock(&rwlock->lock)) != 0)
152 return(ret);
153
154 if (rwlock->state != 0) {
155 pthread_mutex_unlock(&rwlock->lock);
156 return(EBUSY);
157 }
158 pthread_mutex_unlock(&rwlock->lock);
159#endif /* __DARWIN_UNIX03 */
160
5b2abdfb
A
161 pthread_mutex_destroy(&rwlock->lock);
162 pthread_cond_destroy(&rwlock->read_signal);
163 pthread_cond_destroy(&rwlock->write_signal);
164 rwlock->sig = _PTHREAD_NO_SIG;
224c7076 165 return(0);
5b2abdfb
A
166 }
167}
168
169int
170pthread_rwlock_init(pthread_rwlock_t *rwlock, const pthread_rwlockattr_t *attr)
171{
172 int ret;
224c7076
A
173#if __DARWIN_UNIX03
174 if (attr && (attr->sig != _PTHREAD_RWLOCK_ATTR_SIG)) {
175 return(EINVAL);
176 }
177 /* if already inited check whether it is in use, then return EBUSY */
178 if ((rwlock->sig == _PTHREAD_RWLOCK_SIG) && (rwlock->state !=0 )) {
179 return(EBUSY);
180 }
181#endif /* __DARWIN_UNIX03 */
5b2abdfb
A
182
183 /* initialize the lock */
184 if ((ret = pthread_mutex_init(&rwlock->lock, NULL)) != 0)
185 return(ret);
186 else {
187 /* initialize the read condition signal */
188 ret = pthread_cond_init(&rwlock->read_signal, NULL);
189
190 if (ret != 0) {
191 pthread_mutex_destroy(&rwlock->lock);
192 return(ret);
193 } else {
194 /* initialize the write condition signal */
195 ret = pthread_cond_init(&rwlock->write_signal, NULL);
196
197 if (ret != 0) {
198 pthread_cond_destroy(&rwlock->read_signal);
199 pthread_mutex_destroy(&rwlock->lock);
200 return(ret);
201 } else {
202 /* success */
203 rwlock->state = 0;
224c7076 204 rwlock->owner = (pthread_t)0;
5b2abdfb 205 rwlock->blocked_writers = 0;
224c7076
A
206 if (attr)
207 rwlock->pshared = attr->pshared;
208 else
209 rwlock->pshared = _PTHREAD_DEFAULT_PSHARED;
210
5b2abdfb 211 rwlock->sig = _PTHREAD_RWLOCK_SIG;
224c7076 212 return(0);
5b2abdfb
A
213 }
214 }
215 }
216}
217
218int
219pthread_rwlock_rdlock(pthread_rwlock_t *rwlock)
220{
221 int ret;
224c7076
A
222#if __DARWIN_UNIX03
223 pthread_t self = pthread_self();
224#endif
5b2abdfb
A
225
226 if (rwlock->sig == _PTHREAD_RWLOCK_SIG_init) {
227 if ((ret = pthread_rwlock_init(rwlock, NULL)) != 0) {
224c7076 228 PLOCKSTAT_RW_ERROR(rwlock, READ_LOCK_PLOCKSTAT, ret);
5b2abdfb
A
229 return(ret);
230 }
231 }
232
224c7076
A
233 if (rwlock->sig != _PTHREAD_RWLOCK_SIG) {
234 PLOCKSTAT_RW_ERROR(rwlock, READ_LOCK_PLOCKSTAT, EINVAL);
5b2abdfb 235 return(EINVAL);
224c7076 236 }
5b2abdfb 237 /* grab the monitor lock */
224c7076
A
238 if ((ret = pthread_mutex_lock(&rwlock->lock)) != 0) {
239 PLOCKSTAT_RW_ERROR(rwlock, READ_LOCK_PLOCKSTAT, ret);
5b2abdfb 240 return(ret);
224c7076
A
241 }
242
243#if __DARWIN_UNIX03
244 if ((rwlock->state < 0) && (rwlock->owner == self)) {
245 pthread_mutex_unlock(&rwlock->lock);
246 PLOCKSTAT_RW_ERROR(rwlock, READ_LOCK_PLOCKSTAT, EDEADLK);
247 return(EDEADLK);
248 }
249#endif /* __DARWIN_UNIX03 */
250
251#if __DARWIN_UNIX03
252 while (rwlock->blocked_writers || ((rwlock->state < 0) && (rwlock->owner != self)))
253#else /* __DARWIN_UNIX03 */
254 while (rwlock->blocked_writers || rwlock->state < 0)
5b2abdfb 255
224c7076
A
256#endif /* __DARWIN_UNIX03 */
257 {
5b2abdfb 258 /* give writers priority over readers */
224c7076 259 PLOCKSTAT_RW_BLOCK(rwlock, READ_LOCK_PLOCKSTAT);
5b2abdfb
A
260 ret = pthread_cond_wait(&rwlock->read_signal, &rwlock->lock);
261
262 if (ret != 0) {
263 /* can't do a whole lot if this fails */
264 pthread_mutex_unlock(&rwlock->lock);
224c7076
A
265 PLOCKSTAT_RW_BLOCKED(rwlock, READ_LOCK_PLOCKSTAT, BLOCK_FAIL_PLOCKSTAT);
266 PLOCKSTAT_RW_ERROR(rwlock, READ_LOCK_PLOCKSTAT, ret);
5b2abdfb
A
267 return(ret);
268 }
224c7076
A
269
270 PLOCKSTAT_RW_BLOCKED(rwlock, READ_LOCK_PLOCKSTAT, BLOCK_SUCCESS_PLOCKSTAT);
5b2abdfb
A
271 }
272
273 /* check lock count */
224c7076 274 if (rwlock->state == MAX_READ_LOCKS) {
5b2abdfb 275 ret = EAGAIN;
224c7076
A
276 PLOCKSTAT_RW_ERROR(rwlock, READ_LOCK_PLOCKSTAT, ret);
277 }
278 else {
5b2abdfb 279 ++rwlock->state; /* indicate we are locked for reading */
224c7076
A
280 PLOCKSTAT_RW_ACQUIRE(rwlock, READ_LOCK_PLOCKSTAT);
281 }
5b2abdfb
A
282
283 /*
284 * Something is really wrong if this call fails. Returning
285 * error won't do because we've already obtained the read
286 * lock. Decrementing 'state' is no good because we probably
287 * don't have the monitor lock.
288 */
289 pthread_mutex_unlock(&rwlock->lock);
290
291 return(ret);
292}
293
294int
295pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock)
296{
297 int ret;
224c7076
A
298#if __DARWIN_UNIX03
299 pthread_t self = pthread_self();
300#endif
5b2abdfb
A
301
302 /* check for static initialization */
303 if (rwlock->sig == _PTHREAD_RWLOCK_SIG_init) {
304 if ((ret = pthread_rwlock_init(rwlock, NULL)) != 0) {
224c7076 305 PLOCKSTAT_RW_ERROR(rwlock, READ_LOCK_PLOCKSTAT, ret);
5b2abdfb
A
306 return(ret);
307 }
308 }
309
224c7076
A
310 if (rwlock->sig != _PTHREAD_RWLOCK_SIG) {
311 PLOCKSTAT_RW_ERROR(rwlock, READ_LOCK_PLOCKSTAT, EINVAL);
5b2abdfb 312 return(EINVAL);
224c7076 313 }
5b2abdfb 314 /* grab the monitor lock */
224c7076
A
315 if ((ret = pthread_mutex_lock(&rwlock->lock)) != 0) {
316 PLOCKSTAT_RW_ERROR(rwlock, READ_LOCK_PLOCKSTAT, ret);
5b2abdfb 317 return(ret);
224c7076 318 }
5b2abdfb
A
319
320 /* give writers priority over readers */
224c7076 321 if (rwlock->blocked_writers || rwlock->state < 0) {
5b2abdfb 322 ret = EBUSY;
224c7076
A
323 PLOCKSTAT_RW_ERROR(rwlock, READ_LOCK_PLOCKSTAT, ret);
324 }
325 else if (rwlock->state == MAX_READ_LOCKS) {
5b2abdfb 326 ret = EAGAIN; /* too many read locks acquired */
224c7076
A
327 PLOCKSTAT_RW_ERROR(rwlock, READ_LOCK_PLOCKSTAT, ret);
328 }
329 else {
5b2abdfb 330 ++rwlock->state; /* indicate we are locked for reading */
224c7076
A
331 PLOCKSTAT_RW_ACQUIRE(rwlock, READ_LOCK_PLOCKSTAT);
332 }
5b2abdfb
A
333
334 /* see the comment on this in pthread_rwlock_rdlock */
335 pthread_mutex_unlock(&rwlock->lock);
336
337 return(ret);
338}
339
340int
341pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock)
342{
343 int ret;
224c7076
A
344#if __DARWIN_UNIX03
345 pthread_t self = pthread_self();
346#endif /* __DARWIN_UNIX03 */
5b2abdfb
A
347
348 /* check for static initialization */
349 if (rwlock->sig == _PTHREAD_RWLOCK_SIG_init) {
350 if ((ret = pthread_rwlock_init(rwlock, NULL)) != 0) {
224c7076 351 PLOCKSTAT_RW_ERROR(rwlock, WRITE_LOCK_PLOCKSTAT, ret);
5b2abdfb
A
352 return(ret);
353 }
354 }
355
224c7076
A
356 if (rwlock->sig != _PTHREAD_RWLOCK_SIG) {
357 PLOCKSTAT_RW_ERROR(rwlock, WRITE_LOCK_PLOCKSTAT, EINVAL);
5b2abdfb 358 return(EINVAL);
224c7076 359 }
5b2abdfb 360 /* grab the monitor lock */
224c7076
A
361 if ((ret = pthread_mutex_lock(&rwlock->lock)) != 0) {
362 PLOCKSTAT_RW_ERROR(rwlock, WRITE_LOCK_PLOCKSTAT, ret);
5b2abdfb 363 return(ret);
224c7076
A
364 }
365
5b2abdfb 366
224c7076 367 if (rwlock->state != 0) {
5b2abdfb 368 ret = EBUSY;
224c7076
A
369 PLOCKSTAT_RW_ERROR(rwlock, WRITE_LOCK_PLOCKSTAT, ret);
370 }
371 else {
5b2abdfb
A
372 /* indicate we are locked for writing */
373 rwlock->state = -1;
224c7076
A
374#if __DARWIN_UNIX03
375 rwlock->owner = self;
376#endif /* __DARWIN_UNIX03 */
377 PLOCKSTAT_RW_ACQUIRE(rwlock, WRITE_LOCK_PLOCKSTAT);
378 }
5b2abdfb
A
379
380 /* see the comment on this in pthread_rwlock_rdlock */
381 pthread_mutex_unlock(&rwlock->lock);
382
383 return(ret);
384}
385
386int
387pthread_rwlock_unlock(pthread_rwlock_t *rwlock)
388{
389 int ret;
224c7076
A
390 int writer = (rwlock < 0) ? 1:0;
391#if __DARWIN_UNIX03
392 pthread_t self = pthread_self();
393#endif /* __DARWIN_UNIX03 */
5b2abdfb 394
224c7076
A
395 if (rwlock->sig != _PTHREAD_RWLOCK_SIG) {
396 PLOCKSTAT_RW_ERROR(rwlock, writer, EINVAL);
5b2abdfb 397 return(EINVAL);
224c7076 398 }
5b2abdfb 399 /* grab the monitor lock */
224c7076
A
400 if ((ret = pthread_mutex_lock(&rwlock->lock)) != 0) {
401 PLOCKSTAT_RW_ERROR(rwlock, writer, ret);
5b2abdfb 402 return(ret);
224c7076 403 }
5b2abdfb
A
404
405 if (rwlock->state > 0) {
406 if (--rwlock->state == 0 && rwlock->blocked_writers)
407 ret = pthread_cond_signal(&rwlock->write_signal);
408 } else if (rwlock->state < 0) {
409 rwlock->state = 0;
224c7076
A
410#if __DARWIN_UNIX03
411 rwlock->owner = (pthread_t)0;
412#endif /* __DARWIN_UNIX03 */
5b2abdfb
A
413
414 if (rwlock->blocked_writers)
415 ret = pthread_cond_signal(&rwlock->write_signal);
416 else
417 ret = pthread_cond_broadcast(&rwlock->read_signal);
418 } else
419 ret = EINVAL;
420
224c7076
A
421 if (ret == 0) {
422 PLOCKSTAT_RW_RELEASE(rwlock, writer);
423 } else {
424 PLOCKSTAT_RW_ERROR(rwlock, writer, ret);
425 }
426
5b2abdfb
A
427 /* see the comment on this in pthread_rwlock_rdlock */
428 pthread_mutex_unlock(&rwlock->lock);
429
430 return(ret);
431}
432
433int
434pthread_rwlock_wrlock(pthread_rwlock_t *rwlock)
435{
436 int ret;
224c7076
A
437#if __DARWIN_UNIX03
438 pthread_t self = pthread_self();
439#endif /* __DARWIN_UNIX03 */
5b2abdfb
A
440
441 /* check for static initialization */
442 if (rwlock->sig == _PTHREAD_RWLOCK_SIG_init) {
443 if ((ret = pthread_rwlock_init(rwlock, NULL)) != 0) {
224c7076 444 PLOCKSTAT_RW_ERROR(rwlock, WRITE_LOCK_PLOCKSTAT, ret);
5b2abdfb
A
445 return(ret);
446 }
447 }
448
224c7076
A
449 if (rwlock->sig != _PTHREAD_RWLOCK_SIG) {
450 PLOCKSTAT_RW_ERROR(rwlock, WRITE_LOCK_PLOCKSTAT, EINVAL);
5b2abdfb 451 return(EINVAL);
224c7076 452 }
5b2abdfb 453 /* grab the monitor lock */
224c7076
A
454 if ((ret = pthread_mutex_lock(&rwlock->lock)) != 0) {
455 PLOCKSTAT_RW_ERROR(rwlock, WRITE_LOCK_PLOCKSTAT, ret);
5b2abdfb 456 return(ret);
224c7076 457 }
5b2abdfb 458
224c7076
A
459#if __DARWIN_UNIX03
460 if ((rwlock->state < 0) && (rwlock->owner == self)) {
461 pthread_mutex_unlock(&rwlock->lock);
462 PLOCKSTAT_RW_ERROR(rwlock, WRITE_LOCK_PLOCKSTAT, EDEADLK);
463 return(EDEADLK);
464 }
465#endif /* __DARWIN_UNIX03 */
5b2abdfb
A
466 while (rwlock->state != 0) {
467 ++rwlock->blocked_writers;
468
224c7076 469 PLOCKSTAT_RW_BLOCK(rwlock, WRITE_LOCK_PLOCKSTAT);
5b2abdfb
A
470 ret = pthread_cond_wait(&rwlock->write_signal, &rwlock->lock);
471
472 if (ret != 0) {
473 --rwlock->blocked_writers;
474 pthread_mutex_unlock(&rwlock->lock);
224c7076
A
475 PLOCKSTAT_RW_BLOCKED(rwlock, WRITE_LOCK_PLOCKSTAT, BLOCK_FAIL_PLOCKSTAT);
476 PLOCKSTAT_RW_ERROR(rwlock, WRITE_LOCK_PLOCKSTAT, ret);
5b2abdfb
A
477 return(ret);
478 }
479
224c7076
A
480 PLOCKSTAT_RW_BLOCKED(rwlock, WRITE_LOCK_PLOCKSTAT, BLOCK_SUCCESS_PLOCKSTAT);
481
5b2abdfb
A
482 --rwlock->blocked_writers;
483 }
484
485 /* indicate we are locked for writing */
486 rwlock->state = -1;
224c7076
A
487#if __DARWIN_UNIX03
488 rwlock->owner = self;
489#endif /* __DARWIN_UNIX03 */
490 PLOCKSTAT_RW_ACQUIRE(rwlock, WRITE_LOCK_PLOCKSTAT);
5b2abdfb
A
491
492 /* see the comment on this in pthread_rwlock_rdlock */
493 pthread_mutex_unlock(&rwlock->lock);
494
495 return(ret);
496}
497
5b2abdfb 498