]> git.saurik.com Git - apple/libc.git/blob - pthreads/pthread_rwlock.c
Libc-498.1.1.tar.gz
[apple/libc.git] / pthreads / pthread_rwlock.c
1 /*
2 * Copyright (c) 2000-2003, 2007 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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 */
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 extern int __unix_conforming;
60
61 #include "plockstat.h"
62 #define READ_LOCK_PLOCKSTAT 0
63 #define WRITE_LOCK_PLOCKSTAT 1
64
65 #define BLOCK_FAIL_PLOCKSTAT 0
66 #define BLOCK_SUCCESS_PLOCKSTAT 1
67
68 /* maximum number of times a read lock may be obtained */
69 #define MAX_READ_LOCKS (INT_MAX - 1)
70
71
72 #ifndef BUILDING_VARIANT /* [ */
73
74
75 int
76 pthread_rwlockattr_init(pthread_rwlockattr_t *attr)
77 {
78 attr->sig = _PTHREAD_RWLOCK_ATTR_SIG;
79 attr->pshared = _PTHREAD_DEFAULT_PSHARED;
80 return (0);
81 }
82
83 int
84 pthread_rwlockattr_destroy(pthread_rwlockattr_t *attr)
85 {
86 attr->sig = _PTHREAD_NO_SIG; /* Uninitialized */
87 attr->pshared = 0;
88 return (0);
89 }
90
91 int
92 pthread_rwlockattr_getpshared(const pthread_rwlockattr_t *attr,
93 int *pshared)
94 {
95 if (attr->sig == _PTHREAD_RWLOCK_ATTR_SIG)
96 {
97 *pshared = (int)attr->pshared;
98 return (0);
99 } else
100 {
101 return (EINVAL); /* Not an initialized 'attribute' structure */
102 }
103 }
104
105 /* Temp: untill pshared is fixed right */
106 #ifdef PR_5243343
107 /* 5243343 - temporary hack to detect if we are running the conformance test */
108 extern int PR_5243343_flag;
109 #endif /* PR_5243343 */
110
111 int
112 pthread_rwlockattr_setpshared(pthread_rwlockattr_t * attr, int pshared)
113 {
114 if (attr->sig == _PTHREAD_RWLOCK_ATTR_SIG)
115 {
116 #if __DARWIN_UNIX03
117 #ifdef PR_5243343
118 if (( pshared == PTHREAD_PROCESS_PRIVATE) || (pshared == PTHREAD_PROCESS_SHARED && PR_5243343_flag))
119 #else /* !PR_5243343 */
120 if (( pshared == PTHREAD_PROCESS_PRIVATE) || (pshared == PTHREAD_PROCESS_SHARED))
121 #endif /* PR_5243343 */
122 #else /* __DARWIN_UNIX03 */
123 if ( pshared == PTHREAD_PROCESS_PRIVATE)
124 #endif /* __DARWIN_UNIX03 */
125 {
126 attr->pshared = pshared ;
127 return (0);
128 } else
129 {
130 return (EINVAL); /* Invalid parameter */
131 }
132 } else
133 {
134 return (EINVAL); /* Not an initialized 'attribute' structure */
135 }
136
137 }
138
139 #endif /* !BUILDING_VARIANT ] */
140
141 int
142 pthread_rwlock_destroy(pthread_rwlock_t *rwlock)
143 {
144 int ret;
145
146 if (rwlock->sig != _PTHREAD_RWLOCK_SIG) {
147 return(EINVAL);
148 } else {
149 #if __DARWIN_UNIX03
150 /* grab the monitor lock */
151 if ((ret = pthread_mutex_lock(&rwlock->lock)) != 0)
152 return(ret);
153
154 if (rwlock->state != 0) {
155 pthread_mutex_unlock(&rwlock->lock);
156 return(EBUSY);
157 }
158 pthread_mutex_unlock(&rwlock->lock);
159 #endif /* __DARWIN_UNIX03 */
160
161 pthread_mutex_destroy(&rwlock->lock);
162 pthread_cond_destroy(&rwlock->read_signal);
163 pthread_cond_destroy(&rwlock->write_signal);
164 rwlock->sig = _PTHREAD_NO_SIG;
165 return(0);
166 }
167 }
168
169 int
170 pthread_rwlock_init(pthread_rwlock_t *rwlock, const pthread_rwlockattr_t *attr)
171 {
172 int ret;
173 #if __DARWIN_UNIX03
174 if (attr && (attr->sig != _PTHREAD_RWLOCK_ATTR_SIG)) {
175 return(EINVAL);
176 }
177 /* if already inited check whether it is in use, then return EBUSY */
178 if ((rwlock->sig == _PTHREAD_RWLOCK_SIG) && (rwlock->state !=0 )) {
179 return(EBUSY);
180 }
181 #endif /* __DARWIN_UNIX03 */
182
183 /* initialize the lock */
184 if ((ret = pthread_mutex_init(&rwlock->lock, NULL)) != 0)
185 return(ret);
186 else {
187 /* initialize the read condition signal */
188 ret = pthread_cond_init(&rwlock->read_signal, NULL);
189
190 if (ret != 0) {
191 pthread_mutex_destroy(&rwlock->lock);
192 return(ret);
193 } else {
194 /* initialize the write condition signal */
195 ret = pthread_cond_init(&rwlock->write_signal, NULL);
196
197 if (ret != 0) {
198 pthread_cond_destroy(&rwlock->read_signal);
199 pthread_mutex_destroy(&rwlock->lock);
200 return(ret);
201 } else {
202 /* success */
203 rwlock->state = 0;
204 rwlock->owner = (pthread_t)0;
205 rwlock->blocked_writers = 0;
206 if (attr)
207 rwlock->pshared = attr->pshared;
208 else
209 rwlock->pshared = _PTHREAD_DEFAULT_PSHARED;
210
211 rwlock->sig = _PTHREAD_RWLOCK_SIG;
212 return(0);
213 }
214 }
215 }
216 }
217
218 int
219 pthread_rwlock_rdlock(pthread_rwlock_t *rwlock)
220 {
221 int ret;
222 #if __DARWIN_UNIX03
223 pthread_t self = pthread_self();
224 #endif
225
226 if (rwlock->sig == _PTHREAD_RWLOCK_SIG_init) {
227 if ((ret = pthread_rwlock_init(rwlock, NULL)) != 0) {
228 PLOCKSTAT_RW_ERROR(rwlock, READ_LOCK_PLOCKSTAT, ret);
229 return(ret);
230 }
231 }
232
233 if (rwlock->sig != _PTHREAD_RWLOCK_SIG) {
234 PLOCKSTAT_RW_ERROR(rwlock, READ_LOCK_PLOCKSTAT, EINVAL);
235 return(EINVAL);
236 }
237 /* grab the monitor lock */
238 if ((ret = pthread_mutex_lock(&rwlock->lock)) != 0) {
239 PLOCKSTAT_RW_ERROR(rwlock, READ_LOCK_PLOCKSTAT, ret);
240 return(ret);
241 }
242
243 #if __DARWIN_UNIX03
244 if ((rwlock->state < 0) && (rwlock->owner == self)) {
245 pthread_mutex_unlock(&rwlock->lock);
246 PLOCKSTAT_RW_ERROR(rwlock, READ_LOCK_PLOCKSTAT, EDEADLK);
247 return(EDEADLK);
248 }
249 #endif /* __DARWIN_UNIX03 */
250
251 #if __DARWIN_UNIX03
252 while (rwlock->blocked_writers || ((rwlock->state < 0) && (rwlock->owner != self)))
253 #else /* __DARWIN_UNIX03 */
254 while (rwlock->blocked_writers || rwlock->state < 0)
255
256 #endif /* __DARWIN_UNIX03 */
257 {
258 /* give writers priority over readers */
259 PLOCKSTAT_RW_BLOCK(rwlock, READ_LOCK_PLOCKSTAT);
260 ret = pthread_cond_wait(&rwlock->read_signal, &rwlock->lock);
261
262 if (ret != 0) {
263 /* can't do a whole lot if this fails */
264 pthread_mutex_unlock(&rwlock->lock);
265 PLOCKSTAT_RW_BLOCKED(rwlock, READ_LOCK_PLOCKSTAT, BLOCK_FAIL_PLOCKSTAT);
266 PLOCKSTAT_RW_ERROR(rwlock, READ_LOCK_PLOCKSTAT, ret);
267 return(ret);
268 }
269
270 PLOCKSTAT_RW_BLOCKED(rwlock, READ_LOCK_PLOCKSTAT, BLOCK_SUCCESS_PLOCKSTAT);
271 }
272
273 /* check lock count */
274 if (rwlock->state == MAX_READ_LOCKS) {
275 ret = EAGAIN;
276 PLOCKSTAT_RW_ERROR(rwlock, READ_LOCK_PLOCKSTAT, ret);
277 }
278 else {
279 ++rwlock->state; /* indicate we are locked for reading */
280 PLOCKSTAT_RW_ACQUIRE(rwlock, READ_LOCK_PLOCKSTAT);
281 }
282
283 /*
284 * Something is really wrong if this call fails. Returning
285 * error won't do because we've already obtained the read
286 * lock. Decrementing 'state' is no good because we probably
287 * don't have the monitor lock.
288 */
289 pthread_mutex_unlock(&rwlock->lock);
290
291 return(ret);
292 }
293
294 int
295 pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock)
296 {
297 int ret;
298 #if __DARWIN_UNIX03
299 pthread_t self = pthread_self();
300 #endif
301
302 /* check for static initialization */
303 if (rwlock->sig == _PTHREAD_RWLOCK_SIG_init) {
304 if ((ret = pthread_rwlock_init(rwlock, NULL)) != 0) {
305 PLOCKSTAT_RW_ERROR(rwlock, READ_LOCK_PLOCKSTAT, ret);
306 return(ret);
307 }
308 }
309
310 if (rwlock->sig != _PTHREAD_RWLOCK_SIG) {
311 PLOCKSTAT_RW_ERROR(rwlock, READ_LOCK_PLOCKSTAT, EINVAL);
312 return(EINVAL);
313 }
314 /* grab the monitor lock */
315 if ((ret = pthread_mutex_lock(&rwlock->lock)) != 0) {
316 PLOCKSTAT_RW_ERROR(rwlock, READ_LOCK_PLOCKSTAT, ret);
317 return(ret);
318 }
319
320 /* give writers priority over readers */
321 if (rwlock->blocked_writers || rwlock->state < 0) {
322 ret = EBUSY;
323 PLOCKSTAT_RW_ERROR(rwlock, READ_LOCK_PLOCKSTAT, ret);
324 }
325 else if (rwlock->state == MAX_READ_LOCKS) {
326 ret = EAGAIN; /* too many read locks acquired */
327 PLOCKSTAT_RW_ERROR(rwlock, READ_LOCK_PLOCKSTAT, ret);
328 }
329 else {
330 ++rwlock->state; /* indicate we are locked for reading */
331 PLOCKSTAT_RW_ACQUIRE(rwlock, READ_LOCK_PLOCKSTAT);
332 }
333
334 /* see the comment on this in pthread_rwlock_rdlock */
335 pthread_mutex_unlock(&rwlock->lock);
336
337 return(ret);
338 }
339
340 int
341 pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock)
342 {
343 int ret;
344 #if __DARWIN_UNIX03
345 pthread_t self = pthread_self();
346 #endif /* __DARWIN_UNIX03 */
347
348 /* check for static initialization */
349 if (rwlock->sig == _PTHREAD_RWLOCK_SIG_init) {
350 if ((ret = pthread_rwlock_init(rwlock, NULL)) != 0) {
351 PLOCKSTAT_RW_ERROR(rwlock, WRITE_LOCK_PLOCKSTAT, ret);
352 return(ret);
353 }
354 }
355
356 if (rwlock->sig != _PTHREAD_RWLOCK_SIG) {
357 PLOCKSTAT_RW_ERROR(rwlock, WRITE_LOCK_PLOCKSTAT, EINVAL);
358 return(EINVAL);
359 }
360 /* grab the monitor lock */
361 if ((ret = pthread_mutex_lock(&rwlock->lock)) != 0) {
362 PLOCKSTAT_RW_ERROR(rwlock, WRITE_LOCK_PLOCKSTAT, ret);
363 return(ret);
364 }
365
366
367 if (rwlock->state != 0) {
368 ret = EBUSY;
369 PLOCKSTAT_RW_ERROR(rwlock, WRITE_LOCK_PLOCKSTAT, ret);
370 }
371 else {
372 /* indicate we are locked for writing */
373 rwlock->state = -1;
374 #if __DARWIN_UNIX03
375 rwlock->owner = self;
376 #endif /* __DARWIN_UNIX03 */
377 PLOCKSTAT_RW_ACQUIRE(rwlock, WRITE_LOCK_PLOCKSTAT);
378 }
379
380 /* see the comment on this in pthread_rwlock_rdlock */
381 pthread_mutex_unlock(&rwlock->lock);
382
383 return(ret);
384 }
385
386 int
387 pthread_rwlock_unlock(pthread_rwlock_t *rwlock)
388 {
389 int ret;
390 int writer = (rwlock < 0) ? 1:0;
391 #if __DARWIN_UNIX03
392 pthread_t self = pthread_self();
393 #endif /* __DARWIN_UNIX03 */
394
395 if (rwlock->sig != _PTHREAD_RWLOCK_SIG) {
396 PLOCKSTAT_RW_ERROR(rwlock, writer, EINVAL);
397 return(EINVAL);
398 }
399 /* grab the monitor lock */
400 if ((ret = pthread_mutex_lock(&rwlock->lock)) != 0) {
401 PLOCKSTAT_RW_ERROR(rwlock, writer, ret);
402 return(ret);
403 }
404
405 if (rwlock->state > 0) {
406 if (--rwlock->state == 0 && rwlock->blocked_writers)
407 ret = pthread_cond_signal(&rwlock->write_signal);
408 } else if (rwlock->state < 0) {
409 rwlock->state = 0;
410 #if __DARWIN_UNIX03
411 rwlock->owner = (pthread_t)0;
412 #endif /* __DARWIN_UNIX03 */
413
414 if (rwlock->blocked_writers)
415 ret = pthread_cond_signal(&rwlock->write_signal);
416 else
417 ret = pthread_cond_broadcast(&rwlock->read_signal);
418 } else
419 ret = EINVAL;
420
421 if (ret == 0) {
422 PLOCKSTAT_RW_RELEASE(rwlock, writer);
423 } else {
424 PLOCKSTAT_RW_ERROR(rwlock, writer, ret);
425 }
426
427 /* see the comment on this in pthread_rwlock_rdlock */
428 pthread_mutex_unlock(&rwlock->lock);
429
430 return(ret);
431 }
432
433 int
434 pthread_rwlock_wrlock(pthread_rwlock_t *rwlock)
435 {
436 int ret;
437 #if __DARWIN_UNIX03
438 pthread_t self = pthread_self();
439 #endif /* __DARWIN_UNIX03 */
440
441 /* check for static initialization */
442 if (rwlock->sig == _PTHREAD_RWLOCK_SIG_init) {
443 if ((ret = pthread_rwlock_init(rwlock, NULL)) != 0) {
444 PLOCKSTAT_RW_ERROR(rwlock, WRITE_LOCK_PLOCKSTAT, ret);
445 return(ret);
446 }
447 }
448
449 if (rwlock->sig != _PTHREAD_RWLOCK_SIG) {
450 PLOCKSTAT_RW_ERROR(rwlock, WRITE_LOCK_PLOCKSTAT, EINVAL);
451 return(EINVAL);
452 }
453 /* grab the monitor lock */
454 if ((ret = pthread_mutex_lock(&rwlock->lock)) != 0) {
455 PLOCKSTAT_RW_ERROR(rwlock, WRITE_LOCK_PLOCKSTAT, ret);
456 return(ret);
457 }
458
459 #if __DARWIN_UNIX03
460 if ((rwlock->state < 0) && (rwlock->owner == self)) {
461 pthread_mutex_unlock(&rwlock->lock);
462 PLOCKSTAT_RW_ERROR(rwlock, WRITE_LOCK_PLOCKSTAT, EDEADLK);
463 return(EDEADLK);
464 }
465 #endif /* __DARWIN_UNIX03 */
466 while (rwlock->state != 0) {
467 ++rwlock->blocked_writers;
468
469 PLOCKSTAT_RW_BLOCK(rwlock, WRITE_LOCK_PLOCKSTAT);
470 ret = pthread_cond_wait(&rwlock->write_signal, &rwlock->lock);
471
472 if (ret != 0) {
473 --rwlock->blocked_writers;
474 pthread_mutex_unlock(&rwlock->lock);
475 PLOCKSTAT_RW_BLOCKED(rwlock, WRITE_LOCK_PLOCKSTAT, BLOCK_FAIL_PLOCKSTAT);
476 PLOCKSTAT_RW_ERROR(rwlock, WRITE_LOCK_PLOCKSTAT, ret);
477 return(ret);
478 }
479
480 PLOCKSTAT_RW_BLOCKED(rwlock, WRITE_LOCK_PLOCKSTAT, BLOCK_SUCCESS_PLOCKSTAT);
481
482 --rwlock->blocked_writers;
483 }
484
485 /* indicate we are locked for writing */
486 rwlock->state = -1;
487 #if __DARWIN_UNIX03
488 rwlock->owner = self;
489 #endif /* __DARWIN_UNIX03 */
490 PLOCKSTAT_RW_ACQUIRE(rwlock, WRITE_LOCK_PLOCKSTAT);
491
492 /* see the comment on this in pthread_rwlock_rdlock */
493 pthread_mutex_unlock(&rwlock->lock);
494
495 return(ret);
496 }
497
498