VirtualBox

source: vbox/trunk/src/VBox/Runtime/generic/semrw-generic.cpp@ 25620

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

iprt/semaphore.h: Added Debug wrappers for all the RW semaphores.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 25.8 KB
Line 
1/* $Id: semrw-generic.cpp 25620 2010-01-02 22:18:07Z vboxsync $ */
2/** @file
3 * IPRT - Read-Write Semaphore, Generic.
4 *
5 * This is a generic implementation for OSes which don't have
6 * native RW semaphores.
7 */
8
9/*
10 * Copyright (C) 2006-2009 Sun Microsystems, Inc.
11 *
12 * This file is part of VirtualBox Open Source Edition (OSE), as
13 * available from http://www.215389.xyz. This file is free software;
14 * you can redistribute it and/or modify it under the terms of the GNU
15 * General Public License (GPL) as published by the Free Software
16 * Foundation, in version 2 as it comes in the "COPYING" file of the
17 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
18 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
19 *
20 * The contents of this file may alternatively be used under the terms
21 * of the Common Development and Distribution License Version 1.0
22 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
23 * VirtualBox OSE distribution, in which case the provisions of the
24 * CDDL are applicable instead of those of the GPL.
25 *
26 * You may elect to license modified versions of this file under the
27 * terms and conditions of either the GPL or the CDDL or both.
28 *
29 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
30 * Clara, CA 95054 USA or visit http://www.sun.com if you need
31 * additional information or have any questions.
32 */
33
34
35/*******************************************************************************
36* Header Files *
37*******************************************************************************/
38#include <iprt/semaphore.h>
39#include "internal/iprt.h"
40
41#include <iprt/asm.h>
42#include <iprt/assert.h>
43#include <iprt/critsect.h>
44#include <iprt/err.h>
45#include <iprt/lockvalidator.h>
46#include <iprt/mem.h>
47#include <iprt/time.h>
48#include <iprt/thread.h>
49
50#include "internal/magics.h"
51#include "internal/strict.h"
52
53
54/*******************************************************************************
55* Structures and Typedefs *
56*******************************************************************************/
57
58/** Internal representation of a Read-Write semaphore for the
59 * Generic implementation. */
60struct RTSEMRWINTERNAL
61{
62 /** The usual magic. (RTSEMRW_MAGIC) */
63 uint32_t u32Magic;
64 /* Alignment padding. */
65 uint32_t u32Padding;
66 /** This critical section serializes the access to and updating of the structure members. */
67 RTCRITSECT CritSect;
68 /** The current number of reads. (pure read recursion counts too) */
69 uint32_t cReads;
70 /** The current number of writes. (recursion counts too) */
71 uint32_t cWrites;
72 /** Number of read recursions by the writer. */
73 uint32_t cWriterReads;
74 /** Number of writers waiting. */
75 uint32_t cWritesWaiting;
76 /** The write owner of the lock. */
77 RTNATIVETHREAD hWriter;
78 /** The handle of the event object on which the waiting readers block. (manual reset). */
79 RTSEMEVENTMULTI ReadEvent;
80 /** The handle of the event object on which the waiting writers block. (automatic reset). */
81 RTSEMEVENT WriteEvent;
82 /** Need to reset ReadEvent. */
83 bool fNeedResetReadEvent;
84#ifdef RTSEMRW_STRICT
85 /** The validator record for the writer. */
86 RTLOCKVALRECEXCL ValidatorWrite;
87 /** The validator record for the readers. */
88 RTLOCKVALRECSHRD ValidatorRead;
89#endif
90};
91
92
93/* No debug wrapping here. */
94#undef RTSemRWRequestRead
95#undef RTSemRWRequestReadNoResume
96#undef RTSemRWRequestWrite
97#undef RTSemRWRequestWriteNoResume
98
99
100RTDECL(int) RTSemRWCreate(PRTSEMRW pRWSem)
101{
102 int rc;
103
104 /*
105 * Allocate memory.
106 */
107 struct RTSEMRWINTERNAL *pThis = (struct RTSEMRWINTERNAL *)RTMemAlloc(sizeof(struct RTSEMRWINTERNAL));
108 if (pThis)
109 {
110 /*
111 * Create the semaphores.
112 */
113 rc = RTSemEventCreate(&pThis->WriteEvent);
114 if (RT_SUCCESS(rc))
115 {
116 rc = RTSemEventMultiCreate(&pThis->ReadEvent);
117 if (RT_SUCCESS(rc))
118 {
119 rc = RTCritSectInit(&pThis->CritSect);
120 if (RT_SUCCESS(rc))
121 {
122 /*
123 * Signal the read semaphore and initialize other variables.
124 */
125 rc = RTSemEventMultiSignal(pThis->ReadEvent);
126 if (RT_SUCCESS(rc))
127 {
128 pThis->u32Padding = UINT32_C(0xa5a55a5a);
129 pThis->cReads = 0;
130 pThis->cWrites = 0;
131 pThis->cWriterReads = 0;
132 pThis->cWritesWaiting = 0;
133 pThis->hWriter = NIL_RTNATIVETHREAD;
134 pThis->fNeedResetReadEvent = true;
135 pThis->u32Magic = RTSEMRW_MAGIC;
136#ifdef RTSEMRW_STRICT
137 RTLockValidatorRecExclInit(&pThis->ValidatorWrite, NIL_RTLOCKVALIDATORCLASS, RTLOCKVALIDATOR_SUB_CLASS_NONE, "RTSemRW", pThis);
138 RTLockValidatorRecSharedInit(&pThis->ValidatorRead, NIL_RTLOCKVALIDATORCLASS, RTLOCKVALIDATOR_SUB_CLASS_NONE, "RTSemRW", pThis);
139 RTLockValidatorRecMakeSiblings(&pThis->ValidatorWrite.Core, &pThis->ValidatorRead.Core);
140#endif
141 *pRWSem = pThis;
142 return VINF_SUCCESS;
143 }
144 RTCritSectDelete(&pThis->CritSect);
145 }
146 RTSemEventMultiDestroy(pThis->ReadEvent);
147 }
148 RTSemEventDestroy(pThis->WriteEvent);
149 }
150 RTMemFree(pThis);
151 }
152 else
153 rc = VERR_NO_MEMORY;
154
155 return rc;
156}
157RT_EXPORT_SYMBOL(RTSemRWCreate);
158
159
160RTDECL(int) RTSemRWDestroy(RTSEMRW RWSem)
161{
162 struct RTSEMRWINTERNAL *pThis = RWSem;
163
164 /*
165 * Validate handle.
166 */
167 if (pThis == NIL_RTSEMRW)
168 return VINF_SUCCESS;
169 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
170 AssertReturn(pThis->u32Magic == RTSEMRW_MAGIC, VERR_INVALID_HANDLE);
171
172 /*
173 * Check if busy.
174 */
175 int rc = RTCritSectTryEnter(&pThis->CritSect);
176 if (RT_SUCCESS(rc))
177 {
178 if (!pThis->cReads && !pThis->cWrites)
179 {
180 /*
181 * Make it invalid and unusable.
182 */
183 ASMAtomicWriteU32(&pThis->u32Magic, ~RTSEMRW_MAGIC);
184 pThis->cReads = ~0;
185
186 /*
187 * Do actual cleanup. None of these can now fail.
188 */
189 rc = RTSemEventMultiDestroy(pThis->ReadEvent);
190 AssertMsgRC(rc, ("RTSemEventMultiDestroy failed! rc=%Rrc\n", rc));
191 pThis->ReadEvent = NIL_RTSEMEVENTMULTI;
192
193 rc = RTSemEventDestroy(pThis->WriteEvent);
194 AssertMsgRC(rc, ("RTSemEventDestroy failed! rc=%Rrc\n", rc));
195 pThis->WriteEvent = NIL_RTSEMEVENT;
196
197 RTCritSectLeave(&pThis->CritSect);
198 rc = RTCritSectDelete(&pThis->CritSect);
199 AssertMsgRC(rc, ("RTCritSectDelete failed! rc=%Rrc\n", rc));
200
201#ifdef RTSEMRW_STRICT
202 RTLockValidatorRecSharedDelete(&pThis->ValidatorRead);
203 RTLockValidatorRecExclDelete(&pThis->ValidatorWrite);
204#endif
205 RTMemFree(pThis);
206 rc = VINF_SUCCESS;
207 }
208 else
209 {
210 rc = VERR_SEM_BUSY;
211 RTCritSectLeave(&pThis->CritSect);
212 }
213 }
214 else
215 {
216 AssertMsgRC(rc, ("RTCritSectTryEnter failed! rc=%Rrc\n", rc));
217 rc = VERR_SEM_BUSY;
218 }
219
220 return rc;
221}
222RT_EXPORT_SYMBOL(RTSemRWDestroy);
223
224
225DECL_FORCE_INLINE(int) rtSemRWRequestRead(RTSEMRW RWSem, unsigned cMillies, bool fInterruptible, PCRTLOCKVALSRCPOS pSrcPos)
226{
227 /*
228 * Validate handle.
229 */
230 struct RTSEMRWINTERNAL *pThis = RWSem;
231 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
232 AssertReturn(pThis->u32Magic == RTSEMRW_MAGIC, VERR_INVALID_HANDLE);
233
234 unsigned cMilliesInitial = cMillies;
235 uint64_t tsStart = 0;
236 if (cMillies != RT_INDEFINITE_WAIT && cMillies != 0)
237 tsStart = RTTimeNanoTS();
238
239#ifdef RTSEMRW_STRICT
240 RTTHREAD hThreadSelf = RTThreadSelfAutoAdopt();
241 if (cMillies > 0)
242 {
243 int rc9 = RTLockValidatorRecSharedCheckOrder(&pThis->ValidatorRead, hThreadSelf, pSrcPos);
244 if (RT_FAILURE(rc9))
245 return rc9;
246 }
247#endif
248
249 /*
250 * Take critsect.
251 */
252 int rc = RTCritSectEnter(&pThis->CritSect);
253 if (RT_FAILURE(rc))
254 {
255 AssertMsgFailed(("RTCritSectEnter failed on rwsem %p, rc=%Rrc\n", RWSem, rc));
256 return rc;
257 }
258
259 /*
260 * Check if the state of affairs allows read access.
261 * Do not block further readers if there is a writer waiting, as
262 * that will break/deadlock reader recursion.
263 */
264 if ( pThis->hWriter == NIL_RTNATIVETHREAD
265#if 0
266 && ( !pThis->cWritesWaiting
267 || pThis->cReads)
268#endif
269 )
270 {
271 pThis->cReads++;
272 Assert(pThis->cReads > 0);
273#ifdef RTSEMRW_STRICT
274 RTLockValidatorSharedRecAddOwner(&pThis->ValidatorRead, hThreadSelf, pSrcPos);
275#endif
276
277 RTCritSectLeave(&pThis->CritSect);
278 return VINF_SUCCESS;
279 }
280
281 RTNATIVETHREAD hNativeSelf = pThis->CritSect.NativeThreadOwner;
282 if (pThis->hWriter == hNativeSelf)
283 {
284#ifdef RTSEMRW_STRICT
285 int rc9 = RTLockValidatorRecExclRecursionMixed(&pThis->ValidatorWrite, &pThis->ValidatorRead.Core, pSrcPos);
286 if (RT_FAILURE(rc9))
287 {
288 RTCritSectLeave(&pThis->CritSect);
289 return rc9;
290 }
291#endif
292
293 pThis->cWriterReads++;
294 Assert(pThis->cWriterReads > 0);
295
296 RTCritSectLeave(&pThis->CritSect);
297 return VINF_SUCCESS;
298 }
299
300 RTCritSectLeave(&pThis->CritSect);
301
302 /*
303 * Wait till it's ready for reading.
304 */
305 if (cMillies == 0)
306 return VERR_TIMEOUT;
307
308#ifndef RTSEMRW_STRICT
309 RTTHREAD hThreadSelf = RTThreadSelf();
310#endif
311 for (;;)
312 {
313 if (cMillies != RT_INDEFINITE_WAIT)
314 {
315 int64_t tsDelta = RTTimeNanoTS() - tsStart;
316 if (tsDelta >= 1000000)
317 {
318 tsDelta /= 1000000;
319 if ((uint64_t)tsDelta < cMilliesInitial)
320 cMilliesInitial = (unsigned)tsDelta;
321 else
322 cMilliesInitial = 1;
323 }
324 }
325#ifdef RTSEMRW_STRICT
326 rc = RTLockValidatorRecSharedCheckBlocking(&pThis->ValidatorRead, hThreadSelf, pSrcPos, true, RTTHREADSTATE_RW_READ);
327 if (RT_FAILURE(rc))
328 break;
329#else
330 RTThreadBlocking(hThreadSelf, RTTHREADSTATE_RW_READ);
331#endif
332 int rcWait;
333 if (fInterruptible)
334 rcWait = rc = RTSemEventMultiWaitNoResume(pThis->ReadEvent, cMillies);
335 else
336 rcWait = rc = RTSemEventMultiWait(pThis->ReadEvent, cMillies);
337 RTThreadUnblocked(hThreadSelf, RTTHREADSTATE_RW_READ);
338 if (RT_FAILURE(rc) && rc != VERR_TIMEOUT) /* handle timeout below */
339 {
340 AssertMsgRC(rc, ("RTSemEventMultiWait failed on rwsem %p, rc=%Rrc\n", RWSem, rc));
341 break;
342 }
343
344 if (pThis->u32Magic != RTSEMRW_MAGIC)
345 {
346 rc = VERR_SEM_DESTROYED;
347 break;
348 }
349
350 /*
351 * Re-take critsect and repeate the check we did before the loop.
352 */
353 rc = RTCritSectEnter(&pThis->CritSect);
354 if (RT_FAILURE(rc))
355 {
356 AssertMsgFailed(("RTCritSectEnter failed on rwsem %p, rc=%Rrc\n", RWSem, rc));
357 break;
358 }
359
360 if ( pThis->hWriter == NIL_RTNATIVETHREAD
361#if 0
362 && ( !pThis->cWritesWaiting
363 || pThis->cReads)
364#endif
365 )
366 {
367 pThis->cReads++;
368 Assert(pThis->cReads > 0);
369#ifdef RTSEMRW_STRICT
370 RTLockValidatorSharedRecAddOwner(&pThis->ValidatorRead, hThreadSelf, pSrcPos);
371#endif
372
373 RTCritSectLeave(&pThis->CritSect);
374 return VINF_SUCCESS;
375 }
376
377 RTCritSectLeave(&pThis->CritSect);
378
379 /*
380 * Quit if the wait already timed out.
381 */
382 if (rcWait == VERR_TIMEOUT)
383 {
384 rc = VERR_TIMEOUT;
385 break;
386 }
387 }
388
389 /* failed */
390 return rc;
391}
392
393
394RTDECL(int) RTSemRWRequestRead(RTSEMRW RWSem, unsigned cMillies)
395{
396#ifndef RTSEMRW_STRICT
397 return rtSemRWRequestRead(RWSem, cMillies, false, NULL);
398#else
399 RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_NORMAL_API();
400 return rtSemRWRequestRead(RWSem, cMillies, false, &SrcPos);
401#endif
402}
403RT_EXPORT_SYMBOL(RTSemRWRequestRead);
404
405
406RTDECL(int) RTSemRWRequestReadDebug(RTSEMRW RWSem, unsigned cMillies, RTHCUINTPTR uId, RT_SRC_POS_DECL)
407{
408 RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_DEBUG_API();
409 return rtSemRWRequestRead(RWSem, cMillies, false, &SrcPos);
410}
411RT_EXPORT_SYMBOL(RTSemRWRequestReadDebug);
412
413
414RTDECL(int) RTSemRWRequestReadNoResume(RTSEMRW RWSem, unsigned cMillies)
415{
416#ifndef RTSEMRW_STRICT
417 return rtSemRWRequestRead(RWSem, cMillies, true, NULL);
418#else
419 RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_NORMAL_API();
420 return rtSemRWRequestRead(RWSem, cMillies, true, &SrcPos);
421#endif
422}
423RT_EXPORT_SYMBOL(RTSemRWRequestReadNoResume);
424
425
426RTDECL(int) RTSemRWRequestReadNoResumeDebug(RTSEMRW RWSem, unsigned cMillies, RTHCUINTPTR uId, RT_SRC_POS_DECL)
427{
428 RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_DEBUG_API();
429 return rtSemRWRequestRead(RWSem, cMillies, true, &SrcPos);
430}
431RT_EXPORT_SYMBOL(RTSemRWRequestReadNoResumeDebug);
432
433
434RTDECL(int) RTSemRWReleaseRead(RTSEMRW RWSem)
435{
436 struct RTSEMRWINTERNAL *pThis = RWSem;
437
438 /*
439 * Validate handle.
440 */
441 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
442 AssertReturn(pThis->u32Magic == RTSEMRW_MAGIC, VERR_INVALID_HANDLE);
443
444 /*
445 * Take critsect.
446 */
447 int rc = RTCritSectEnter(&pThis->CritSect);
448 if (RT_SUCCESS(rc))
449 {
450 if (pThis->hWriter == NIL_RTNATIVETHREAD)
451 {
452#ifdef RTSEMRW_STRICT
453 rc = RTLockValidatorRecSharedCheckAndRelease(&pThis->ValidatorRead, NIL_RTTHREAD);
454 if (RT_SUCCESS(rc))
455#endif
456 {
457 if (RT_LIKELY(pThis->cReads > 0))
458 {
459 pThis->cReads--;
460
461 /* Kick off a writer if appropriate. */
462 if ( pThis->cWritesWaiting > 0
463 && !pThis->cReads)
464 {
465 rc = RTSemEventSignal(pThis->WriteEvent);
466 AssertMsgRC(rc, ("Failed to signal writers on rwsem %p, rc=%Rrc\n", RWSem, rc));
467 }
468 }
469 else
470 {
471 AssertFailed();
472 rc = VERR_NOT_OWNER;
473 }
474 }
475 }
476 else
477 {
478 RTNATIVETHREAD hNativeSelf = pThis->CritSect.NativeThreadOwner;
479 if (pThis->hWriter == hNativeSelf)
480 {
481 if (pThis->cWriterReads > 0)
482 {
483#ifdef RTSEMRW_STRICT
484 rc = RTLockValidatorRecExclUnwindMixed(&pThis->ValidatorWrite, &pThis->ValidatorRead.Core);
485 if (RT_SUCCESS(rc))
486#endif
487 {
488 pThis->cWriterReads--;
489 }
490 }
491 else
492 {
493 AssertFailed();
494 rc = VERR_NOT_OWNER;
495 }
496 }
497 else
498 {
499 AssertFailed();
500 rc = VERR_NOT_OWNER;
501 }
502 }
503
504 RTCritSectLeave(&pThis->CritSect);
505 }
506 else
507 AssertMsgFailed(("RTCritSectEnter failed on rwsem %p, rc=%Rrc\n", RWSem, rc));
508
509 return rc;
510}
511RT_EXPORT_SYMBOL(RTSemRWReleaseRead);
512
513
514DECL_FORCE_INLINE(int) rtSemRWRequestWrite(RTSEMRW RWSem, unsigned cMillies, bool fInterruptible, PCRTLOCKVALSRCPOS pSrcPos)
515{
516 /*
517 * Validate handle.
518 */
519 struct RTSEMRWINTERNAL *pThis = RWSem;
520 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
521 AssertReturn(pThis->u32Magic == RTSEMRW_MAGIC, VERR_INVALID_HANDLE);
522
523 unsigned cMilliesInitial = cMillies;
524 uint64_t tsStart = 0;
525 if (cMillies != RT_INDEFINITE_WAIT && cMillies != 0)
526 tsStart = RTTimeNanoTS();
527
528#ifdef RTSEMRW_STRICT
529 RTTHREAD hThreadSelf = NIL_RTTHREAD;
530 if (cMillies)
531 {
532 hThreadSelf = RTThreadSelfAutoAdopt();
533 int rc9 = RTLockValidatorRecExclCheckOrder(&pThis->ValidatorWrite, hThreadSelf, pSrcPos);
534 if (RT_FAILURE(rc9))
535 return rc9;
536 }
537#endif
538
539 /*
540 * Take critsect.
541 */
542 int rc = RTCritSectEnter(&pThis->CritSect);
543 if (RT_FAILURE(rc))
544 {
545 AssertMsgFailed(("RTCritSectEnter failed on rwsem %p, rc=%Rrc\n", RWSem, rc));
546 return rc;
547 }
548
549 /*
550 * Check if the state of affairs allows write access.
551 */
552 RTNATIVETHREAD hNativeSelf = pThis->CritSect.NativeThreadOwner;
553 if ( !pThis->cReads
554 && ( ( !pThis->cWrites
555 && ( !pThis->cWritesWaiting /* play fair if we can wait */
556 || !cMillies)
557 )
558 || pThis->hWriter == hNativeSelf
559 )
560 )
561 {
562 /*
563 * Reset the reader event semaphore if necessary.
564 */
565 if (pThis->fNeedResetReadEvent)
566 {
567 pThis->fNeedResetReadEvent = false;
568 rc = RTSemEventMultiReset(pThis->ReadEvent);
569 AssertMsgRC(rc, ("Failed to reset readers, rwsem %p, rc=%Rrc.\n", RWSem, rc));
570 }
571
572 pThis->cWrites++;
573 pThis->hWriter = hNativeSelf;
574#ifdef RTSEMRW_STRICT
575 RTLockValidatorRecExclSetOwner(&pThis->ValidatorWrite, hThreadSelf, pSrcPos, pThis->cWrites == 1);
576#endif
577 RTCritSectLeave(&pThis->CritSect);
578 return VINF_SUCCESS;
579 }
580
581 /*
582 * Signal writer presence.
583 */
584 if (cMillies != 0)
585 pThis->cWritesWaiting++;
586
587 RTCritSectLeave(&pThis->CritSect);
588
589 /*
590 * Wait till it's ready for writing.
591 */
592 if (cMillies == 0)
593 return VERR_TIMEOUT;
594
595#ifndef RTSEMRW_STRICT
596 RTTHREAD hThreadSelf = RTThreadSelf();
597#endif
598 for (;;)
599 {
600 if (cMillies != RT_INDEFINITE_WAIT)
601 {
602 int64_t tsDelta = RTTimeNanoTS() - tsStart;
603 if (tsDelta >= 1000000)
604 {
605 tsDelta /= 1000000;
606 if ((uint64_t)tsDelta < cMilliesInitial)
607 cMilliesInitial = (unsigned)tsDelta;
608 else
609 cMilliesInitial = 1;
610 }
611 }
612
613#ifdef RTSEMRW_STRICT
614 rc = RTLockValidatorRecExclCheckBlocking(&pThis->ValidatorWrite, hThreadSelf, pSrcPos, true, RTTHREADSTATE_RW_WRITE);
615 if (RT_FAILURE(rc))
616 break;
617#else
618 RTThreadBlocking(hThreadSelf, RTTHREADSTATE_RW_WRITE);
619#endif
620 int rcWait;
621 if (fInterruptible)
622 rcWait = rc = RTSemEventWaitNoResume(pThis->WriteEvent, cMillies);
623 else
624 rcWait = rc = RTSemEventWait(pThis->WriteEvent, cMillies);
625 RTThreadUnblocked(hThreadSelf, RTTHREADSTATE_RW_WRITE);
626 if (RT_UNLIKELY(RT_FAILURE_NP(rc) && rc != VERR_TIMEOUT)) /* timeouts are handled below */
627 {
628 AssertMsgRC(rc, ("RTSemEventWait failed on rwsem %p, rc=%Rrc\n", RWSem, rc));
629 break;
630 }
631
632 if (RT_UNLIKELY(pThis->u32Magic != RTSEMRW_MAGIC))
633 {
634 rc = VERR_SEM_DESTROYED;
635 break;
636 }
637
638 /*
639 * Re-take critsect and repeate the check we did prior to this loop.
640 */
641 rc = RTCritSectEnter(&pThis->CritSect);
642 if (RT_FAILURE(rc))
643 {
644 AssertMsgFailed(("RTCritSectEnter failed on rwsem %p, rc=%Rrc\n", RWSem, rc));
645 break;
646 }
647
648 if (!pThis->cReads && (!pThis->cWrites || pThis->hWriter == hNativeSelf))
649 {
650 /*
651 * Reset the reader event semaphore if necessary.
652 */
653 if (pThis->fNeedResetReadEvent)
654 {
655 pThis->fNeedResetReadEvent = false;
656 rc = RTSemEventMultiReset(pThis->ReadEvent);
657 AssertMsgRC(rc, ("Failed to reset readers, rwsem %p, rc=%Rrc.\n", RWSem, rc));
658 }
659
660 pThis->cWrites++;
661 pThis->hWriter = hNativeSelf;
662 pThis->cWritesWaiting--;
663#ifdef RTSEMRW_STRICT
664 RTLockValidatorRecExclSetOwner(&pThis->ValidatorWrite, hThreadSelf, pSrcPos, true);
665#endif
666
667 RTCritSectLeave(&pThis->CritSect);
668 return VINF_SUCCESS;
669 }
670
671 RTCritSectLeave(&pThis->CritSect);
672
673 /*
674 * Quit if the wait already timed out.
675 */
676 if (rcWait == VERR_TIMEOUT)
677 {
678 rc = VERR_TIMEOUT;
679 break;
680 }
681 }
682
683 /*
684 * Timeout/error case, clean up.
685 */
686 if (pThis->u32Magic == RTSEMRW_MAGIC)
687 {
688 RTCritSectEnter(&pThis->CritSect);
689 /* Adjust this counter, whether we got the critsect or not. */
690 pThis->cWritesWaiting--;
691 RTCritSectLeave(&pThis->CritSect);
692 }
693 return rc;
694}
695
696
697RTDECL(int) RTSemRWRequestWrite(RTSEMRW RWSem, unsigned cMillies)
698{
699#ifndef RTSEMRW_STRICT
700 return rtSemRWRequestWrite(RWSem, cMillies, false, NULL);
701#else
702 RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_NORMAL_API();
703 return rtSemRWRequestWrite(RWSem, cMillies, false, &SrcPos);
704#endif
705}
706RT_EXPORT_SYMBOL(RTSemRWRequestWrite);
707
708
709RTDECL(int) RTSemRWRequestWriteDebug(RTSEMRW RWSem, unsigned cMillies, RTHCUINTPTR uId, RT_SRC_POS_DECL)
710{
711 RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_DEBUG_API();
712 return rtSemRWRequestWrite(RWSem, cMillies, false, &SrcPos);
713}
714RT_EXPORT_SYMBOL(RTSemRWRequestWriteDebug);
715
716
717RTDECL(int) RTSemRWRequestWriteNoResume(RTSEMRW RWSem, unsigned cMillies)
718{
719#ifndef RTSEMRW_STRICT
720 return rtSemRWRequestWrite(RWSem, cMillies, true, NULL);
721#else
722 RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_NORMAL_API();
723 return rtSemRWRequestWrite(RWSem, cMillies, true, &SrcPos);
724#endif
725}
726RT_EXPORT_SYMBOL(RTSemRWRequestWriteNoResume);
727
728
729RTDECL(int) RTSemRWRequestWriteNoResumeDebug(RTSEMRW RWSem, unsigned cMillies, RTHCUINTPTR uId, RT_SRC_POS_DECL)
730{
731 RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_DEBUG_API();
732 return rtSemRWRequestWrite(RWSem, cMillies, true, &SrcPos);
733}
734RT_EXPORT_SYMBOL(RTSemRWRequestWriteNoResumeDebug);
735
736
737RTDECL(int) RTSemRWReleaseWrite(RTSEMRW RWSem)
738{
739
740 /*
741 * Validate handle.
742 */
743 struct RTSEMRWINTERNAL *pThis = RWSem;
744 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
745 AssertReturn(pThis->u32Magic == RTSEMRW_MAGIC, VERR_INVALID_HANDLE);
746
747 /*
748 * Take critsect.
749 */
750 int rc = RTCritSectEnter(&pThis->CritSect);
751 AssertRCReturn(rc, rc);
752
753 /*
754 * Check if owner.
755 */
756 RTNATIVETHREAD hNativeSelf = pThis->CritSect.NativeThreadOwner;
757 if (pThis->hWriter != hNativeSelf)
758 {
759 RTCritSectLeave(&pThis->CritSect);
760 AssertMsgFailed(("Not read-write owner of rwsem %p.\n", RWSem));
761 return VERR_NOT_OWNER;
762 }
763
764#ifdef RTSEMRW_STRICT
765 if (pThis->cWrites > 1 || !pThis->cWriterReads) /* don't check+release if VERR_WRONG_ORDER */
766 {
767 int rc9 = RTLockValidatorRecExclReleaseOwner(&pThis->ValidatorWrite, pThis->cWrites == 1);
768 if (RT_FAILURE(rc9))
769 {
770 RTCritSectLeave(&pThis->CritSect);
771 return rc9;
772 }
773 }
774#endif
775
776 /*
777 * Release ownership and remove ourselves from the writers count.
778 */
779 Assert(pThis->cWrites > 0);
780 pThis->cWrites--;
781 if (!pThis->cWrites)
782 {
783 if (RT_UNLIKELY(pThis->cWriterReads > 0))
784 {
785 pThis->cWrites++;
786 RTCritSectLeave(&pThis->CritSect);
787 AssertMsgFailed(("All recursive read locks need to be released prior to the final write lock! (%p)n\n", pThis));
788 return VERR_WRONG_ORDER;
789 }
790
791 pThis->hWriter = NIL_RTNATIVETHREAD;
792 }
793
794 /*
795 * Release the readers if no more writers waiting, otherwise the writers.
796 */
797 if (!pThis->cWritesWaiting)
798 {
799 rc = RTSemEventMultiSignal(pThis->ReadEvent);
800 AssertMsgRC(rc, ("RTSemEventMultiSignal failed for rwsem %p, rc=%Rrc.\n", RWSem, rc));
801 pThis->fNeedResetReadEvent = true;
802 }
803 else
804 {
805 rc = RTSemEventSignal(pThis->WriteEvent);
806 AssertMsgRC(rc, ("Failed to signal writers on rwsem %p, rc=%Rrc\n", RWSem, rc));
807 }
808 RTCritSectLeave(&pThis->CritSect);
809
810 return rc;
811}
812RT_EXPORT_SYMBOL(RTSemRWReleaseWrite);
813
814
815RTDECL(bool) RTSemRWIsWriteOwner(RTSEMRW RWSem)
816{
817 struct RTSEMRWINTERNAL *pThis = RWSem;
818
819 /*
820 * Validate handle.
821 */
822 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
823 AssertReturn(pThis->u32Magic == RTSEMRW_MAGIC, VERR_INVALID_HANDLE);
824
825 /*
826 * Check ownership.
827 */
828 RTNATIVETHREAD hNativeSelf = RTThreadNativeSelf();
829 RTNATIVETHREAD hWriter;
830 ASMAtomicUoReadHandle(&pThis->hWriter, &hWriter);
831 return hWriter == hNativeSelf;
832}
833RT_EXPORT_SYMBOL(RTSemRWIsWriteOwner);
834
835
836RTDECL(uint32_t) RTSemRWGetWriteRecursion(RTSEMRW RWSem)
837{
838 struct RTSEMRWINTERNAL *pThis = RWSem;
839
840 /*
841 * Validate handle.
842 */
843 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
844 AssertReturn(pThis->u32Magic == RTSEMRW_MAGIC, VERR_INVALID_HANDLE);
845
846 /*
847 * Return the requested data.
848 */
849 return pThis->cWrites;
850}
851RT_EXPORT_SYMBOL(RTSemRWGetWriteRecursion);
852
853
854RTDECL(uint32_t) RTSemRWGetWriterReadRecursion(RTSEMRW RWSem)
855{
856 struct RTSEMRWINTERNAL *pThis = RWSem;
857
858 /*
859 * Validate handle.
860 */
861 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
862 AssertReturn(pThis->u32Magic == RTSEMRW_MAGIC, VERR_INVALID_HANDLE);
863
864 /*
865 * Return the requested data.
866 */
867 return pThis->cWriterReads;
868}
869RT_EXPORT_SYMBOL(RTSemRWGetWriterReadRecursion);
870
871
872RTDECL(uint32_t) RTSemRWGetReadCount(RTSEMRW RWSem)
873{
874 /*
875 * Validate input.
876 */
877 struct RTSEMRWINTERNAL *pThis = RWSem;
878 AssertPtrReturn(pThis, 0);
879 AssertMsgReturn(pThis->u32Magic == RTSEMRW_MAGIC,
880 ("pThis=%p u32Magic=%#x\n", pThis, pThis->u32Magic),
881 0);
882
883 /*
884 * Return the requested data.
885 */
886 return pThis->cReads;
887}
888RT_EXPORT_SYMBOL(RTSemRWGetReadCount);
889
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