2 * Copyright (c) 1998 Alex Nash
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * $FreeBSD: src/lib/libc_r/uthread/uthread_rwlock.c,v 1.4.2.2 2002/10/22 14:44:03 fjoe Exp $
27 * $DragonFly: src/lib/libc_r/uthread/uthread_rwlock.c,v 1.3 2005/05/30 22:50:53 joerg Exp $
35 #include "pthread_private.h"
37 /* maximum number of times a read lock may be obtained */
38 #define MAX_READ_LOCKS (INT_MAX - 1)
40 static int init_static (pthread_rwlock_t
*rwlock
);
42 static spinlock_t static_init_lock
= _SPINLOCK_INITIALIZER
;
45 init_static (pthread_rwlock_t
*rwlock
)
49 _SPINLOCK(&static_init_lock
);
52 ret
= pthread_rwlock_init(rwlock
, NULL
);
56 _SPINUNLOCK(&static_init_lock
);
62 _pthread_rwlock_destroy (pthread_rwlock_t
*rwlock
)
69 pthread_rwlock_t prwlock
;
73 pthread_mutex_destroy(&prwlock
->lock
);
74 pthread_cond_destroy(&prwlock
->read_signal
);
75 pthread_cond_destroy(&prwlock
->write_signal
);
87 _pthread_rwlock_init (pthread_rwlock_t
*rwlock
, const pthread_rwlockattr_t
*attr
)
89 pthread_rwlock_t prwlock
;
92 /* allocate rwlock object */
93 prwlock
= (pthread_rwlock_t
)malloc(sizeof(struct pthread_rwlock
));
98 /* initialize the lock */
99 if ((ret
= pthread_mutex_init(&prwlock
->lock
, NULL
)) != 0)
102 /* initialize the read condition signal */
103 ret
= pthread_cond_init(&prwlock
->read_signal
, NULL
);
106 pthread_mutex_destroy(&prwlock
->lock
);
109 /* initialize the write condition signal */
110 ret
= pthread_cond_init(&prwlock
->write_signal
, NULL
);
113 pthread_cond_destroy(&prwlock
->read_signal
);
114 pthread_mutex_destroy(&prwlock
->lock
);
119 prwlock
->blocked_writers
= 0;
130 _pthread_rwlock_rdlock (pthread_rwlock_t
*rwlock
)
132 pthread_rwlock_t prwlock
;
140 /* check for static initialization */
141 if (prwlock
== NULL
) {
142 if ((ret
= init_static(rwlock
)) != 0)
148 /* grab the monitor lock */
149 if ((ret
= pthread_mutex_lock(&prwlock
->lock
)) != 0)
152 /* give writers priority over readers */
153 while (prwlock
->blocked_writers
|| prwlock
->state
< 0) {
154 ret
= pthread_cond_wait(&prwlock
->read_signal
, &prwlock
->lock
);
157 /* can't do a whole lot if this fails */
158 pthread_mutex_unlock(&prwlock
->lock
);
163 /* check lock count */
164 if (prwlock
->state
== MAX_READ_LOCKS
)
167 ++prwlock
->state
; /* indicate we are locked for reading */
170 * Something is really wrong if this call fails. Returning
171 * error won't do because we've already obtained the read
172 * lock. Decrementing 'state' is no good because we probably
173 * don't have the monitor lock.
175 pthread_mutex_unlock(&prwlock
->lock
);
181 _pthread_rwlock_tryrdlock (pthread_rwlock_t
*rwlock
)
183 pthread_rwlock_t prwlock
;
191 /* check for static initialization */
192 if (prwlock
== NULL
) {
193 if ((ret
= init_static(rwlock
)) != 0)
199 /* grab the monitor lock */
200 if ((ret
= pthread_mutex_lock(&prwlock
->lock
)) != 0)
203 /* give writers priority over readers */
204 if (prwlock
->blocked_writers
|| prwlock
->state
< 0)
206 else if (prwlock
->state
== MAX_READ_LOCKS
)
207 ret
= EAGAIN
; /* too many read locks acquired */
209 ++prwlock
->state
; /* indicate we are locked for reading */
211 /* see the comment on this in pthread_rwlock_rdlock */
212 pthread_mutex_unlock(&prwlock
->lock
);
218 _pthread_rwlock_trywrlock (pthread_rwlock_t
*rwlock
)
220 pthread_rwlock_t prwlock
;
228 /* check for static initialization */
229 if (prwlock
== NULL
) {
230 if ((ret
= init_static(rwlock
)) != 0)
236 /* grab the monitor lock */
237 if ((ret
= pthread_mutex_lock(&prwlock
->lock
)) != 0)
240 if (prwlock
->state
!= 0)
243 /* indicate we are locked for writing */
246 /* see the comment on this in pthread_rwlock_rdlock */
247 pthread_mutex_unlock(&prwlock
->lock
);
253 _pthread_rwlock_unlock (pthread_rwlock_t
*rwlock
)
255 pthread_rwlock_t prwlock
;
266 /* grab the monitor lock */
267 if ((ret
= pthread_mutex_lock(&prwlock
->lock
)) != 0)
270 if (prwlock
->state
> 0) {
271 if (--prwlock
->state
== 0 && prwlock
->blocked_writers
)
272 ret
= pthread_cond_signal(&prwlock
->write_signal
);
273 } else if (prwlock
->state
< 0) {
276 if (prwlock
->blocked_writers
)
277 ret
= pthread_cond_signal(&prwlock
->write_signal
);
279 ret
= pthread_cond_broadcast(&prwlock
->read_signal
);
283 /* see the comment on this in pthread_rwlock_rdlock */
284 pthread_mutex_unlock(&prwlock
->lock
);
290 _pthread_rwlock_wrlock (pthread_rwlock_t
*rwlock
)
292 pthread_rwlock_t prwlock
;
300 /* check for static initialization */
301 if (prwlock
== NULL
) {
302 if ((ret
= init_static(rwlock
)) != 0)
308 /* grab the monitor lock */
309 if ((ret
= pthread_mutex_lock(&prwlock
->lock
)) != 0)
312 while (prwlock
->state
!= 0) {
313 ++prwlock
->blocked_writers
;
315 ret
= pthread_cond_wait(&prwlock
->write_signal
, &prwlock
->lock
);
318 --prwlock
->blocked_writers
;
319 pthread_mutex_unlock(&prwlock
->lock
);
323 --prwlock
->blocked_writers
;
326 /* indicate we are locked for writing */
329 /* see the comment on this in pthread_rwlock_rdlock */
330 pthread_mutex_unlock(&prwlock
->lock
);
335 __strong_reference(_pthread_rwlock_destroy
, pthread_rwlock_destroy
);
336 __strong_reference(_pthread_rwlock_init
, pthread_rwlock_init
);
337 __strong_reference(_pthread_rwlock_rdlock
, pthread_rwlock_rdlock
);
338 __strong_reference(_pthread_rwlock_tryrdlock
, pthread_rwlock_tryrdlock
);
339 __strong_reference(_pthread_rwlock_trywrlock
, pthread_rwlock_trywrlock
);
340 __strong_reference(_pthread_rwlock_unlock
, pthread_rwlock_unlock
);
341 __strong_reference(_pthread_rwlock_wrlock
, pthread_rwlock_wrlock
);