VirtualBox

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

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

iprt,pdmcritsect: Added RTSemEvent[Set|Add|Remove]Signaller so that we can validate who is signalling an event if we like and, more importantly, detect deadlocks involving event semaphores. More attempts at dealing with the races (and bugs) in the all-other-threads-blocking detection in tstRTLockValidator.cpp, adding RTThreadGetReallySleeping and RTThreadGetNativeState in the process.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 25.9 KB
Line 
1/* $Id: semrw-generic.cpp 25638 2010-01-04 16:08:04Z 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_RTLOCKVALIDATORCLASS, RTLOCKVALIDATOR_SUB_CLASS_NONE, "RTSemRW", pThis);
138 RTLockValidatorRecSharedInit(&pThis->ValidatorRead, NIL_RTLOCKVALIDATORCLASS, RTLOCKVALIDATOR_SUB_CLASS_NONE, "RTSemRW", pThis, false /*fSignaller*/);
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 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 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);
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 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.

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