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
33 #include "namespace.h"
35 #include "un-namespace.h"
36 #include "thr_private.h"
38 /* maximum number of times a read lock may be obtained */
39 #define MAX_READ_LOCKS (INT_MAX - 1)
41 LT10_COMPAT_PRIVATE(_pthread_rwlock_destroy);
42 LT10_COMPAT_DEFAULT(pthread_rwlock_destroy);
43 LT10_COMPAT_PRIVATE(_pthread_rwlock_init);
44 LT10_COMPAT_DEFAULT(pthread_rwlock_init);
45 LT10_COMPAT_PRIVATE(_pthread_rwlock_rdlock);
46 LT10_COMPAT_DEFAULT(pthread_rwlock_rdlock);
47 LT10_COMPAT_PRIVATE(_pthread_rwlock_timedrdlock);
48 LT10_COMPAT_DEFAULT(pthread_rwlock_timedrdlock);
49 LT10_COMPAT_PRIVATE(_pthread_rwlock_tryrdlock);
50 LT10_COMPAT_DEFAULT(pthread_rwlock_tryrdlock);
51 LT10_COMPAT_PRIVATE(_pthread_rwlock_trywrlock);
52 LT10_COMPAT_DEFAULT(pthread_rwlock_trywrlock);
53 LT10_COMPAT_PRIVATE(_pthread_rwlock_unlock);
54 LT10_COMPAT_DEFAULT(pthread_rwlock_unlock);
55 LT10_COMPAT_PRIVATE(_pthread_rwlock_wrlock);
56 LT10_COMPAT_DEFAULT(pthread_rwlock_wrlock);
57 LT10_COMPAT_PRIVATE(_pthread_rwlock_timedwrlock);
58 LT10_COMPAT_DEFAULT(pthread_rwlock_timedwrlock);
60 __weak_reference(_pthread_rwlock_destroy, pthread_rwlock_destroy);
61 __weak_reference(_pthread_rwlock_init, pthread_rwlock_init);
62 __weak_reference(_pthread_rwlock_rdlock, pthread_rwlock_rdlock);
63 __weak_reference(_pthread_rwlock_timedrdlock, pthread_rwlock_timedrdlock);
64 __weak_reference(_pthread_rwlock_tryrdlock, pthread_rwlock_tryrdlock);
65 __weak_reference(_pthread_rwlock_trywrlock, pthread_rwlock_trywrlock);
66 __weak_reference(_pthread_rwlock_unlock, pthread_rwlock_unlock);
67 __weak_reference(_pthread_rwlock_wrlock, pthread_rwlock_wrlock);
68 __weak_reference(_pthread_rwlock_timedwrlock, pthread_rwlock_timedwrlock);
73 static int init_static(pthread_rwlock_t *rwlock);
77 init_static(pthread_rwlock_t *rwlock)
79 struct pthread *thread = _get_curthread();
82 THR_LOCK_ACQUIRE(thread, &_rwlock_static_lock);
85 ret = _pthread_rwlock_init(rwlock, NULL);
89 THR_LOCK_RELEASE(thread, &_rwlock_static_lock);
94 _pthread_rwlock_destroy (pthread_rwlock_t *rwlock)
101 pthread_rwlock_t prwlock;
105 _pthread_mutex_destroy(&prwlock->lock);
106 _pthread_cond_destroy(&prwlock->read_signal);
107 _pthread_cond_destroy(&prwlock->write_signal);
118 _pthread_rwlock_init (pthread_rwlock_t *rwlock, const pthread_rwlockattr_t *attr)
120 pthread_rwlock_t prwlock;
123 /* allocate rwlock object */
124 prwlock = (pthread_rwlock_t)malloc(sizeof(struct pthread_rwlock));
129 /* initialize the lock */
130 if ((ret = _pthread_mutex_init(&prwlock->lock, NULL)) != 0)
133 /* initialize the read condition signal */
134 ret = _pthread_cond_init(&prwlock->read_signal, NULL);
137 _pthread_mutex_destroy(&prwlock->lock);
140 /* initialize the write condition signal */
141 ret = _pthread_cond_init(&prwlock->write_signal, NULL);
144 _pthread_cond_destroy(&prwlock->read_signal);
145 _pthread_mutex_destroy(&prwlock->lock);
150 prwlock->blocked_writers = 0;
161 rwlock_rdlock_common (pthread_rwlock_t *rwlock, const struct timespec *abstime)
163 pthread_rwlock_t prwlock;
164 struct pthread *curthread;
172 /* check for static initialization */
173 if (prwlock == NULL) {
174 if ((ret = init_static(rwlock)) != 0)
180 /* grab the monitor lock */
181 if ((ret = _thr_mutex_lock(&prwlock->lock)) != 0)
184 /* check lock count */
185 if (prwlock->state == MAX_READ_LOCKS) {
186 _thr_mutex_unlock(&prwlock->lock);
190 curthread = _get_curthread();
191 if ((curthread->rdlock_count > 0) && (prwlock->state > 0)) {
193 * To avoid having to track all the rdlocks held by
194 * a thread or all of the threads that hold a rdlock,
195 * we keep a simple count of all the rdlocks held by
196 * a thread. If a thread holds any rdlocks it is
197 * possible that it is attempting to take a recursive
198 * rdlock. If there are blocked writers and precedence
199 * is given to them, then that would result in the thread
200 * deadlocking. So allowing a thread to take the rdlock
201 * when it already has one or more rdlocks avoids the
202 * deadlock. I hope the reader can follow that logic ;-)
204 ; /* nothing needed */
206 /* give writers priority over readers */
207 while (prwlock->blocked_writers || prwlock->state < 0) {
209 ret = _pthread_cond_timedwait
210 (&prwlock->read_signal,
211 &prwlock->lock, abstime);
213 ret = _thr_cond_wait(&prwlock->read_signal,
216 /* can't do a whole lot if this fails */
217 _thr_mutex_unlock(&prwlock->lock);
223 curthread->rdlock_count++;
224 prwlock->state++; /* indicate we are locked for reading */
227 * Something is really wrong if this call fails. Returning
228 * error won't do because we've already obtained the read
229 * lock. Decrementing 'state' is no good because we probably
230 * don't have the monitor lock.
232 _thr_mutex_unlock(&prwlock->lock);
238 _pthread_rwlock_rdlock (pthread_rwlock_t *rwlock)
240 return (rwlock_rdlock_common(rwlock, NULL));
243 __strong_reference(_pthread_rwlock_rdlock, _thr_rwlock_rdlock);
246 _pthread_rwlock_timedrdlock (pthread_rwlock_t *rwlock,
247 const struct timespec *abstime)
249 return (rwlock_rdlock_common(rwlock, abstime));
253 _pthread_rwlock_tryrdlock (pthread_rwlock_t *rwlock)
255 struct pthread *curthread;
256 pthread_rwlock_t prwlock;
264 /* check for static initialization */
265 if (prwlock == NULL) {
266 if ((ret = init_static(rwlock)) != 0)
272 /* grab the monitor lock */
273 if ((ret = _pthread_mutex_lock(&prwlock->lock)) != 0)
276 curthread = _get_curthread();
277 if (prwlock->state == MAX_READ_LOCKS)
279 else if ((curthread->rdlock_count > 0) && (prwlock->state > 0)) {
280 /* see comment for pthread_rwlock_rdlock() */
281 curthread->rdlock_count++;
284 /* give writers priority over readers */
285 else if (prwlock->blocked_writers || prwlock->state < 0)
288 curthread->rdlock_count++;
289 prwlock->state++; /* indicate we are locked for reading */
292 /* see the comment on this in pthread_rwlock_rdlock */
293 _pthread_mutex_unlock(&prwlock->lock);
299 _pthread_rwlock_trywrlock (pthread_rwlock_t *rwlock)
301 pthread_rwlock_t prwlock;
309 /* check for static initialization */
310 if (prwlock == NULL) {
311 if ((ret = init_static(rwlock)) != 0)
317 /* grab the monitor lock */
318 if ((ret = _pthread_mutex_lock(&prwlock->lock)) != 0)
321 if (prwlock->state != 0)
324 /* indicate we are locked for writing */
327 /* see the comment on this in pthread_rwlock_rdlock */
328 _pthread_mutex_unlock(&prwlock->lock);
334 _pthread_rwlock_unlock (pthread_rwlock_t *rwlock)
336 struct pthread *curthread;
337 pthread_rwlock_t prwlock;
348 /* grab the monitor lock */
349 if ((ret = _thr_mutex_lock(&prwlock->lock)) != 0)
352 curthread = _get_curthread();
353 if (prwlock->state > 0) {
354 curthread->rdlock_count--;
356 if (prwlock->state == 0 && prwlock->blocked_writers)
357 ret = _thr_cond_signal(&prwlock->write_signal);
358 } else if (prwlock->state < 0) {
361 if (prwlock->blocked_writers)
362 ret = _thr_cond_signal(&prwlock->write_signal);
364 ret = _thr_cond_broadcast(&prwlock->read_signal);
368 /* see the comment on this in pthread_rwlock_rdlock */
369 _thr_mutex_unlock(&prwlock->lock);
374 __strong_reference(_pthread_rwlock_unlock, _thr_rwlock_unlock);
377 rwlock_wrlock_common (pthread_rwlock_t *rwlock, const struct timespec *abstime)
379 pthread_rwlock_t prwlock;
387 /* check for static initialization */
388 if (prwlock == NULL) {
389 if ((ret = init_static(rwlock)) != 0)
395 /* grab the monitor lock */
396 if ((ret = _thr_mutex_lock(&prwlock->lock)) != 0)
399 while (prwlock->state != 0) {
400 prwlock->blocked_writers++;
403 ret = _pthread_cond_timedwait(&prwlock->write_signal,
404 &prwlock->lock, abstime);
406 ret = _thr_cond_wait(&prwlock->write_signal,
409 prwlock->blocked_writers--;
410 _thr_mutex_unlock(&prwlock->lock);
414 prwlock->blocked_writers--;
417 /* indicate we are locked for writing */
420 /* see the comment on this in pthread_rwlock_rdlock */
421 _thr_mutex_unlock(&prwlock->lock);
427 _pthread_rwlock_wrlock (pthread_rwlock_t *rwlock)
429 return (rwlock_wrlock_common (rwlock, NULL));
431 __strong_reference(_pthread_rwlock_wrlock, _thr_rwlock_wrlock);
434 _pthread_rwlock_timedwrlock (pthread_rwlock_t *rwlock,
435 const struct timespec *abstime)
437 return (rwlock_wrlock_common (rwlock, abstime));