VirtualBox

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

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

iprt,pdmcritsect: Some more lock validator code, almost there now... :-)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 26.0 KB
Line 
1/* $Id: semrw-generic.cpp 25685 2010-01-07 22:03:06Z 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.virtualbox.org. 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_RTLOCKVALCLASS, RTLOCKVAL_SUB_CLASS_NONE, "RTSemRW", pThis, true);
138 RTLockValidatorRecSharedInit(&pThis->ValidatorRead, NIL_RTLOCKVALCLASS, RTLOCKVAL_SUB_CLASS_NONE, "RTSemRW", pThis, false /*fSignaller*/, true);
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, cMillies);
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 RTLockValidatorRecSharedAddOwner(&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,
327 cMillies, RTTHREADSTATE_RW_READ, false);
328 if (RT_FAILURE(rc))
329 break;
330#else
331 RTThreadBlocking(hThreadSelf, RTTHREADSTATE_RW_READ, false);
332#endif
333 int rcWait;
334 if (fInterruptible)
335 rcWait = rc = RTSemEventMultiWaitNoResume(pThis->ReadEvent, cMillies);
336 else
337 rcWait = rc = RTSemEventMultiWait(pThis->ReadEvent, cMillies);
338 RTThreadUnblocked(hThreadSelf, RTTHREADSTATE_RW_READ);
339 if (RT_FAILURE(rc) && rc != VERR_TIMEOUT) /* handle timeout below */
340 {
341 AssertMsgRC(rc, ("RTSemEventMultiWait failed on rwsem %p, rc=%Rrc\n", RWSem, rc));
342 break;
343 }
344
345 if (pThis->u32Magic != RTSEMRW_MAGIC)
346 {
347 rc = VERR_SEM_DESTROYED;
348 break;
349 }
350
351 /*
352 * Re-take critsect and repeate the check we did before the loop.
353 */
354 rc = RTCritSectEnter(&pThis->CritSect);
355 if (RT_FAILURE(rc))
356 {
357 AssertMsgFailed(("RTCritSectEnter failed on rwsem %p, rc=%Rrc\n", RWSem, rc));
358 break;
359 }
360
361 if ( pThis->hWriter == NIL_RTNATIVETHREAD
362#if 0
363 && ( !pThis->cWritesWaiting
364 || pThis->cReads)
365#endif
366 )
367 {
368 pThis->cReads++;
369 Assert(pThis->cReads > 0);
370#ifdef RTSEMRW_STRICT
371 RTLockValidatorRecSharedAddOwner(&pThis->ValidatorRead, hThreadSelf, pSrcPos);
372#endif
373
374 RTCritSectLeave(&pThis->CritSect);
375 return VINF_SUCCESS;
376 }
377
378 RTCritSectLeave(&pThis->CritSect);
379
380 /*
381 * Quit if the wait already timed out.
382 */
383 if (rcWait == VERR_TIMEOUT)
384 {
385 rc = VERR_TIMEOUT;
386 break;
387 }
388 }
389
390 /* failed */
391 return rc;
392}
393
394
395RTDECL(int) RTSemRWRequestRead(RTSEMRW RWSem, unsigned cMillies)
396{
397#ifndef RTSEMRW_STRICT
398 return rtSemRWRequestRead(RWSem, cMillies, false, NULL);
399#else
400 RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_NORMAL_API();
401 return rtSemRWRequestRead(RWSem, cMillies, false, &SrcPos);
402#endif
403}
404RT_EXPORT_SYMBOL(RTSemRWRequestRead);
405
406
407RTDECL(int) RTSemRWRequestReadDebug(RTSEMRW RWSem, unsigned cMillies, RTHCUINTPTR uId, RT_SRC_POS_DECL)
408{
409 RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_DEBUG_API();
410 return rtSemRWRequestRead(RWSem, cMillies, false, &SrcPos);
411}
412RT_EXPORT_SYMBOL(RTSemRWRequestReadDebug);
413
414
415RTDECL(int) RTSemRWRequestReadNoResume(RTSEMRW RWSem, unsigned cMillies)
416{
417#ifndef RTSEMRW_STRICT
418 return rtSemRWRequestRead(RWSem, cMillies, true, NULL);
419#else
420 RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_NORMAL_API();
421 return rtSemRWRequestRead(RWSem, cMillies, true, &SrcPos);
422#endif
423}
424RT_EXPORT_SYMBOL(RTSemRWRequestReadNoResume);
425
426
427RTDECL(int) RTSemRWRequestReadNoResumeDebug(RTSEMRW RWSem, unsigned cMillies, RTHCUINTPTR uId, RT_SRC_POS_DECL)
428{
429 RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_DEBUG_API();
430 return rtSemRWRequestRead(RWSem, cMillies, true, &SrcPos);
431}
432RT_EXPORT_SYMBOL(RTSemRWRequestReadNoResumeDebug);
433
434
435RTDECL(int) RTSemRWReleaseRead(RTSEMRW RWSem)
436{
437 struct RTSEMRWINTERNAL *pThis = RWSem;
438
439 /*
440 * Validate handle.
441 */
442 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
443 AssertReturn(pThis->u32Magic == RTSEMRW_MAGIC, VERR_INVALID_HANDLE);
444
445 /*
446 * Take critsect.
447 */
448 int rc = RTCritSectEnter(&pThis->CritSect);
449 if (RT_SUCCESS(rc))
450 {
451 if (pThis->hWriter == NIL_RTNATIVETHREAD)
452 {
453#ifdef RTSEMRW_STRICT
454 rc = RTLockValidatorRecSharedCheckAndRelease(&pThis->ValidatorRead, NIL_RTTHREAD);
455 if (RT_SUCCESS(rc))
456#endif
457 {
458 if (RT_LIKELY(pThis->cReads > 0))
459 {
460 pThis->cReads--;
461
462 /* Kick off a writer if appropriate. */
463 if ( pThis->cWritesWaiting > 0
464 && !pThis->cReads)
465 {
466 rc = RTSemEventSignal(pThis->WriteEvent);
467 AssertMsgRC(rc, ("Failed to signal writers on rwsem %p, rc=%Rrc\n", RWSem, rc));
468 }
469 }
470 else
471 {
472 AssertFailed();
473 rc = VERR_NOT_OWNER;
474 }
475 }
476 }
477 else
478 {
479 RTNATIVETHREAD hNativeSelf = pThis->CritSect.NativeThreadOwner;
480 if (pThis->hWriter == hNativeSelf)
481 {
482 if (pThis->cWriterReads > 0)
483 {
484#ifdef RTSEMRW_STRICT
485 rc = RTLockValidatorRecExclUnwindMixed(&pThis->ValidatorWrite, &pThis->ValidatorRead.Core);
486 if (RT_SUCCESS(rc))
487#endif
488 {
489 pThis->cWriterReads--;
490 }
491 }
492 else
493 {
494 AssertFailed();
495 rc = VERR_NOT_OWNER;
496 }
497 }
498 else
499 {
500 AssertFailed();
501 rc = VERR_NOT_OWNER;
502 }
503 }
504
505 RTCritSectLeave(&pThis->CritSect);
506 }
507 else
508 AssertMsgFailed(("RTCritSectEnter failed on rwsem %p, rc=%Rrc\n", RWSem, rc));
509
510 return rc;
511}
512RT_EXPORT_SYMBOL(RTSemRWReleaseRead);
513
514
515DECL_FORCE_INLINE(int) rtSemRWRequestWrite(RTSEMRW RWSem, unsigned cMillies, bool fInterruptible, PCRTLOCKVALSRCPOS pSrcPos)
516{
517 /*
518 * Validate handle.
519 */
520 struct RTSEMRWINTERNAL *pThis = RWSem;
521 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
522 AssertReturn(pThis->u32Magic == RTSEMRW_MAGIC, VERR_INVALID_HANDLE);
523
524 unsigned cMilliesInitial = cMillies;
525 uint64_t tsStart = 0;
526 if (cMillies != RT_INDEFINITE_WAIT && cMillies != 0)
527 tsStart = RTTimeNanoTS();
528
529#ifdef RTSEMRW_STRICT
530 RTTHREAD hThreadSelf = NIL_RTTHREAD;
531 if (cMillies)
532 {
533 hThreadSelf = RTThreadSelfAutoAdopt();
534 int rc9 = RTLockValidatorRecExclCheckOrder(&pThis->ValidatorWrite, hThreadSelf, pSrcPos, cMillies);
535 if (RT_FAILURE(rc9))
536 return rc9;
537 }
538#endif
539
540 /*
541 * Take critsect.
542 */
543 int rc = RTCritSectEnter(&pThis->CritSect);
544 if (RT_FAILURE(rc))
545 {
546 AssertMsgFailed(("RTCritSectEnter failed on rwsem %p, rc=%Rrc\n", RWSem, rc));
547 return rc;
548 }
549
550 /*
551 * Check if the state of affairs allows write access.
552 */
553 RTNATIVETHREAD hNativeSelf = pThis->CritSect.NativeThreadOwner;
554 if ( !pThis->cReads
555 && ( ( !pThis->cWrites
556 && ( !pThis->cWritesWaiting /* play fair if we can wait */
557 || !cMillies)
558 )
559 || pThis->hWriter == hNativeSelf
560 )
561 )
562 {
563 /*
564 * Reset the reader event semaphore if necessary.
565 */
566 if (pThis->fNeedResetReadEvent)
567 {
568 pThis->fNeedResetReadEvent = false;
569 rc = RTSemEventMultiReset(pThis->ReadEvent);
570 AssertMsgRC(rc, ("Failed to reset readers, rwsem %p, rc=%Rrc.\n", RWSem, rc));
571 }
572
573 pThis->cWrites++;
574 pThis->hWriter = hNativeSelf;
575#ifdef RTSEMRW_STRICT
576 RTLockValidatorRecExclSetOwner(&pThis->ValidatorWrite, hThreadSelf, pSrcPos, pThis->cWrites == 1);
577#endif
578 RTCritSectLeave(&pThis->CritSect);
579 return VINF_SUCCESS;
580 }
581
582 /*
583 * Signal writer presence.
584 */
585 if (cMillies != 0)
586 pThis->cWritesWaiting++;
587
588 RTCritSectLeave(&pThis->CritSect);
589
590 /*
591 * Wait till it's ready for writing.
592 */
593 if (cMillies == 0)
594 return VERR_TIMEOUT;
595
596#ifndef RTSEMRW_STRICT
597 RTTHREAD hThreadSelf = RTThreadSelf();
598#endif
599 for (;;)
600 {
601 if (cMillies != RT_INDEFINITE_WAIT)
602 {
603 int64_t tsDelta = RTTimeNanoTS() - tsStart;
604 if (tsDelta >= 1000000)
605 {
606 tsDelta /= 1000000;
607 if ((uint64_t)tsDelta < cMilliesInitial)
608 cMilliesInitial = (unsigned)tsDelta;
609 else
610 cMilliesInitial = 1;
611 }
612 }
613
614#ifdef RTSEMRW_STRICT
615 rc = RTLockValidatorRecExclCheckBlocking(&pThis->ValidatorWrite, hThreadSelf, pSrcPos, true,
616 cMillies, RTTHREADSTATE_RW_WRITE, false);
617 if (RT_FAILURE(rc))
618 break;
619#else
620 RTThreadBlocking(hThreadSelf, RTTHREADSTATE_RW_WRITE, false);
621#endif
622 int rcWait;
623 if (fInterruptible)
624 rcWait = rc = RTSemEventWaitNoResume(pThis->WriteEvent, cMillies);
625 else
626 rcWait = rc = RTSemEventWait(pThis->WriteEvent, cMillies);
627 RTThreadUnblocked(hThreadSelf, RTTHREADSTATE_RW_WRITE);
628 if (RT_UNLIKELY(RT_FAILURE_NP(rc) && rc != VERR_TIMEOUT)) /* timeouts are handled below */
629 {
630 AssertMsgRC(rc, ("RTSemEventWait failed on rwsem %p, rc=%Rrc\n", RWSem, rc));
631 break;
632 }
633
634 if (RT_UNLIKELY(pThis->u32Magic != RTSEMRW_MAGIC))
635 {
636 rc = VERR_SEM_DESTROYED;
637 break;
638 }
639
640 /*
641 * Re-take critsect and repeate the check we did prior to this loop.
642 */
643 rc = RTCritSectEnter(&pThis->CritSect);
644 if (RT_FAILURE(rc))
645 {
646 AssertMsgFailed(("RTCritSectEnter failed on rwsem %p, rc=%Rrc\n", RWSem, rc));
647 break;
648 }
649
650 if (!pThis->cReads && (!pThis->cWrites || pThis->hWriter == hNativeSelf))
651 {
652 /*
653 * Reset the reader event semaphore if necessary.
654 */
655 if (pThis->fNeedResetReadEvent)
656 {
657 pThis->fNeedResetReadEvent = false;
658 rc = RTSemEventMultiReset(pThis->ReadEvent);
659 AssertMsgRC(rc, ("Failed to reset readers, rwsem %p, rc=%Rrc.\n", RWSem, rc));
660 }
661
662 pThis->cWrites++;
663 pThis->hWriter = hNativeSelf;
664 pThis->cWritesWaiting--;
665#ifdef RTSEMRW_STRICT
666 RTLockValidatorRecExclSetOwner(&pThis->ValidatorWrite, hThreadSelf, pSrcPos, true);
667#endif
668
669 RTCritSectLeave(&pThis->CritSect);
670 return VINF_SUCCESS;
671 }
672
673 RTCritSectLeave(&pThis->CritSect);
674
675 /*
676 * Quit if the wait already timed out.
677 */
678 if (rcWait == VERR_TIMEOUT)
679 {
680 rc = VERR_TIMEOUT;
681 break;
682 }
683 }
684
685 /*
686 * Timeout/error case, clean up.
687 */
688 if (pThis->u32Magic == RTSEMRW_MAGIC)
689 {
690 RTCritSectEnter(&pThis->CritSect);
691 /* Adjust this counter, whether we got the critsect or not. */
692 pThis->cWritesWaiting--;
693 RTCritSectLeave(&pThis->CritSect);
694 }
695 return rc;
696}
697
698
699RTDECL(int) RTSemRWRequestWrite(RTSEMRW RWSem, unsigned cMillies)
700{
701#ifndef RTSEMRW_STRICT
702 return rtSemRWRequestWrite(RWSem, cMillies, false, NULL);
703#else
704 RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_NORMAL_API();
705 return rtSemRWRequestWrite(RWSem, cMillies, false, &SrcPos);
706#endif
707}
708RT_EXPORT_SYMBOL(RTSemRWRequestWrite);
709
710
711RTDECL(int) RTSemRWRequestWriteDebug(RTSEMRW RWSem, unsigned cMillies, RTHCUINTPTR uId, RT_SRC_POS_DECL)
712{
713 RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_DEBUG_API();
714 return rtSemRWRequestWrite(RWSem, cMillies, false, &SrcPos);
715}
716RT_EXPORT_SYMBOL(RTSemRWRequestWriteDebug);
717
718
719RTDECL(int) RTSemRWRequestWriteNoResume(RTSEMRW RWSem, unsigned cMillies)
720{
721#ifndef RTSEMRW_STRICT
722 return rtSemRWRequestWrite(RWSem, cMillies, true, NULL);
723#else
724 RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_NORMAL_API();
725 return rtSemRWRequestWrite(RWSem, cMillies, true, &SrcPos);
726#endif
727}
728RT_EXPORT_SYMBOL(RTSemRWRequestWriteNoResume);
729
730
731RTDECL(int) RTSemRWRequestWriteNoResumeDebug(RTSEMRW RWSem, unsigned cMillies, RTHCUINTPTR uId, RT_SRC_POS_DECL)
732{
733 RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_DEBUG_API();
734 return rtSemRWRequestWrite(RWSem, cMillies, true, &SrcPos);
735}
736RT_EXPORT_SYMBOL(RTSemRWRequestWriteNoResumeDebug);
737
738
739RTDECL(int) RTSemRWReleaseWrite(RTSEMRW RWSem)
740{
741
742 /*
743 * Validate handle.
744 */
745 struct RTSEMRWINTERNAL *pThis = RWSem;
746 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
747 AssertReturn(pThis->u32Magic == RTSEMRW_MAGIC, VERR_INVALID_HANDLE);
748
749 /*
750 * Take critsect.
751 */
752 int rc = RTCritSectEnter(&pThis->CritSect);
753 AssertRCReturn(rc, rc);
754
755 /*
756 * Check if owner.
757 */
758 RTNATIVETHREAD hNativeSelf = pThis->CritSect.NativeThreadOwner;
759 if (pThis->hWriter != hNativeSelf)
760 {
761 RTCritSectLeave(&pThis->CritSect);
762 AssertMsgFailed(("Not read-write owner of rwsem %p.\n", RWSem));
763 return VERR_NOT_OWNER;
764 }
765
766#ifdef RTSEMRW_STRICT
767 if (pThis->cWrites > 1 || !pThis->cWriterReads) /* don't check+release if VERR_WRONG_ORDER */
768 {
769 int rc9 = RTLockValidatorRecExclReleaseOwner(&pThis->ValidatorWrite, pThis->cWrites == 1);
770 if (RT_FAILURE(rc9))
771 {
772 RTCritSectLeave(&pThis->CritSect);
773 return rc9;
774 }
775 }
776#endif
777
778 /*
779 * Release ownership and remove ourselves from the writers count.
780 */
781 Assert(pThis->cWrites > 0);
782 pThis->cWrites--;
783 if (!pThis->cWrites)
784 {
785 if (RT_UNLIKELY(pThis->cWriterReads > 0))
786 {
787 pThis->cWrites++;
788 RTCritSectLeave(&pThis->CritSect);
789 AssertMsgFailed(("All recursive read locks need to be released prior to the final write lock! (%p)n\n", pThis));
790 return VERR_WRONG_ORDER;
791 }
792
793 pThis->hWriter = NIL_RTNATIVETHREAD;
794 }
795
796 /*
797 * Release the readers if no more writers waiting, otherwise the writers.
798 */
799 if (!pThis->cWritesWaiting)
800 {
801 rc = RTSemEventMultiSignal(pThis->ReadEvent);
802 AssertMsgRC(rc, ("RTSemEventMultiSignal failed for rwsem %p, rc=%Rrc.\n", RWSem, rc));
803 pThis->fNeedResetReadEvent = true;
804 }
805 else
806 {
807 rc = RTSemEventSignal(pThis->WriteEvent);
808 AssertMsgRC(rc, ("Failed to signal writers on rwsem %p, rc=%Rrc\n", RWSem, rc));
809 }
810 RTCritSectLeave(&pThis->CritSect);
811
812 return rc;
813}
814RT_EXPORT_SYMBOL(RTSemRWReleaseWrite);
815
816
817RTDECL(bool) RTSemRWIsWriteOwner(RTSEMRW RWSem)
818{
819 struct RTSEMRWINTERNAL *pThis = RWSem;
820
821 /*
822 * Validate handle.
823 */
824 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
825 AssertReturn(pThis->u32Magic == RTSEMRW_MAGIC, VERR_INVALID_HANDLE);
826
827 /*
828 * Check ownership.
829 */
830 RTNATIVETHREAD hNativeSelf = RTThreadNativeSelf();
831 RTNATIVETHREAD hWriter;
832 ASMAtomicUoReadHandle(&pThis->hWriter, &hWriter);
833 return hWriter == hNativeSelf;
834}
835RT_EXPORT_SYMBOL(RTSemRWIsWriteOwner);
836
837
838RTDECL(uint32_t) RTSemRWGetWriteRecursion(RTSEMRW RWSem)
839{
840 struct RTSEMRWINTERNAL *pThis = RWSem;
841
842 /*
843 * Validate handle.
844 */
845 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
846 AssertReturn(pThis->u32Magic == RTSEMRW_MAGIC, VERR_INVALID_HANDLE);
847
848 /*
849 * Return the requested data.
850 */
851 return pThis->cWrites;
852}
853RT_EXPORT_SYMBOL(RTSemRWGetWriteRecursion);
854
855
856RTDECL(uint32_t) RTSemRWGetWriterReadRecursion(RTSEMRW RWSem)
857{
858 struct RTSEMRWINTERNAL *pThis = RWSem;
859
860 /*
861 * Validate handle.
862 */
863 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
864 AssertReturn(pThis->u32Magic == RTSEMRW_MAGIC, VERR_INVALID_HANDLE);
865
866 /*
867 * Return the requested data.
868 */
869 return pThis->cWriterReads;
870}
871RT_EXPORT_SYMBOL(RTSemRWGetWriterReadRecursion);
872
873
874RTDECL(uint32_t) RTSemRWGetReadCount(RTSEMRW RWSem)
875{
876 /*
877 * Validate input.
878 */
879 struct RTSEMRWINTERNAL *pThis = RWSem;
880 AssertPtrReturn(pThis, 0);
881 AssertMsgReturn(pThis->u32Magic == RTSEMRW_MAGIC,
882 ("pThis=%p u32Magic=%#x\n", pThis, pThis->u32Magic),
883 0);
884
885 /*
886 * Return the requested data.
887 */
888 return pThis->cReads;
889}
890RT_EXPORT_SYMBOL(RTSemRWGetReadCount);
891
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