VirtualBox

source: vbox/trunk/src/VBox/Runtime/r3/posix/semrw-posix.cpp@ 25536

Last change on this file since 25536 was 25524, checked in by vboxsync, 15 years ago

semrw-posix.cpp,tstRTSemRW: added an insufficient workaround for the glibc pthread_rwlock_unlock issue.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 17.6 KB
Line 
1/* $Id: semrw-posix.cpp 25524 2009-12-20 16:56:30Z vboxsync $ */
2/** @file
3 * IPRT - Read-Write Semaphore, POSIX.
4 */
5
6/*
7 * Copyright (C) 2006-2007 Sun Microsystems, Inc.
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.215389.xyz. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 *
26 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
27 * Clara, CA 95054 USA or visit http://www.sun.com if you need
28 * additional information or have any questions.
29 */
30
31/*******************************************************************************
32* Header Files *
33*******************************************************************************/
34#include <iprt/semaphore.h>
35#include "internal/iprt.h"
36
37#include <iprt/asm.h>
38#include <iprt/assert.h>
39#include <iprt/err.h>
40#include <iprt/lockvalidator.h>
41#include <iprt/mem.h>
42#include <iprt/thread.h>
43
44#include <errno.h>
45#include <pthread.h>
46#include <unistd.h>
47#include <sys/time.h>
48
49#include "internal/magics.h"
50#include "internal/strict.h"
51
52
53/*******************************************************************************
54* Defined Constants And Macros *
55*******************************************************************************/
56/** @todo move this to r3/posix/something.h. */
57#ifdef RT_OS_SOLARIS
58# define ATOMIC_GET_PTHREAD_T(pvVar, pThread) ASMAtomicReadSize(pvVar, pThread)
59# define ATOMIC_SET_PTHREAD_T(pvVar, pThread) ASMAtomicWriteSize(pvVar, pThread)
60#else
61AssertCompileSize(pthread_t, sizeof(void *));
62# define ATOMIC_GET_PTHREAD_T(pvVar, pThread) do { *(pThread) = (pthread_t)ASMAtomicReadPtr((void *volatile *)pvVar); } while (0)
63# define ATOMIC_SET_PTHREAD_T(pvVar, pThread) ASMAtomicWritePtr((void *volatile *)pvVar, (void *)pThread)
64#endif
65
66
67/*******************************************************************************
68* Structures and Typedefs *
69*******************************************************************************/
70/** Posix internal representation of a read-write semaphore. */
71struct RTSEMRWINTERNAL
72{
73 /** The usual magic. (RTSEMRW_MAGIC) */
74 uint32_t u32Magic;
75 /** The number of readers.
76 * (For preventing screwing up the lock on linux). */
77 uint32_t volatile cReaders;
78 /** Number of write recursions. */
79 uint32_t cWrites;
80 /** Number of read recursions by the writer. */
81 uint32_t cWriterReads;
82 /** The write owner of the lock. */
83 volatile pthread_t Writer;
84 /** pthread rwlock. */
85 pthread_rwlock_t RWLock;
86#ifdef RTSEMRW_STRICT
87 /** The validator record for the writer. */
88 RTLOCKVALIDATORREC ValidatorWrite;
89 /** The validator record for the readers. */
90 RTLOCKVALIDATORSHARED ValidatorRead;
91#endif
92};
93
94
95RTDECL(int) RTSemRWCreate(PRTSEMRW pRWSem)
96{
97 int rc;
98
99 /*
100 * Allocate handle.
101 */
102 struct RTSEMRWINTERNAL *pThis = (struct RTSEMRWINTERNAL *)RTMemAlloc(sizeof(struct RTSEMRWINTERNAL));
103 if (pThis)
104 {
105 /*
106 * Create the rwlock.
107 */
108 pthread_rwlockattr_t Attr;
109 rc = pthread_rwlockattr_init(&Attr);
110 if (!rc)
111 {
112 rc = pthread_rwlock_init(&pThis->RWLock, &Attr);
113 if (!rc)
114 {
115 pThis->u32Magic = RTSEMRW_MAGIC;
116 pThis->cReaders = 0;
117 pThis->cWrites = 0;
118 pThis->cWriterReads = 0;
119 pThis->Writer = (pthread_t)-1;
120#ifdef RTSEMRW_STRICT
121 RTLockValidatorRecInit(&pThis->ValidatorWrite, NIL_RTLOCKVALIDATORCLASS, RTLOCKVALIDATOR_SUB_CLASS_NONE, NULL, pThis);
122 RTLockValidatorSharedRecInit(&pThis->ValidatorRead, NIL_RTLOCKVALIDATORCLASS, RTLOCKVALIDATOR_SUB_CLASS_NONE, NULL, pThis);
123#endif
124 *pRWSem = pThis;
125 return VINF_SUCCESS;
126 }
127 }
128
129 rc = RTErrConvertFromErrno(rc);
130 RTMemFree(pThis);
131 }
132 else
133 rc = VERR_NO_MEMORY;
134
135 return rc;
136}
137
138
139RTDECL(int) RTSemRWDestroy(RTSEMRW RWSem)
140{
141 /*
142 * Validate input, nil handle is fine.
143 */
144 struct RTSEMRWINTERNAL *pThis = RWSem;
145 if (pThis == NIL_RTSEMRW)
146 return VINF_SUCCESS;
147 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
148 AssertMsgReturn(pThis->u32Magic == RTSEMRW_MAGIC,
149 ("pThis=%p u32Magic=%#x\n", pThis, pThis->u32Magic),
150 VERR_INVALID_HANDLE);
151 Assert(pThis->Writer == (pthread_t)-1);
152 Assert(!pThis->cReaders);
153 Assert(!pThis->cWrites);
154 Assert(!pThis->cWriterReads);
155
156 /*
157 * Try destroy it.
158 */
159 AssertReturn(ASMAtomicCmpXchgU32(&pThis->u32Magic, ~RTSEMRW_MAGIC, RTSEMRW_MAGIC), VERR_INVALID_HANDLE);
160 int rc = pthread_rwlock_destroy(&pThis->RWLock);
161 if (!rc)
162 {
163#ifdef RTSEMRW_STRICT
164 RTLockValidatorSharedRecDelete(&pThis->ValidatorRead);
165 RTLockValidatorRecDelete(&pThis->ValidatorWrite);
166#endif
167 RTMemFree(pThis);
168 rc = VINF_SUCCESS;
169 }
170 else
171 {
172 ASMAtomicWriteU32(&pThis->u32Magic, RTSEMRW_MAGIC);
173 AssertMsgFailed(("Failed to destroy read-write sem %p, rc=%d.\n", RWSem, rc));
174 rc = RTErrConvertFromErrno(rc);
175 }
176
177 return rc;
178}
179
180
181RTDECL(int) RTSemRWRequestRead(RTSEMRW RWSem, unsigned cMillies)
182{
183 PRTLOCKVALIDATORSRCPOS pSrcPos = NULL;
184
185 /*
186 * Validate input.
187 */
188 struct RTSEMRWINTERNAL *pThis = RWSem;
189 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
190 AssertMsgReturn(pThis->u32Magic == RTSEMRW_MAGIC,
191 ("pThis=%p u32Magic=%#x\n", pThis, pThis->u32Magic),
192 VERR_INVALID_HANDLE);
193
194 /*
195 * Check if it's the writer (implement write+read recursion).
196 */
197 pthread_t Self = pthread_self();
198 pthread_t Writer;
199 ATOMIC_GET_PTHREAD_T(&pThis->Writer, &Writer);
200 if (Writer == Self)
201 {
202#ifdef RTSEMRW_STRICT
203 int rc9 = RTLockValidatorRecordReadWriteRecursion(&pThis->ValidatorWrite, &pThis->ValidatorRead, pSrcPos);
204 if (RT_FAILURE(rc9))
205 return rc9;
206#endif
207 Assert(pThis->cWriterReads < INT32_MAX);
208 pThis->cWriterReads++;
209 return VINF_SUCCESS;
210 }
211
212 /*
213 * Try lock it.
214 */
215#ifdef RTSEMRW_STRICT
216 RTTHREAD hThreadSelf = RTThreadSelfAutoAdopt();
217#else
218 RTTHREAD hThreadSelf = RTThreadSelf();
219#endif
220 if (cMillies > 0)
221 {
222#ifdef RTSEMRW_STRICT
223 int rc9 = RTLockValidatorCheckReadOrderBlocking(&pThis->ValidatorRead, &pThis->ValidatorWrite,
224 hThreadSelf, RTTHREADSTATE_RW_READ, false, pSrcPos);
225 if (RT_FAILURE(rc9))
226 return rc9;
227#endif
228 RTThreadBlocking(hThreadSelf, RTTHREADSTATE_RW_READ);
229 }
230
231 if (cMillies == RT_INDEFINITE_WAIT)
232 {
233 /* take rwlock */
234 int rc = pthread_rwlock_rdlock(&pThis->RWLock);
235 RTThreadUnblocked(hThreadSelf, RTTHREADSTATE_RW_READ);
236 if (rc)
237 {
238 AssertMsgFailed(("Failed read lock read-write sem %p, rc=%d.\n", RWSem, rc));
239 return RTErrConvertFromErrno(rc);
240 }
241 }
242 else
243 {
244#ifdef RT_OS_DARWIN
245 AssertMsgFailed(("Not implemented on Darwin yet because of incomplete pthreads API."));
246 return VERR_NOT_IMPLEMENTED;
247
248#else /* !RT_OS_DARWIN */
249 /*
250 * Get current time and calc end of wait time.
251 */
252 struct timespec ts = {0,0};
253 clock_gettime(CLOCK_REALTIME, &ts);
254 if (cMillies != 0)
255 {
256 ts.tv_nsec += (cMillies % 1000) * 1000000;
257 ts.tv_sec += cMillies / 1000;
258 if (ts.tv_nsec >= 1000000000)
259 {
260 ts.tv_nsec -= 1000000000;
261 ts.tv_sec++;
262 }
263 }
264
265 /* take rwlock */
266 int rc = pthread_rwlock_timedrdlock(&pThis->RWLock, &ts);
267 RTThreadUnblocked(hThreadSelf, RTTHREADSTATE_RW_READ);
268 if (rc)
269 {
270 AssertMsg(rc == ETIMEDOUT, ("Failed read lock read-write sem %p, rc=%d.\n", RWSem, rc));
271 return RTErrConvertFromErrno(rc);
272 }
273#endif /* !RT_OS_DARWIN */
274 }
275
276 ASMAtomicIncU32(&pThis->cReaders);
277#ifdef RTSEMRW_STRICT
278 RTLockValidatorAddReadOwner(&pThis->ValidatorRead, hThreadSelf, pSrcPos);
279#endif
280 return VINF_SUCCESS;
281}
282
283
284RTDECL(int) RTSemRWRequestReadNoResume(RTSEMRW RWSem, unsigned cMillies)
285{
286 /* EINTR isn't returned by the wait functions we're using. */
287 return RTSemRWRequestRead(RWSem, cMillies);
288}
289
290
291RTDECL(int) RTSemRWReleaseRead(RTSEMRW RWSem)
292{
293 /*
294 * Validate input.
295 */
296 struct RTSEMRWINTERNAL *pThis = RWSem;
297 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
298 AssertMsgReturn(pThis->u32Magic == RTSEMRW_MAGIC,
299 ("pThis=%p u32Magic=%#x\n", pThis, pThis->u32Magic),
300 VERR_INVALID_HANDLE);
301
302 /*
303 * Check if it's the writer.
304 */
305 pthread_t Self = pthread_self();
306 pthread_t Writer;
307 ATOMIC_GET_PTHREAD_T(&pThis->Writer, &Writer);
308 if (Writer == Self)
309 {
310 AssertMsgReturn(pThis->cWriterReads > 0, ("pThis=%p\n", pThis), VERR_NOT_OWNER);
311#ifdef RTSEMRW_STRICT
312 int rc9 = RTLockValidatorUnwindReadWriteRecursion(&pThis->ValidatorWrite, &pThis->ValidatorRead);
313 if (RT_FAILURE(rc9))
314 return rc9;
315#endif
316 pThis->cWriterReads--;
317 return VINF_SUCCESS;
318 }
319
320 /*
321 * Try unlock it.
322 */
323#ifdef RTSEMRW_STRICT
324 int rc9 = RTLockValidatorCheckAndReleaseReadOwner(&pThis->ValidatorRead, RTThreadSelf());
325 if (RT_FAILURE(rc9))
326 return rc9;
327#endif
328#ifdef RT_OS_LINUX /* glibc (at least 2.8) may screw up when unlocking a lock we don't own. */
329 if (ASMAtomicReadU32(&pThis->cReaders) == 0)
330 {
331 AssertMsgFailed(("Not owner of %p\n", pThis));
332 return VERR_NOT_OWNER;
333 }
334#endif
335 ASMAtomicDecU32(&pThis->cReaders);
336 int rc = pthread_rwlock_unlock(&pThis->RWLock);
337 if (rc)
338 {
339 ASMAtomicIncU32(&pThis->cReaders);
340 AssertMsgFailed(("Failed read unlock read-write sem %p, rc=%d.\n", RWSem, rc));
341 return RTErrConvertFromErrno(rc);
342 }
343 return VINF_SUCCESS;
344}
345
346
347DECL_FORCE_INLINE(int) rtSemRWRequestWrite(RTSEMRW RWSem, unsigned cMillies, PCRTLOCKVALIDATORSRCPOS pSrcPos)
348{
349 /*
350 * Validate input.
351 */
352 struct RTSEMRWINTERNAL *pThis = RWSem;
353 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
354 AssertMsgReturn(pThis->u32Magic == RTSEMRW_MAGIC,
355 ("pThis=%p u32Magic=%#x\n", pThis, pThis->u32Magic),
356 VERR_INVALID_HANDLE);
357 /*
358 * Recursion?
359 */
360 pthread_t Self = pthread_self();
361 pthread_t Writer;
362 ATOMIC_GET_PTHREAD_T(&pThis->Writer, &Writer);
363 if (Writer == Self)
364 {
365#ifdef RTSEMRW_STRICT
366 int rc9 = RTLockValidatorRecordRecursion(&pThis->ValidatorWrite, pSrcPos);
367 if (RT_FAILURE(rc9))
368 return rc9;
369#endif
370 Assert(pThis->cWrites < INT32_MAX);
371 pThis->cWrites++;
372 return VINF_SUCCESS;
373 }
374
375 /*
376 * Try lock it.
377 */
378#ifdef RTSEMRW_STRICT
379 RTTHREAD hThreadSelf = RTThreadSelfAutoAdopt();
380#else
381 RTTHREAD hThreadSelf = RTThreadSelf();
382#endif
383 if (cMillies)
384 {
385#ifdef RTSEMRW_STRICT
386 int rc9 = RTLockValidatorCheckWriteOrderBlocking(&pThis->ValidatorWrite, &pThis->ValidatorRead,
387 hThreadSelf, RTTHREADSTATE_RW_WRITE, true, pSrcPos);
388 if (RT_FAILURE(rc9))
389 return rc9;
390#endif
391 RTThreadBlocking(hThreadSelf, RTTHREADSTATE_RW_WRITE);
392 }
393
394 if (cMillies == RT_INDEFINITE_WAIT)
395 {
396 /* take rwlock */
397 int rc = pthread_rwlock_wrlock(&pThis->RWLock);
398 RTThreadUnblocked(hThreadSelf, RTTHREADSTATE_RW_WRITE);
399 if (rc)
400 {
401 AssertMsgFailed(("Failed write lock read-write sem %p, rc=%d.\n", RWSem, rc));
402 return RTErrConvertFromErrno(rc);
403 }
404 }
405 else
406 {
407#ifdef RT_OS_DARWIN
408 AssertMsgFailed(("Not implemented on Darwin yet because of incomplete pthreads API."));
409 return VERR_NOT_IMPLEMENTED;
410#else /* !RT_OS_DARWIN */
411 /*
412 * Get current time and calc end of wait time.
413 */
414 struct timespec ts = {0,0};
415 clock_gettime(CLOCK_REALTIME, &ts);
416 if (cMillies != 0)
417 {
418 ts.tv_nsec += (cMillies % 1000) * 1000000;
419 ts.tv_sec += cMillies / 1000;
420 if (ts.tv_nsec >= 1000000000)
421 {
422 ts.tv_nsec -= 1000000000;
423 ts.tv_sec++;
424 }
425 }
426
427 /* take rwlock */
428 int rc = pthread_rwlock_timedwrlock(&pThis->RWLock, &ts);
429 RTThreadUnblocked(hThreadSelf, RTTHREADSTATE_RW_WRITE);
430 if (rc)
431 {
432 AssertMsg(rc == ETIMEDOUT, ("Failed read lock read-write sem %p, rc=%d.\n", RWSem, rc));
433 return RTErrConvertFromErrno(rc);
434 }
435#endif /* !RT_OS_DARWIN */
436 }
437
438 ATOMIC_SET_PTHREAD_T(&pThis->Writer, Self);
439 pThis->cWrites = 1;
440 Assert(!pThis->cReaders);
441#ifdef RTSEMRW_STRICT
442 RTLockValidatorSetOwner(&pThis->ValidatorWrite, hThreadSelf, pSrcPos);
443#endif
444 return VINF_SUCCESS;
445}
446
447
448RTDECL(int) RTSemRWRequestWrite(RTSEMRW RWSem, unsigned cMillies)
449{
450#ifndef RTSEMRW_STRICT
451 return rtSemRWRequestWrite(RWSem, cMillies, NULL);
452#else
453 RTLOCKVALIDATORSRCPOS SrcPos = RTLOCKVALIDATORSRCPOS_INIT_NORMAL_API();
454 return rtSemRWRequestWrite(RWSem, cMillies, &SrcPos);
455#endif
456}
457
458
459RTDECL(int) RTSemRWRequestWriteDebug(RTSEMRW RWSem, unsigned cMillies, RTHCUINTPTR uId, RT_SRC_POS_DECL)
460{
461 RTLOCKVALIDATORSRCPOS SrcPos = RTLOCKVALIDATORSRCPOS_INIT_DEBUG_API();
462 return rtSemRWRequestWrite(RWSem, cMillies, &SrcPos);
463}
464
465
466RTDECL(int) RTSemRWRequestWriteNoResume(RTSEMRW RWSem, unsigned cMillies)
467{
468 /* EINTR isn't returned by the wait functions we're using. */
469#ifndef RTSEMRW_STRICT
470 return rtSemRWRequestWrite(RWSem, cMillies, NULL);
471#else
472 RTLOCKVALIDATORSRCPOS SrcPos = RTLOCKVALIDATORSRCPOS_INIT_NORMAL_API();
473 return rtSemRWRequestWrite(RWSem, cMillies, &SrcPos);
474#endif
475}
476
477
478RTDECL(int) RTSemRWRequestWriteNoResumeDebug(RTSEMRW RWSem, unsigned cMillies, RTHCUINTPTR uId, RT_SRC_POS_DECL)
479{
480 /* EINTR isn't returned by the wait functions we're using. */
481 RTLOCKVALIDATORSRCPOS SrcPos = RTLOCKVALIDATORSRCPOS_INIT_DEBUG_API();
482 return rtSemRWRequestWrite(RWSem, cMillies, &SrcPos);
483}
484
485
486RTDECL(int) RTSemRWReleaseWrite(RTSEMRW RWSem)
487{
488 /*
489 * Validate input.
490 */
491 struct RTSEMRWINTERNAL *pThis = RWSem;
492 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
493 AssertMsgReturn(pThis->u32Magic == RTSEMRW_MAGIC,
494 ("pThis=%p u32Magic=%#x\n", pThis, pThis->u32Magic),
495 VERR_INVALID_HANDLE);
496
497 /*
498 * Verify ownership and implement recursion.
499 */
500 pthread_t Self = pthread_self();
501 pthread_t Writer;
502 ATOMIC_GET_PTHREAD_T(&pThis->Writer, &Writer);
503 AssertMsgReturn(Writer == Self, ("pThis=%p\n", pThis), VERR_NOT_OWNER);
504 AssertReturn(pThis->cWriterReads == 0 || pThis->cWrites > 1, VERR_WRONG_ORDER);
505
506 if (pThis->cWrites > 1)
507 {
508#ifdef RTSEMRW_STRICT
509 int rc9 = RTLockValidatorUnwindRecursion(&pThis->ValidatorWrite);
510 if (RT_FAILURE(rc9))
511 return rc9;
512#endif
513 pThis->cWrites--;
514 return VINF_SUCCESS;
515 }
516 pThis->cWrites--;
517
518 /*
519 * Try unlock it.
520 */
521#ifdef RTSEMRW_STRICT
522 int rc9 = RTLockValidatorCheckAndRelease(&pThis->ValidatorWrite);
523 if (RT_FAILURE(rc9))
524 return rc9;
525#endif
526
527 ATOMIC_SET_PTHREAD_T(&pThis->Writer, (pthread_t)-1);
528 int rc = pthread_rwlock_unlock(&pThis->RWLock);
529 if (rc)
530 {
531 AssertMsgFailed(("Failed write unlock read-write sem %p, rc=%d.\n", RWSem, rc));
532 return RTErrConvertFromErrno(rc);
533 }
534
535 return VINF_SUCCESS;
536}
537
538
539RTDECL(bool) RTSemRWIsWriteOwner(RTSEMRW RWSem)
540{
541 /*
542 * Validate input.
543 */
544 struct RTSEMRWINTERNAL *pThis = RWSem;
545 AssertPtrReturn(pThis, false);
546 AssertMsgReturn(pThis->u32Magic == RTSEMRW_MAGIC,
547 ("pThis=%p u32Magic=%#x\n", pThis, pThis->u32Magic),
548 false);
549
550 /*
551 * Check ownership.
552 */
553 pthread_t Self = pthread_self();
554 pthread_t Writer;
555 ATOMIC_GET_PTHREAD_T(&pThis->Writer, &Writer);
556 return Writer == Self;
557}
558
559
560RTDECL(uint32_t) RTSemRWGetWriteRecursion(RTSEMRW RWSem)
561{
562 /*
563 * Validate input.
564 */
565 struct RTSEMRWINTERNAL *pThis = RWSem;
566 AssertPtrReturn(pThis, 0);
567 AssertMsgReturn(pThis->u32Magic == RTSEMRW_MAGIC,
568 ("pThis=%p u32Magic=%#x\n", pThis, pThis->u32Magic),
569 0);
570
571 /*
572 * Return the requested data.
573 */
574 return pThis->cWrites;
575}
576
577
578RTDECL(uint32_t) RTSemRWGetWriterReadRecursion(RTSEMRW RWSem)
579{
580 /*
581 * Validate input.
582 */
583 struct RTSEMRWINTERNAL *pThis = RWSem;
584 AssertPtrReturn(pThis, 0);
585 AssertMsgReturn(pThis->u32Magic == RTSEMRW_MAGIC,
586 ("pThis=%p u32Magic=%#x\n", pThis, pThis->u32Magic),
587 0);
588
589 /*
590 * Return the requested data.
591 */
592 return pThis->cWriterReads;
593}
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette