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
29 #include "namespace.h"
34 #include "un-namespace.h"
35 #include "thr_private.h"
37 /* maximum number of times a read lock may be obtained */
38 #define MAX_READ_LOCKS (INT_MAX - 1)
40 __weak_reference(_pthread_rwlock_destroy, pthread_rwlock_destroy);
41 __weak_reference(_pthread_rwlock_init, pthread_rwlock_init);
42 __weak_reference(_pthread_rwlock_rdlock, pthread_rwlock_rdlock);
43 __weak_reference(_pthread_rwlock_timedrdlock, pthread_rwlock_timedrdlock);
44 __weak_reference(_pthread_rwlock_tryrdlock, pthread_rwlock_tryrdlock);
45 __weak_reference(_pthread_rwlock_trywrlock, pthread_rwlock_trywrlock);
46 __weak_reference(_pthread_rwlock_unlock, pthread_rwlock_unlock);
47 __weak_reference(_pthread_rwlock_wrlock, pthread_rwlock_wrlock);
48 __weak_reference(_pthread_rwlock_timedwrlock, pthread_rwlock_timedwrlock);
53 static int init_static(pthread_rwlock_t *rwlock);
57 init_static(pthread_rwlock_t *rwlock)
59 struct pthread *thread = _get_curthread();
62 THR_LOCK_ACQUIRE(thread, &_rwlock_static_lock);
65 ret = _pthread_rwlock_init(rwlock, NULL);
69 THR_LOCK_RELEASE(thread, &_rwlock_static_lock);
74 _pthread_rwlock_destroy (pthread_rwlock_t *rwlock)
81 pthread_rwlock_t prwlock;
85 _pthread_mutex_destroy(&prwlock->lock);
86 _pthread_cond_destroy(&prwlock->read_signal);
87 _pthread_cond_destroy(&prwlock->write_signal);
98 _pthread_rwlock_init (pthread_rwlock_t *rwlock,
99 const pthread_rwlockattr_t *attr __unused)
101 pthread_rwlock_t prwlock;
104 /* allocate rwlock object */
105 prwlock = (pthread_rwlock_t)malloc(sizeof(struct pthread_rwlock));
110 /* initialize the lock */
111 if ((ret = _pthread_mutex_init(&prwlock->lock, NULL)) != 0)
114 /* initialize the read condition signal */
115 ret = _pthread_cond_init(&prwlock->read_signal, NULL);
118 _pthread_mutex_destroy(&prwlock->lock);
121 /* initialize the write condition signal */
122 ret = _pthread_cond_init(&prwlock->write_signal, NULL);
125 _pthread_cond_destroy(&prwlock->read_signal);
126 _pthread_mutex_destroy(&prwlock->lock);
131 prwlock->blocked_writers = 0;
142 rwlock_rdlock_common (pthread_rwlock_t *rwlock, const struct timespec *abstime)
144 pthread_rwlock_t prwlock;
145 struct pthread *curthread;
153 /* check for static initialization */
154 if (prwlock == NULL) {
155 if ((ret = init_static(rwlock)) != 0)
161 /* grab the monitor lock */
162 if ((ret = _thr_mutex_lock(&prwlock->lock)) != 0)
165 /* check lock count */
166 if (prwlock->state == MAX_READ_LOCKS) {
167 _thr_mutex_unlock(&prwlock->lock);
171 curthread = _get_curthread();
172 if ((curthread->rdlock_count > 0) && (prwlock->state > 0)) {
174 * To avoid having to track all the rdlocks held by
175 * a thread or all of the threads that hold a rdlock,
176 * we keep a simple count of all the rdlocks held by
177 * a thread. If a thread holds any rdlocks it is
178 * possible that it is attempting to take a recursive
179 * rdlock. If there are blocked writers and precedence
180 * is given to them, then that would result in the thread
181 * deadlocking. So allowing a thread to take the rdlock
182 * when it already has one or more rdlocks avoids the
183 * deadlock. I hope the reader can follow that logic ;-)
185 ; /* nothing needed */
187 /* give writers priority over readers */
188 while (prwlock->blocked_writers || prwlock->state < 0) {
190 ret = _pthread_cond_timedwait
191 (&prwlock->read_signal,
192 &prwlock->lock, abstime);
194 ret = _thr_cond_wait(&prwlock->read_signal,
197 /* can't do a whole lot if this fails */
198 _thr_mutex_unlock(&prwlock->lock);
204 curthread->rdlock_count++;
205 prwlock->state++; /* indicate we are locked for reading */
208 * Something is really wrong if this call fails. Returning
209 * error won't do because we've already obtained the read
210 * lock. Decrementing 'state' is no good because we probably
211 * don't have the monitor lock.
213 _thr_mutex_unlock(&prwlock->lock);
219 _pthread_rwlock_rdlock (pthread_rwlock_t *rwlock)
221 return (rwlock_rdlock_common(rwlock, NULL));
224 __strong_reference(_pthread_rwlock_rdlock, _thr_rwlock_rdlock);
227 _pthread_rwlock_timedrdlock (pthread_rwlock_t *rwlock,
228 const struct timespec *abstime)
230 return (rwlock_rdlock_common(rwlock, abstime));
234 _pthread_rwlock_tryrdlock (pthread_rwlock_t *rwlock)
236 struct pthread *curthread;
237 pthread_rwlock_t prwlock;
245 /* check for static initialization */
246 if (prwlock == NULL) {
247 if ((ret = init_static(rwlock)) != 0)
253 /* grab the monitor lock */
254 if ((ret = _pthread_mutex_lock(&prwlock->lock)) != 0)
257 curthread = _get_curthread();
258 if (prwlock->state == MAX_READ_LOCKS)
260 else if ((curthread->rdlock_count > 0) && (prwlock->state > 0)) {
261 /* see comment for pthread_rwlock_rdlock() */
262 curthread->rdlock_count++;
265 /* give writers priority over readers */
266 else if (prwlock->blocked_writers || prwlock->state < 0)
269 curthread->rdlock_count++;
270 prwlock->state++; /* indicate we are locked for reading */
273 /* see the comment on this in pthread_rwlock_rdlock */
274 _pthread_mutex_unlock(&prwlock->lock);
280 _pthread_rwlock_trywrlock (pthread_rwlock_t *rwlock)
282 pthread_rwlock_t prwlock;
290 /* check for static initialization */
291 if (prwlock == NULL) {
292 if ((ret = init_static(rwlock)) != 0)
298 /* grab the monitor lock */
299 if ((ret = _pthread_mutex_lock(&prwlock->lock)) != 0)
302 if (prwlock->state != 0)
305 /* indicate we are locked for writing */
308 /* see the comment on this in pthread_rwlock_rdlock */
309 _pthread_mutex_unlock(&prwlock->lock);
315 _pthread_rwlock_unlock (pthread_rwlock_t *rwlock)
317 struct pthread *curthread;
318 pthread_rwlock_t prwlock;
329 /* grab the monitor lock */
330 if ((ret = _thr_mutex_lock(&prwlock->lock)) != 0)
333 curthread = _get_curthread();
334 if (prwlock->state > 0) {
335 curthread->rdlock_count--;
337 if (prwlock->state == 0 && prwlock->blocked_writers)
338 ret = _thr_cond_signal(&prwlock->write_signal);
339 } else if (prwlock->state < 0) {
342 if (prwlock->blocked_writers)
343 ret = _thr_cond_signal(&prwlock->write_signal);
345 ret = _thr_cond_broadcast(&prwlock->read_signal);
349 /* see the comment on this in pthread_rwlock_rdlock */
350 _thr_mutex_unlock(&prwlock->lock);
355 __strong_reference(_pthread_rwlock_unlock, _thr_rwlock_unlock);
358 rwlock_wrlock_common (pthread_rwlock_t *rwlock, const struct timespec *abstime)
360 pthread_rwlock_t prwlock;
368 /* check for static initialization */
369 if (prwlock == NULL) {
370 if ((ret = init_static(rwlock)) != 0)
376 /* grab the monitor lock */
377 if ((ret = _thr_mutex_lock(&prwlock->lock)) != 0)
380 while (prwlock->state != 0) {
381 prwlock->blocked_writers++;
384 ret = _pthread_cond_timedwait(&prwlock->write_signal,
385 &prwlock->lock, abstime);
387 ret = _thr_cond_wait(&prwlock->write_signal,
390 prwlock->blocked_writers--;
391 _thr_mutex_unlock(&prwlock->lock);
395 prwlock->blocked_writers--;
398 /* indicate we are locked for writing */
401 /* see the comment on this in pthread_rwlock_rdlock */
402 _thr_mutex_unlock(&prwlock->lock);
408 _pthread_rwlock_wrlock (pthread_rwlock_t *rwlock)
410 return (rwlock_wrlock_common (rwlock, NULL));
412 __strong_reference(_pthread_rwlock_wrlock, _thr_rwlock_wrlock);
415 _pthread_rwlock_timedwrlock (pthread_rwlock_t *rwlock,
416 const struct timespec *abstime)
418 return (rwlock_wrlock_common (rwlock, abstime));