]> git.saurik.com Git - apple/libc.git/blob - pthreads/pthread_rwlock.c
Libc-320.tar.gz
[apple/libc.git] / pthreads / pthread_rwlock.c
1 /*
2 * Copyright (c) 2000-2003 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
7 *
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * file.
14 *
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
22 *
23 * @APPLE_LICENSE_HEADER_END@
24 */
25 /*-
26 * Copyright (c) 1998 Alex Nash
27 * All rights reserved.
28 *
29 * Redistribution and use in source and binary forms, with or without
30 * modification, are permitted provided that the following conditions
31 * are met:
32 * 1. Redistributions of source code must retain the above copyright
33 * notice, this list of conditions and the following disclaimer.
34 * 2. Redistributions in binary form must reproduce the above copyright
35 * notice, this list of conditions and the following disclaimer in the
36 * documentation and/or other materials provided with the distribution.
37 *
38 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
39 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
40 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
41 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
42 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
43 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
44 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
45 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
46 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
47 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
48 * SUCH DAMAGE.
49 *
50 * $FreeBSD: src/lib/libc_r/uthread/uthread_rwlock.c,v 1.6 2001/04/10 04:19:20 deischen Exp $
51 */
52
53 /*
54 * POSIX Pthread Library
55 * -- Read Write Lock support
56 * 4/24/02: A. Ramesh
57 * Ported from FreeBSD
58 */
59
60 #include "pthread_internals.h"
61
62 /* maximum number of times a read lock may be obtained */
63 #define MAX_READ_LOCKS (INT_MAX - 1)
64
65 int
66 pthread_rwlock_destroy(pthread_rwlock_t *rwlock)
67 {
68
69 if (rwlock->sig != _PTHREAD_RWLOCK_SIG) {
70 return(EINVAL);
71 } else {
72 pthread_mutex_destroy(&rwlock->lock);
73 pthread_cond_destroy(&rwlock->read_signal);
74 pthread_cond_destroy(&rwlock->write_signal);
75 rwlock->sig = _PTHREAD_NO_SIG;
76 return(ESUCCESS);
77 }
78 }
79
80 int
81 pthread_rwlock_init(pthread_rwlock_t *rwlock, const pthread_rwlockattr_t *attr)
82 {
83 int ret;
84
85 /* initialize the lock */
86 if ((ret = pthread_mutex_init(&rwlock->lock, NULL)) != 0)
87 return(ret);
88 else {
89 /* initialize the read condition signal */
90 ret = pthread_cond_init(&rwlock->read_signal, NULL);
91
92 if (ret != 0) {
93 pthread_mutex_destroy(&rwlock->lock);
94 return(ret);
95 } else {
96 /* initialize the write condition signal */
97 ret = pthread_cond_init(&rwlock->write_signal, NULL);
98
99 if (ret != 0) {
100 pthread_cond_destroy(&rwlock->read_signal);
101 pthread_mutex_destroy(&rwlock->lock);
102 return(ret);
103 } else {
104 /* success */
105 rwlock->state = 0;
106 rwlock->blocked_writers = 0;
107 rwlock->sig = _PTHREAD_RWLOCK_SIG;
108 return(ESUCCESS);
109 }
110 }
111 }
112 }
113
114 int
115 pthread_rwlock_rdlock(pthread_rwlock_t *rwlock)
116 {
117 int ret;
118
119 if (rwlock->sig == _PTHREAD_RWLOCK_SIG_init) {
120 if ((ret = pthread_rwlock_init(rwlock, NULL)) != 0) {
121 return(ret);
122 }
123 }
124
125 if (rwlock->sig != _PTHREAD_RWLOCK_SIG)
126 return(EINVAL);
127 /* grab the monitor lock */
128 if ((ret = pthread_mutex_lock(&rwlock->lock)) != 0)
129 return(ret);
130
131 /* give writers priority over readers */
132 while (rwlock->blocked_writers || rwlock->state < 0) {
133 ret = pthread_cond_wait(&rwlock->read_signal, &rwlock->lock);
134
135 if (ret != 0) {
136 /* can't do a whole lot if this fails */
137 pthread_mutex_unlock(&rwlock->lock);
138 return(ret);
139 }
140 }
141
142 /* check lock count */
143 if (rwlock->state == MAX_READ_LOCKS)
144 ret = EAGAIN;
145 else
146 ++rwlock->state; /* indicate we are locked for reading */
147
148 /*
149 * Something is really wrong if this call fails. Returning
150 * error won't do because we've already obtained the read
151 * lock. Decrementing 'state' is no good because we probably
152 * don't have the monitor lock.
153 */
154 pthread_mutex_unlock(&rwlock->lock);
155
156 return(ret);
157 }
158
159 int
160 pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock)
161 {
162 int ret;
163
164 /* check for static initialization */
165 if (rwlock->sig == _PTHREAD_RWLOCK_SIG_init) {
166 if ((ret = pthread_rwlock_init(rwlock, NULL)) != 0) {
167 return(ret);
168 }
169 }
170
171 if (rwlock->sig != _PTHREAD_RWLOCK_SIG)
172 return(EINVAL);
173 /* grab the monitor lock */
174 if ((ret = pthread_mutex_lock(&rwlock->lock)) != 0)
175 return(ret);
176
177 /* give writers priority over readers */
178 if (rwlock->blocked_writers || rwlock->state < 0)
179 ret = EBUSY;
180 else if (rwlock->state == MAX_READ_LOCKS)
181 ret = EAGAIN; /* too many read locks acquired */
182 else
183 ++rwlock->state; /* indicate we are locked for reading */
184
185 /* see the comment on this in pthread_rwlock_rdlock */
186 pthread_mutex_unlock(&rwlock->lock);
187
188 return(ret);
189 }
190
191 int
192 pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock)
193 {
194 int ret;
195
196 /* check for static initialization */
197 if (rwlock->sig == _PTHREAD_RWLOCK_SIG_init) {
198 if ((ret = pthread_rwlock_init(rwlock, NULL)) != 0) {
199 return(ret);
200 }
201 }
202
203 if (rwlock->sig != _PTHREAD_RWLOCK_SIG)
204 return(EINVAL);
205 /* grab the monitor lock */
206 if ((ret = pthread_mutex_lock(&rwlock->lock)) != 0)
207 return(ret);
208
209 if (rwlock->state != 0)
210 ret = EBUSY;
211 else
212 /* indicate we are locked for writing */
213 rwlock->state = -1;
214
215 /* see the comment on this in pthread_rwlock_rdlock */
216 pthread_mutex_unlock(&rwlock->lock);
217
218 return(ret);
219 }
220
221 int
222 pthread_rwlock_unlock(pthread_rwlock_t *rwlock)
223 {
224 int ret;
225
226 if (rwlock->sig != _PTHREAD_RWLOCK_SIG)
227 return(EINVAL);
228 /* grab the monitor lock */
229 if ((ret = pthread_mutex_lock(&rwlock->lock)) != 0)
230 return(ret);
231
232 if (rwlock->state > 0) {
233 if (--rwlock->state == 0 && rwlock->blocked_writers)
234 ret = pthread_cond_signal(&rwlock->write_signal);
235 } else if (rwlock->state < 0) {
236 rwlock->state = 0;
237
238 if (rwlock->blocked_writers)
239 ret = pthread_cond_signal(&rwlock->write_signal);
240 else
241 ret = pthread_cond_broadcast(&rwlock->read_signal);
242 } else
243 ret = EINVAL;
244
245 /* see the comment on this in pthread_rwlock_rdlock */
246 pthread_mutex_unlock(&rwlock->lock);
247
248 return(ret);
249 }
250
251 int
252 pthread_rwlock_wrlock(pthread_rwlock_t *rwlock)
253 {
254 int ret;
255
256 /* check for static initialization */
257 if (rwlock->sig == _PTHREAD_RWLOCK_SIG_init) {
258 if ((ret = pthread_rwlock_init(rwlock, NULL)) != 0) {
259 return(ret);
260 }
261 }
262
263 if (rwlock->sig != _PTHREAD_RWLOCK_SIG)
264 return(EINVAL);
265 /* grab the monitor lock */
266 if ((ret = pthread_mutex_lock(&rwlock->lock)) != 0)
267 return(ret);
268
269 while (rwlock->state != 0) {
270 ++rwlock->blocked_writers;
271
272 ret = pthread_cond_wait(&rwlock->write_signal, &rwlock->lock);
273
274 if (ret != 0) {
275 --rwlock->blocked_writers;
276 pthread_mutex_unlock(&rwlock->lock);
277 return(ret);
278 }
279
280 --rwlock->blocked_writers;
281 }
282
283 /* indicate we are locked for writing */
284 rwlock->state = -1;
285
286 /* see the comment on this in pthread_rwlock_rdlock */
287 pthread_mutex_unlock(&rwlock->lock);
288
289 return(ret);
290 }
291
292 int
293 pthread_rwlockattr_init(pthread_rwlockattr_t *attr)
294 {
295 attr->sig = _PTHREAD_RWLOCK_ATTR_SIG;
296 attr->pshared = PTHREAD_PROCESS_PRIVATE;
297 return (ESUCCESS);
298 }
299
300 int
301 pthread_rwlockattr_destroy(pthread_rwlockattr_t *attr)
302 {
303 attr->sig = _PTHREAD_NO_SIG; /* Uninitialized */
304 attr->pshared = 0;
305 return (ESUCCESS);
306 }
307
308 int
309 pthread_rwlockattr_getpshared(const pthread_rwlockattr_t *attr,
310 int *pshared)
311 {
312 if (attr->sig == _PTHREAD_RWLOCK_ATTR_SIG)
313 {
314 /* *pshared = (int)attr->pshared; */
315 *pshared = (int)PTHREAD_PROCESS_PRIVATE;
316 return (ESUCCESS);
317 } else
318 {
319 return (EINVAL); /* Not an initialized 'attribute' structure */
320 }
321 }
322
323
324 int
325 pthread_rwlockattr_setpshared(pthread_rwlockattr_t * attr, int pshared)
326 {
327 if (attr->sig == _PTHREAD_RWLOCK_ATTR_SIG)
328 {
329 if ( pshared == PTHREAD_PROCESS_PRIVATE)
330 {
331 attr->pshared = pshared ;
332 return (ESUCCESS);
333 } else
334 {
335 return (EINVAL); /* Invalid parameter */
336 }
337 } else
338 {
339 return (EINVAL); /* Not an initialized 'attribute' structure */
340 }
341
342 }
343