]>
git.saurik.com Git - apple/libc.git/blob - pthreads/pthread_rwlock.c
35bb6d08522f6d809437426474e656d96faa62d4
2 * Copyright (c) 2000-2003, 2007, 2008 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
;
62 #include "plockstat.h"
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 */
71 #define READ_LOCK_PLOCKSTAT 0
72 #define WRITE_LOCK_PLOCKSTAT 1
74 #define BLOCK_FAIL_PLOCKSTAT 0
75 #define BLOCK_SUCCESS_PLOCKSTAT 1
77 /* maximum number of times a read lock may be obtained */
78 #define MAX_READ_LOCKS (INT_MAX - 1)
81 #ifndef BUILDING_VARIANT /* [ */
85 pthread_rwlockattr_init(pthread_rwlockattr_t
*attr
)
87 attr
->sig
= _PTHREAD_RWLOCK_ATTR_SIG
;
88 attr
->pshared
= _PTHREAD_DEFAULT_PSHARED
;
93 pthread_rwlockattr_destroy(pthread_rwlockattr_t
*attr
)
95 attr
->sig
= _PTHREAD_NO_SIG
; /* Uninitialized */
101 pthread_rwlockattr_getpshared(const pthread_rwlockattr_t
*attr
,
104 if (attr
->sig
== _PTHREAD_RWLOCK_ATTR_SIG
)
106 *pshared
= (int)attr
->pshared
;
110 return (EINVAL
); /* Not an initialized 'attribute' structure */
114 /* Temp: untill pshared is fixed right */
116 /* 5243343 - temporary hack to detect if we are running the conformance test */
117 extern int PR_5243343_flag
;
118 #endif /* PR_5243343 */
121 pthread_rwlockattr_setpshared(pthread_rwlockattr_t
* attr
, int pshared
)
123 if (attr
->sig
== _PTHREAD_RWLOCK_ATTR_SIG
)
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 */
135 attr
->pshared
= pshared
;
139 return (EINVAL
); /* Invalid parameter */
143 return (EINVAL
); /* Not an initialized 'attribute' structure */
148 #endif /* !BUILDING_VARIANT ] */
151 pthread_rwlock_destroy(pthread_rwlock_t
*rwlock
)
155 if (rwlock
->sig
!= _PTHREAD_RWLOCK_SIG
) {
159 /* grab the monitor lock */
160 if ((ret
= pthread_mutex_lock(&rwlock
->lock
)) != 0)
163 if (rwlock
->state
!= 0) {
164 pthread_mutex_unlock(&rwlock
->lock
);
167 pthread_mutex_unlock(&rwlock
->lock
);
168 #endif /* __DARWIN_UNIX03 */
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
;
179 pthread_rwlock_init(pthread_rwlock_t
*rwlock
, const pthread_rwlockattr_t
*attr
)
183 if (attr
&& (attr
->sig
!= _PTHREAD_RWLOCK_ATTR_SIG
)) {
186 /* if already inited check whether it is in use, then return EBUSY */
187 if ((rwlock
->sig
== _PTHREAD_RWLOCK_SIG
) && (rwlock
->state
!=0 )) {
190 #endif /* __DARWIN_UNIX03 */
192 /* initialize the lock */
193 if ((ret
= pthread_mutex_init(&rwlock
->lock
, NULL
)) != 0)
196 /* initialize the read condition signal */
197 ret
= pthread_cond_init(&rwlock
->read_signal
, NULL
);
200 pthread_mutex_destroy(&rwlock
->lock
);
203 /* initialize the write condition signal */
204 ret
= pthread_cond_init(&rwlock
->write_signal
, NULL
);
207 pthread_cond_destroy(&rwlock
->read_signal
);
208 pthread_mutex_destroy(&rwlock
->lock
);
213 rwlock
->owner
= (pthread_t
)0;
214 rwlock
->blocked_writers
= 0;
216 rwlock
->pshared
= attr
->pshared
;
218 rwlock
->pshared
= _PTHREAD_DEFAULT_PSHARED
;
220 rwlock
->sig
= _PTHREAD_RWLOCK_SIG
;
228 pthread_rwlock_rdlock(pthread_rwlock_t
*rwlock
)
232 pthread_t self
= pthread_self();
235 if (rwlock
->sig
== _PTHREAD_RWLOCK_SIG_init
) {
236 if ((ret
= pthread_rwlock_init(rwlock
, NULL
)) != 0) {
237 PLOCKSTAT_RW_ERROR(rwlock
, READ_LOCK_PLOCKSTAT
, ret
);
242 if (rwlock
->sig
!= _PTHREAD_RWLOCK_SIG
) {
243 PLOCKSTAT_RW_ERROR(rwlock
, READ_LOCK_PLOCKSTAT
, EINVAL
);
246 /* grab the monitor lock */
247 if ((ret
= pthread_mutex_lock(&rwlock
->lock
)) != 0) {
248 PLOCKSTAT_RW_ERROR(rwlock
, READ_LOCK_PLOCKSTAT
, ret
);
253 if ((rwlock
->state
< 0) && (rwlock
->owner
== self
)) {
254 pthread_mutex_unlock(&rwlock
->lock
);
255 PLOCKSTAT_RW_ERROR(rwlock
, READ_LOCK_PLOCKSTAT
, EDEADLK
);
258 #endif /* __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)
265 #endif /* __DARWIN_UNIX03 */
267 /* give writers priority over readers */
268 PLOCKSTAT_RW_BLOCK(rwlock
, READ_LOCK_PLOCKSTAT
);
269 ret
= pthread_cond_wait(&rwlock
->read_signal
, &rwlock
->lock
);
272 /* can't do a whole lot if this fails */
273 pthread_mutex_unlock(&rwlock
->lock
);
274 PLOCKSTAT_RW_BLOCKED(rwlock
, READ_LOCK_PLOCKSTAT
, BLOCK_FAIL_PLOCKSTAT
);
275 PLOCKSTAT_RW_ERROR(rwlock
, READ_LOCK_PLOCKSTAT
, ret
);
279 PLOCKSTAT_RW_BLOCKED(rwlock
, READ_LOCK_PLOCKSTAT
, BLOCK_SUCCESS_PLOCKSTAT
);
282 /* check lock count */
283 if (rwlock
->state
== MAX_READ_LOCKS
) {
285 PLOCKSTAT_RW_ERROR(rwlock
, READ_LOCK_PLOCKSTAT
, ret
);
288 ++rwlock
->state
; /* indicate we are locked for reading */
289 PLOCKSTAT_RW_ACQUIRE(rwlock
, READ_LOCK_PLOCKSTAT
);
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.
298 pthread_mutex_unlock(&rwlock
->lock
);
304 pthread_rwlock_tryrdlock(pthread_rwlock_t
*rwlock
)
308 pthread_t self
= pthread_self();
311 /* check for static initialization */
312 if (rwlock
->sig
== _PTHREAD_RWLOCK_SIG_init
) {
313 if ((ret
= pthread_rwlock_init(rwlock
, NULL
)) != 0) {
314 PLOCKSTAT_RW_ERROR(rwlock
, READ_LOCK_PLOCKSTAT
, ret
);
319 if (rwlock
->sig
!= _PTHREAD_RWLOCK_SIG
) {
320 PLOCKSTAT_RW_ERROR(rwlock
, READ_LOCK_PLOCKSTAT
, EINVAL
);
323 /* grab the monitor lock */
324 if ((ret
= pthread_mutex_lock(&rwlock
->lock
)) != 0) {
325 PLOCKSTAT_RW_ERROR(rwlock
, READ_LOCK_PLOCKSTAT
, ret
);
329 /* give writers priority over readers */
330 if (rwlock
->blocked_writers
|| rwlock
->state
< 0) {
332 PLOCKSTAT_RW_ERROR(rwlock
, READ_LOCK_PLOCKSTAT
, ret
);
334 else if (rwlock
->state
== MAX_READ_LOCKS
) {
335 ret
= EAGAIN
; /* too many read locks acquired */
336 PLOCKSTAT_RW_ERROR(rwlock
, READ_LOCK_PLOCKSTAT
, ret
);
339 ++rwlock
->state
; /* indicate we are locked for reading */
340 PLOCKSTAT_RW_ACQUIRE(rwlock
, READ_LOCK_PLOCKSTAT
);
343 /* see the comment on this in pthread_rwlock_rdlock */
344 pthread_mutex_unlock(&rwlock
->lock
);
350 pthread_rwlock_trywrlock(pthread_rwlock_t
*rwlock
)
354 pthread_t self
= pthread_self();
355 #endif /* __DARWIN_UNIX03 */
357 /* check for static initialization */
358 if (rwlock
->sig
== _PTHREAD_RWLOCK_SIG_init
) {
359 if ((ret
= pthread_rwlock_init(rwlock
, NULL
)) != 0) {
360 PLOCKSTAT_RW_ERROR(rwlock
, WRITE_LOCK_PLOCKSTAT
, ret
);
365 if (rwlock
->sig
!= _PTHREAD_RWLOCK_SIG
) {
366 PLOCKSTAT_RW_ERROR(rwlock
, WRITE_LOCK_PLOCKSTAT
, EINVAL
);
369 /* grab the monitor lock */
370 if ((ret
= pthread_mutex_lock(&rwlock
->lock
)) != 0) {
371 PLOCKSTAT_RW_ERROR(rwlock
, WRITE_LOCK_PLOCKSTAT
, ret
);
376 if (rwlock
->state
!= 0) {
378 PLOCKSTAT_RW_ERROR(rwlock
, WRITE_LOCK_PLOCKSTAT
, ret
);
381 /* indicate we are locked for writing */
384 rwlock
->owner
= self
;
385 #endif /* __DARWIN_UNIX03 */
386 PLOCKSTAT_RW_ACQUIRE(rwlock
, WRITE_LOCK_PLOCKSTAT
);
389 /* see the comment on this in pthread_rwlock_rdlock */
390 pthread_mutex_unlock(&rwlock
->lock
);
396 pthread_rwlock_unlock(pthread_rwlock_t
*rwlock
)
399 int writer
= (rwlock
< 0) ? 1:0;
401 pthread_t self
= pthread_self();
402 #endif /* __DARWIN_UNIX03 */
404 if (rwlock
->sig
!= _PTHREAD_RWLOCK_SIG
) {
405 PLOCKSTAT_RW_ERROR(rwlock
, writer
, EINVAL
);
408 /* grab the monitor lock */
409 if ((ret
= pthread_mutex_lock(&rwlock
->lock
)) != 0) {
410 PLOCKSTAT_RW_ERROR(rwlock
, writer
, ret
);
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) {
420 rwlock
->owner
= (pthread_t
)0;
421 #endif /* __DARWIN_UNIX03 */
423 if (rwlock
->blocked_writers
)
424 ret
= pthread_cond_signal(&rwlock
->write_signal
);
426 ret
= pthread_cond_broadcast(&rwlock
->read_signal
);
431 PLOCKSTAT_RW_RELEASE(rwlock
, writer
);
433 PLOCKSTAT_RW_ERROR(rwlock
, writer
, ret
);
436 /* see the comment on this in pthread_rwlock_rdlock */
437 pthread_mutex_unlock(&rwlock
->lock
);
443 pthread_rwlock_wrlock(pthread_rwlock_t
*rwlock
)
447 pthread_t self
= pthread_self();
448 #endif /* __DARWIN_UNIX03 */
450 /* check for static initialization */
451 if (rwlock
->sig
== _PTHREAD_RWLOCK_SIG_init
) {
452 if ((ret
= pthread_rwlock_init(rwlock
, NULL
)) != 0) {
453 PLOCKSTAT_RW_ERROR(rwlock
, WRITE_LOCK_PLOCKSTAT
, ret
);
458 if (rwlock
->sig
!= _PTHREAD_RWLOCK_SIG
) {
459 PLOCKSTAT_RW_ERROR(rwlock
, WRITE_LOCK_PLOCKSTAT
, EINVAL
);
462 /* grab the monitor lock */
463 if ((ret
= pthread_mutex_lock(&rwlock
->lock
)) != 0) {
464 PLOCKSTAT_RW_ERROR(rwlock
, WRITE_LOCK_PLOCKSTAT
, ret
);
469 if ((rwlock
->state
< 0) && (rwlock
->owner
== self
)) {
470 pthread_mutex_unlock(&rwlock
->lock
);
471 PLOCKSTAT_RW_ERROR(rwlock
, WRITE_LOCK_PLOCKSTAT
, EDEADLK
);
474 #endif /* __DARWIN_UNIX03 */
475 while (rwlock
->state
!= 0) {
476 ++rwlock
->blocked_writers
;
478 PLOCKSTAT_RW_BLOCK(rwlock
, WRITE_LOCK_PLOCKSTAT
);
479 ret
= pthread_cond_wait(&rwlock
->write_signal
, &rwlock
->lock
);
482 --rwlock
->blocked_writers
;
483 pthread_mutex_unlock(&rwlock
->lock
);
484 PLOCKSTAT_RW_BLOCKED(rwlock
, WRITE_LOCK_PLOCKSTAT
, BLOCK_FAIL_PLOCKSTAT
);
485 PLOCKSTAT_RW_ERROR(rwlock
, WRITE_LOCK_PLOCKSTAT
, ret
);
489 PLOCKSTAT_RW_BLOCKED(rwlock
, WRITE_LOCK_PLOCKSTAT
, BLOCK_SUCCESS_PLOCKSTAT
);
491 --rwlock
->blocked_writers
;
494 /* indicate we are locked for writing */
497 rwlock
->owner
= self
;
498 #endif /* __DARWIN_UNIX03 */
499 PLOCKSTAT_RW_ACQUIRE(rwlock
, WRITE_LOCK_PLOCKSTAT
);
501 /* see the comment on this in pthread_rwlock_rdlock */
502 pthread_mutex_unlock(&rwlock
->lock
);