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