]>
git.saurik.com Git - apple/libc.git/blob - pthreads/pthread_rwlock.c
2 * Copyright (c) 2000-2003, 2007 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
24 * Copyright (c) 1998 Alex Nash
25 * All rights reserved.
27 * Redistribution and use in source and binary forms, with or without
28 * modification, are permitted provided that the following conditions
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.
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
48 * $FreeBSD: src/lib/libc_r/uthread/uthread_rwlock.c,v 1.6 2001/04/10 04:19:20 deischen Exp $
52 * POSIX Pthread Library
53 * -- Read Write Lock support
58 #include "pthread_internals.h"
59 extern int __unix_conforming
;
61 #include "plockstat.h"
62 #define READ_LOCK_PLOCKSTAT 0
63 #define WRITE_LOCK_PLOCKSTAT 1
65 #define BLOCK_FAIL_PLOCKSTAT 0
66 #define BLOCK_SUCCESS_PLOCKSTAT 1
68 /* maximum number of times a read lock may be obtained */
69 #define MAX_READ_LOCKS (INT_MAX - 1)
72 #ifndef BUILDING_VARIANT /* [ */
76 pthread_rwlockattr_init(pthread_rwlockattr_t
*attr
)
78 attr
->sig
= _PTHREAD_RWLOCK_ATTR_SIG
;
79 attr
->pshared
= _PTHREAD_DEFAULT_PSHARED
;
84 pthread_rwlockattr_destroy(pthread_rwlockattr_t
*attr
)
86 attr
->sig
= _PTHREAD_NO_SIG
; /* Uninitialized */
92 pthread_rwlockattr_getpshared(const pthread_rwlockattr_t
*attr
,
95 if (attr
->sig
== _PTHREAD_RWLOCK_ATTR_SIG
)
97 *pshared
= (int)attr
->pshared
;
101 return (EINVAL
); /* Not an initialized 'attribute' structure */
105 /* Temp: untill pshared is fixed right */
107 /* 5243343 - temporary hack to detect if we are running the conformance test */
108 extern int PR_5243343_flag
;
109 #endif /* PR_5243343 */
112 pthread_rwlockattr_setpshared(pthread_rwlockattr_t
* attr
, int pshared
)
114 if (attr
->sig
== _PTHREAD_RWLOCK_ATTR_SIG
)
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 */
126 attr
->pshared
= pshared
;
130 return (EINVAL
); /* Invalid parameter */
134 return (EINVAL
); /* Not an initialized 'attribute' structure */
139 #endif /* !BUILDING_VARIANT ] */
142 pthread_rwlock_destroy(pthread_rwlock_t
*rwlock
)
146 if (rwlock
->sig
!= _PTHREAD_RWLOCK_SIG
) {
150 /* grab the monitor lock */
151 if ((ret
= pthread_mutex_lock(&rwlock
->lock
)) != 0)
154 if (rwlock
->state
!= 0) {
155 pthread_mutex_unlock(&rwlock
->lock
);
158 pthread_mutex_unlock(&rwlock
->lock
);
159 #endif /* __DARWIN_UNIX03 */
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
;
170 pthread_rwlock_init(pthread_rwlock_t
*rwlock
, const pthread_rwlockattr_t
*attr
)
174 if (attr
&& (attr
->sig
!= _PTHREAD_RWLOCK_ATTR_SIG
)) {
177 /* if already inited check whether it is in use, then return EBUSY */
178 if ((rwlock
->sig
== _PTHREAD_RWLOCK_SIG
) && (rwlock
->state
!=0 )) {
181 #endif /* __DARWIN_UNIX03 */
183 /* initialize the lock */
184 if ((ret
= pthread_mutex_init(&rwlock
->lock
, NULL
)) != 0)
187 /* initialize the read condition signal */
188 ret
= pthread_cond_init(&rwlock
->read_signal
, NULL
);
191 pthread_mutex_destroy(&rwlock
->lock
);
194 /* initialize the write condition signal */
195 ret
= pthread_cond_init(&rwlock
->write_signal
, NULL
);
198 pthread_cond_destroy(&rwlock
->read_signal
);
199 pthread_mutex_destroy(&rwlock
->lock
);
204 rwlock
->owner
= (pthread_t
)0;
205 rwlock
->blocked_writers
= 0;
207 rwlock
->pshared
= attr
->pshared
;
209 rwlock
->pshared
= _PTHREAD_DEFAULT_PSHARED
;
211 rwlock
->sig
= _PTHREAD_RWLOCK_SIG
;
219 pthread_rwlock_rdlock(pthread_rwlock_t
*rwlock
)
223 pthread_t self
= pthread_self();
226 if (rwlock
->sig
== _PTHREAD_RWLOCK_SIG_init
) {
227 if ((ret
= pthread_rwlock_init(rwlock
, NULL
)) != 0) {
228 PLOCKSTAT_RW_ERROR(rwlock
, READ_LOCK_PLOCKSTAT
, ret
);
233 if (rwlock
->sig
!= _PTHREAD_RWLOCK_SIG
) {
234 PLOCKSTAT_RW_ERROR(rwlock
, READ_LOCK_PLOCKSTAT
, EINVAL
);
237 /* grab the monitor lock */
238 if ((ret
= pthread_mutex_lock(&rwlock
->lock
)) != 0) {
239 PLOCKSTAT_RW_ERROR(rwlock
, READ_LOCK_PLOCKSTAT
, ret
);
244 if ((rwlock
->state
< 0) && (rwlock
->owner
== self
)) {
245 pthread_mutex_unlock(&rwlock
->lock
);
246 PLOCKSTAT_RW_ERROR(rwlock
, READ_LOCK_PLOCKSTAT
, EDEADLK
);
249 #endif /* __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)
256 #endif /* __DARWIN_UNIX03 */
258 /* give writers priority over readers */
259 PLOCKSTAT_RW_BLOCK(rwlock
, READ_LOCK_PLOCKSTAT
);
260 ret
= pthread_cond_wait(&rwlock
->read_signal
, &rwlock
->lock
);
263 /* can't do a whole lot if this fails */
264 pthread_mutex_unlock(&rwlock
->lock
);
265 PLOCKSTAT_RW_BLOCKED(rwlock
, READ_LOCK_PLOCKSTAT
, BLOCK_FAIL_PLOCKSTAT
);
266 PLOCKSTAT_RW_ERROR(rwlock
, READ_LOCK_PLOCKSTAT
, ret
);
270 PLOCKSTAT_RW_BLOCKED(rwlock
, READ_LOCK_PLOCKSTAT
, BLOCK_SUCCESS_PLOCKSTAT
);
273 /* check lock count */
274 if (rwlock
->state
== MAX_READ_LOCKS
) {
276 PLOCKSTAT_RW_ERROR(rwlock
, READ_LOCK_PLOCKSTAT
, ret
);
279 ++rwlock
->state
; /* indicate we are locked for reading */
280 PLOCKSTAT_RW_ACQUIRE(rwlock
, READ_LOCK_PLOCKSTAT
);
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.
289 pthread_mutex_unlock(&rwlock
->lock
);
295 pthread_rwlock_tryrdlock(pthread_rwlock_t
*rwlock
)
299 pthread_t self
= pthread_self();
302 /* check for static initialization */
303 if (rwlock
->sig
== _PTHREAD_RWLOCK_SIG_init
) {
304 if ((ret
= pthread_rwlock_init(rwlock
, NULL
)) != 0) {
305 PLOCKSTAT_RW_ERROR(rwlock
, READ_LOCK_PLOCKSTAT
, ret
);
310 if (rwlock
->sig
!= _PTHREAD_RWLOCK_SIG
) {
311 PLOCKSTAT_RW_ERROR(rwlock
, READ_LOCK_PLOCKSTAT
, EINVAL
);
314 /* grab the monitor lock */
315 if ((ret
= pthread_mutex_lock(&rwlock
->lock
)) != 0) {
316 PLOCKSTAT_RW_ERROR(rwlock
, READ_LOCK_PLOCKSTAT
, ret
);
320 /* give writers priority over readers */
321 if (rwlock
->blocked_writers
|| rwlock
->state
< 0) {
323 PLOCKSTAT_RW_ERROR(rwlock
, READ_LOCK_PLOCKSTAT
, ret
);
325 else if (rwlock
->state
== MAX_READ_LOCKS
) {
326 ret
= EAGAIN
; /* too many read locks acquired */
327 PLOCKSTAT_RW_ERROR(rwlock
, READ_LOCK_PLOCKSTAT
, ret
);
330 ++rwlock
->state
; /* indicate we are locked for reading */
331 PLOCKSTAT_RW_ACQUIRE(rwlock
, READ_LOCK_PLOCKSTAT
);
334 /* see the comment on this in pthread_rwlock_rdlock */
335 pthread_mutex_unlock(&rwlock
->lock
);
341 pthread_rwlock_trywrlock(pthread_rwlock_t
*rwlock
)
345 pthread_t self
= pthread_self();
346 #endif /* __DARWIN_UNIX03 */
348 /* check for static initialization */
349 if (rwlock
->sig
== _PTHREAD_RWLOCK_SIG_init
) {
350 if ((ret
= pthread_rwlock_init(rwlock
, NULL
)) != 0) {
351 PLOCKSTAT_RW_ERROR(rwlock
, WRITE_LOCK_PLOCKSTAT
, ret
);
356 if (rwlock
->sig
!= _PTHREAD_RWLOCK_SIG
) {
357 PLOCKSTAT_RW_ERROR(rwlock
, WRITE_LOCK_PLOCKSTAT
, EINVAL
);
360 /* grab the monitor lock */
361 if ((ret
= pthread_mutex_lock(&rwlock
->lock
)) != 0) {
362 PLOCKSTAT_RW_ERROR(rwlock
, WRITE_LOCK_PLOCKSTAT
, ret
);
367 if (rwlock
->state
!= 0) {
369 PLOCKSTAT_RW_ERROR(rwlock
, WRITE_LOCK_PLOCKSTAT
, ret
);
372 /* indicate we are locked for writing */
375 rwlock
->owner
= self
;
376 #endif /* __DARWIN_UNIX03 */
377 PLOCKSTAT_RW_ACQUIRE(rwlock
, WRITE_LOCK_PLOCKSTAT
);
380 /* see the comment on this in pthread_rwlock_rdlock */
381 pthread_mutex_unlock(&rwlock
->lock
);
387 pthread_rwlock_unlock(pthread_rwlock_t
*rwlock
)
390 int writer
= (rwlock
< 0) ? 1:0;
392 pthread_t self
= pthread_self();
393 #endif /* __DARWIN_UNIX03 */
395 if (rwlock
->sig
!= _PTHREAD_RWLOCK_SIG
) {
396 PLOCKSTAT_RW_ERROR(rwlock
, writer
, EINVAL
);
399 /* grab the monitor lock */
400 if ((ret
= pthread_mutex_lock(&rwlock
->lock
)) != 0) {
401 PLOCKSTAT_RW_ERROR(rwlock
, writer
, ret
);
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) {
411 rwlock
->owner
= (pthread_t
)0;
412 #endif /* __DARWIN_UNIX03 */
414 if (rwlock
->blocked_writers
)
415 ret
= pthread_cond_signal(&rwlock
->write_signal
);
417 ret
= pthread_cond_broadcast(&rwlock
->read_signal
);
422 PLOCKSTAT_RW_RELEASE(rwlock
, writer
);
424 PLOCKSTAT_RW_ERROR(rwlock
, writer
, ret
);
427 /* see the comment on this in pthread_rwlock_rdlock */
428 pthread_mutex_unlock(&rwlock
->lock
);
434 pthread_rwlock_wrlock(pthread_rwlock_t
*rwlock
)
438 pthread_t self
= pthread_self();
439 #endif /* __DARWIN_UNIX03 */
441 /* check for static initialization */
442 if (rwlock
->sig
== _PTHREAD_RWLOCK_SIG_init
) {
443 if ((ret
= pthread_rwlock_init(rwlock
, NULL
)) != 0) {
444 PLOCKSTAT_RW_ERROR(rwlock
, WRITE_LOCK_PLOCKSTAT
, ret
);
449 if (rwlock
->sig
!= _PTHREAD_RWLOCK_SIG
) {
450 PLOCKSTAT_RW_ERROR(rwlock
, WRITE_LOCK_PLOCKSTAT
, EINVAL
);
453 /* grab the monitor lock */
454 if ((ret
= pthread_mutex_lock(&rwlock
->lock
)) != 0) {
455 PLOCKSTAT_RW_ERROR(rwlock
, WRITE_LOCK_PLOCKSTAT
, ret
);
460 if ((rwlock
->state
< 0) && (rwlock
->owner
== self
)) {
461 pthread_mutex_unlock(&rwlock
->lock
);
462 PLOCKSTAT_RW_ERROR(rwlock
, WRITE_LOCK_PLOCKSTAT
, EDEADLK
);
465 #endif /* __DARWIN_UNIX03 */
466 while (rwlock
->state
!= 0) {
467 ++rwlock
->blocked_writers
;
469 PLOCKSTAT_RW_BLOCK(rwlock
, WRITE_LOCK_PLOCKSTAT
);
470 ret
= pthread_cond_wait(&rwlock
->write_signal
, &rwlock
->lock
);
473 --rwlock
->blocked_writers
;
474 pthread_mutex_unlock(&rwlock
->lock
);
475 PLOCKSTAT_RW_BLOCKED(rwlock
, WRITE_LOCK_PLOCKSTAT
, BLOCK_FAIL_PLOCKSTAT
);
476 PLOCKSTAT_RW_ERROR(rwlock
, WRITE_LOCK_PLOCKSTAT
, ret
);
480 PLOCKSTAT_RW_BLOCKED(rwlock
, WRITE_LOCK_PLOCKSTAT
, BLOCK_SUCCESS_PLOCKSTAT
);
482 --rwlock
->blocked_writers
;
485 /* indicate we are locked for writing */
488 rwlock
->owner
= self
;
489 #endif /* __DARWIN_UNIX03 */
490 PLOCKSTAT_RW_ACQUIRE(rwlock
, WRITE_LOCK_PLOCKSTAT
);
492 /* see the comment on this in pthread_rwlock_rdlock */
493 pthread_mutex_unlock(&rwlock
->lock
);