]> git.saurik.com Git - apple/libc.git/blame - pthreads/pthread_rwlock.c
Libc-391.5.22.tar.gz
[apple/libc.git] / pthreads / pthread_rwlock.c
CommitLineData
9385eb3d
A
1/*
2 * Copyright (c) 2000-2003 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
9385eb3d
A
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
11 * file.
12 *
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.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
5b2abdfb
A
23/*-
24 * Copyright (c) 1998 Alex Nash
25 * All rights reserved.
26 *
27 * Redistribution and use in source and binary forms, with or without
28 * modification, are permitted provided that the following conditions
29 * are met:
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.
35 *
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
46 * SUCH DAMAGE.
47 *
48 * $FreeBSD: src/lib/libc_r/uthread/uthread_rwlock.c,v 1.6 2001/04/10 04:19:20 deischen Exp $
49 */
50
51/*
52 * POSIX Pthread Library
53 * -- Read Write Lock support
54 * 4/24/02: A. Ramesh
55 * Ported from FreeBSD
56 */
57
58#include "pthread_internals.h"
59
60/* maximum number of times a read lock may be obtained */
61#define MAX_READ_LOCKS (INT_MAX - 1)
62
63int
64pthread_rwlock_destroy(pthread_rwlock_t *rwlock)
65{
66
67 if (rwlock->sig != _PTHREAD_RWLOCK_SIG) {
68 return(EINVAL);
69 } else {
70 pthread_mutex_destroy(&rwlock->lock);
71 pthread_cond_destroy(&rwlock->read_signal);
72 pthread_cond_destroy(&rwlock->write_signal);
73 rwlock->sig = _PTHREAD_NO_SIG;
74 return(ESUCCESS);
75 }
76}
77
78int
79pthread_rwlock_init(pthread_rwlock_t *rwlock, const pthread_rwlockattr_t *attr)
80{
81 int ret;
82
83 /* initialize the lock */
84 if ((ret = pthread_mutex_init(&rwlock->lock, NULL)) != 0)
85 return(ret);
86 else {
87 /* initialize the read condition signal */
88 ret = pthread_cond_init(&rwlock->read_signal, NULL);
89
90 if (ret != 0) {
91 pthread_mutex_destroy(&rwlock->lock);
92 return(ret);
93 } else {
94 /* initialize the write condition signal */
95 ret = pthread_cond_init(&rwlock->write_signal, NULL);
96
97 if (ret != 0) {
98 pthread_cond_destroy(&rwlock->read_signal);
99 pthread_mutex_destroy(&rwlock->lock);
100 return(ret);
101 } else {
102 /* success */
103 rwlock->state = 0;
104 rwlock->blocked_writers = 0;
105 rwlock->sig = _PTHREAD_RWLOCK_SIG;
106 return(ESUCCESS);
107 }
108 }
109 }
110}
111
112int
113pthread_rwlock_rdlock(pthread_rwlock_t *rwlock)
114{
115 int ret;
116
117 if (rwlock->sig == _PTHREAD_RWLOCK_SIG_init) {
118 if ((ret = pthread_rwlock_init(rwlock, NULL)) != 0) {
119 return(ret);
120 }
121 }
122
123 if (rwlock->sig != _PTHREAD_RWLOCK_SIG)
124 return(EINVAL);
125 /* grab the monitor lock */
126 if ((ret = pthread_mutex_lock(&rwlock->lock)) != 0)
127 return(ret);
128
129 /* give writers priority over readers */
130 while (rwlock->blocked_writers || rwlock->state < 0) {
131 ret = pthread_cond_wait(&rwlock->read_signal, &rwlock->lock);
132
133 if (ret != 0) {
134 /* can't do a whole lot if this fails */
135 pthread_mutex_unlock(&rwlock->lock);
136 return(ret);
137 }
138 }
139
140 /* check lock count */
141 if (rwlock->state == MAX_READ_LOCKS)
142 ret = EAGAIN;
143 else
144 ++rwlock->state; /* indicate we are locked for reading */
145
146 /*
147 * Something is really wrong if this call fails. Returning
148 * error won't do because we've already obtained the read
149 * lock. Decrementing 'state' is no good because we probably
150 * don't have the monitor lock.
151 */
152 pthread_mutex_unlock(&rwlock->lock);
153
154 return(ret);
155}
156
157int
158pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock)
159{
160 int ret;
161
162 /* check for static initialization */
163 if (rwlock->sig == _PTHREAD_RWLOCK_SIG_init) {
164 if ((ret = pthread_rwlock_init(rwlock, NULL)) != 0) {
165 return(ret);
166 }
167 }
168
169 if (rwlock->sig != _PTHREAD_RWLOCK_SIG)
170 return(EINVAL);
171 /* grab the monitor lock */
172 if ((ret = pthread_mutex_lock(&rwlock->lock)) != 0)
173 return(ret);
174
175 /* give writers priority over readers */
176 if (rwlock->blocked_writers || rwlock->state < 0)
177 ret = EBUSY;
178 else if (rwlock->state == MAX_READ_LOCKS)
179 ret = EAGAIN; /* too many read locks acquired */
180 else
181 ++rwlock->state; /* indicate we are locked for reading */
182
183 /* see the comment on this in pthread_rwlock_rdlock */
184 pthread_mutex_unlock(&rwlock->lock);
185
186 return(ret);
187}
188
189int
190pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock)
191{
192 int ret;
193
194 /* check for static initialization */
195 if (rwlock->sig == _PTHREAD_RWLOCK_SIG_init) {
196 if ((ret = pthread_rwlock_init(rwlock, NULL)) != 0) {
197 return(ret);
198 }
199 }
200
201 if (rwlock->sig != _PTHREAD_RWLOCK_SIG)
202 return(EINVAL);
203 /* grab the monitor lock */
204 if ((ret = pthread_mutex_lock(&rwlock->lock)) != 0)
205 return(ret);
206
207 if (rwlock->state != 0)
208 ret = EBUSY;
209 else
210 /* indicate we are locked for writing */
211 rwlock->state = -1;
212
213 /* see the comment on this in pthread_rwlock_rdlock */
214 pthread_mutex_unlock(&rwlock->lock);
215
216 return(ret);
217}
218
219int
220pthread_rwlock_unlock(pthread_rwlock_t *rwlock)
221{
222 int ret;
223
224 if (rwlock->sig != _PTHREAD_RWLOCK_SIG)
225 return(EINVAL);
226 /* grab the monitor lock */
227 if ((ret = pthread_mutex_lock(&rwlock->lock)) != 0)
228 return(ret);
229
230 if (rwlock->state > 0) {
231 if (--rwlock->state == 0 && rwlock->blocked_writers)
232 ret = pthread_cond_signal(&rwlock->write_signal);
233 } else if (rwlock->state < 0) {
234 rwlock->state = 0;
235
236 if (rwlock->blocked_writers)
237 ret = pthread_cond_signal(&rwlock->write_signal);
238 else
239 ret = pthread_cond_broadcast(&rwlock->read_signal);
240 } else
241 ret = EINVAL;
242
243 /* see the comment on this in pthread_rwlock_rdlock */
244 pthread_mutex_unlock(&rwlock->lock);
245
246 return(ret);
247}
248
249int
250pthread_rwlock_wrlock(pthread_rwlock_t *rwlock)
251{
252 int ret;
253
254 /* check for static initialization */
255 if (rwlock->sig == _PTHREAD_RWLOCK_SIG_init) {
256 if ((ret = pthread_rwlock_init(rwlock, NULL)) != 0) {
257 return(ret);
258 }
259 }
260
261 if (rwlock->sig != _PTHREAD_RWLOCK_SIG)
262 return(EINVAL);
263 /* grab the monitor lock */
264 if ((ret = pthread_mutex_lock(&rwlock->lock)) != 0)
265 return(ret);
266
267 while (rwlock->state != 0) {
268 ++rwlock->blocked_writers;
269
270 ret = pthread_cond_wait(&rwlock->write_signal, &rwlock->lock);
271
272 if (ret != 0) {
273 --rwlock->blocked_writers;
274 pthread_mutex_unlock(&rwlock->lock);
275 return(ret);
276 }
277
278 --rwlock->blocked_writers;
279 }
280
281 /* indicate we are locked for writing */
282 rwlock->state = -1;
283
284 /* see the comment on this in pthread_rwlock_rdlock */
285 pthread_mutex_unlock(&rwlock->lock);
286
287 return(ret);
288}
289
290int
291pthread_rwlockattr_init(pthread_rwlockattr_t *attr)
292{
293 attr->sig = _PTHREAD_RWLOCK_ATTR_SIG;
294 attr->pshared = PTHREAD_PROCESS_PRIVATE;
295 return (ESUCCESS);
296}
297
298int
299pthread_rwlockattr_destroy(pthread_rwlockattr_t *attr)
300{
301 attr->sig = _PTHREAD_NO_SIG; /* Uninitialized */
302 attr->pshared = 0;
303 return (ESUCCESS);
304}
305
306int
307pthread_rwlockattr_getpshared(const pthread_rwlockattr_t *attr,
308 int *pshared)
309{
310 if (attr->sig == _PTHREAD_RWLOCK_ATTR_SIG)
311 {
312 /* *pshared = (int)attr->pshared; */
313 *pshared = (int)PTHREAD_PROCESS_PRIVATE;
314 return (ESUCCESS);
315 } else
316 {
317 return (EINVAL); /* Not an initialized 'attribute' structure */
318 }
319}
320
321
322int
323pthread_rwlockattr_setpshared(pthread_rwlockattr_t * attr, int pshared)
324{
325 if (attr->sig == _PTHREAD_RWLOCK_ATTR_SIG)
326 {
327 if ( pshared == PTHREAD_PROCESS_PRIVATE)
328 {
329 attr->pshared = pshared ;
330 return (ESUCCESS);
331 } else
332 {
333 return (EINVAL); /* Invalid parameter */
334 }
335 } else
336 {
337 return (EINVAL); /* Not an initialized 'attribute' structure */
338 }
339
340}
341