VirtualBox

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

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

iprt,pdmcritsect: More flexible lock naming, added RTCritSectSetSubClass and made some RTCritSectInitEx.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 26.1 KB
Line 
1/* $Id: semrw-generic.cpp 25704 2010-01-10 20:12:30Z 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, pThis,
138 true /*fEnabled*/, "RTSemRW");
139 RTLockValidatorRecSharedInit(&pThis->ValidatorRead, NIL_RTLOCKVALCLASS, RTLOCKVAL_SUB_CLASS_NONE, pThis,
140 false /*fSignaller*/, true /*fEnabled*/, "RTSemEvent");
141 RTLockValidatorRecMakeSiblings(&pThis->ValidatorWrite.Core, &pThis->ValidatorRead.Core);
142#endif
143 *pRWSem = pThis;
144 return VINF_SUCCESS;
145 }
146 RTCritSectDelete(&pThis->CritSect);
147 }
148 RTSemEventMultiDestroy(pThis->ReadEvent);
149 }
150 RTSemEventDestroy(pThis->WriteEvent);
151 }
152 RTMemFree(pThis);
153 }
154 else
155 rc = VERR_NO_MEMORY;
156
157 return rc;
158}
159RT_EXPORT_SYMBOL(RTSemRWCreate);
160
161
162RTDECL(int) RTSemRWDestroy(RTSEMRW RWSem)
163{
164 struct RTSEMRWINTERNAL *pThis = RWSem;
165
166 /*
167 * Validate handle.
168 */
169 if (pThis == NIL_RTSEMRW)
170 return VINF_SUCCESS;
171 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
172 AssertReturn(pThis->u32Magic == RTSEMRW_MAGIC, VERR_INVALID_HANDLE);
173
174 /*
175 * Check if busy.
176 */
177 int rc = RTCritSectTryEnter(&pThis->CritSect);
178 if (RT_SUCCESS(rc))
179 {
180 if (!pThis->cReads && !pThis->cWrites)
181 {
182 /*
183 * Make it invalid and unusable.
184 */
185 ASMAtomicWriteU32(&pThis->u32Magic, ~RTSEMRW_MAGIC);
186 pThis->cReads = ~0;
187
188 /*
189 * Do actual cleanup. None of these can now fail.
190 */
191 rc = RTSemEventMultiDestroy(pThis->ReadEvent);
192 AssertMsgRC(rc, ("RTSemEventMultiDestroy failed! rc=%Rrc\n", rc));
193 pThis->ReadEvent = NIL_RTSEMEVENTMULTI;
194
195 rc = RTSemEventDestroy(pThis->WriteEvent);
196 AssertMsgRC(rc, ("RTSemEventDestroy failed! rc=%Rrc\n", rc));
197 pThis->WriteEvent = NIL_RTSEMEVENT;
198
199 RTCritSectLeave(&pThis->CritSect);
200 rc = RTCritSectDelete(&pThis->CritSect);
201 AssertMsgRC(rc, ("RTCritSectDelete failed! rc=%Rrc\n", rc));
202
203#ifdef RTSEMRW_STRICT
204 RTLockValidatorRecSharedDelete(&pThis->ValidatorRead);
205 RTLockValidatorRecExclDelete(&pThis->ValidatorWrite);
206#endif
207 RTMemFree(pThis);
208 rc = VINF_SUCCESS;
209 }
210 else
211 {
212 rc = VERR_SEM_BUSY;
213 RTCritSectLeave(&pThis->CritSect);
214 }
215 }
216 else
217 {
218 AssertMsgRC(rc, ("RTCritSectTryEnter failed! rc=%Rrc\n", rc));
219 rc = VERR_SEM_BUSY;
220 }
221
222 return rc;
223}
224RT_EXPORT_SYMBOL(RTSemRWDestroy);
225
226
227DECL_FORCE_INLINE(int) rtSemRWRequestRead(RTSEMRW RWSem, unsigned cMillies, bool fInterruptible, PCRTLOCKVALSRCPOS pSrcPos)
228{
229 /*
230 * Validate handle.
231 */
232 struct RTSEMRWINTERNAL *pThis = RWSem;
233 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
234 AssertReturn(pThis->u32Magic == RTSEMRW_MAGIC, VERR_INVALID_HANDLE);
235
236 unsigned cMilliesInitial = cMillies;
237 uint64_t tsStart = 0;
238 if (cMillies != RT_INDEFINITE_WAIT && cMillies != 0)
239 tsStart = RTTimeNanoTS();
240
241#ifdef RTSEMRW_STRICT
242 RTTHREAD hThreadSelf = RTThreadSelfAutoAdopt();
243 if (cMillies > 0)
244 {
245 int rc9 = RTLockValidatorRecSharedCheckOrder(&pThis->ValidatorRead, hThreadSelf, pSrcPos, cMillies);
246 if (RT_FAILURE(rc9))
247 return rc9;
248 }
249#endif
250
251 /*
252 * Take critsect.
253 */
254 int rc = RTCritSectEnter(&pThis->CritSect);
255 if (RT_FAILURE(rc))
256 {
257 AssertMsgFailed(("RTCritSectEnter failed on rwsem %p, rc=%Rrc\n", RWSem, rc));
258 return rc;
259 }
260
261 /*
262 * Check if the state of affairs allows read access.
263 * Do not block further readers if there is a writer waiting, as
264 * that will break/deadlock reader recursion.
265 */
266 if ( pThis->hWriter == NIL_RTNATIVETHREAD
267#if 0
268 && ( !pThis->cWritesWaiting
269 || pThis->cReads)
270#endif
271 )
272 {
273 pThis->cReads++;
274 Assert(pThis->cReads > 0);
275#ifdef RTSEMRW_STRICT
276 RTLockValidatorRecSharedAddOwner(&pThis->ValidatorRead, hThreadSelf, pSrcPos);
277#endif
278
279 RTCritSectLeave(&pThis->CritSect);
280 return VINF_SUCCESS;
281 }
282
283 RTNATIVETHREAD hNativeSelf = pThis->CritSect.NativeThreadOwner;
284 if (pThis->hWriter == hNativeSelf)
285 {
286#ifdef RTSEMRW_STRICT
287 int rc9 = RTLockValidatorRecExclRecursionMixed(&pThis->ValidatorWrite, &pThis->ValidatorRead.Core, pSrcPos);
288 if (RT_FAILURE(rc9))
289 {
290 RTCritSectLeave(&pThis->CritSect);
291 return rc9;
292 }
293#endif
294
295 pThis->cWriterReads++;
296 Assert(pThis->cWriterReads > 0);
297
298 RTCritSectLeave(&pThis->CritSect);
299 return VINF_SUCCESS;
300 }
301
302 RTCritSectLeave(&pThis->CritSect);
303
304 /*
305 * Wait till it's ready for reading.
306 */
307 if (cMillies == 0)
308 return VERR_TIMEOUT;
309
310#ifndef RTSEMRW_STRICT
311 RTTHREAD hThreadSelf = RTThreadSelf();
312#endif
313 for (;;)
314 {
315 if (cMillies != RT_INDEFINITE_WAIT)
316 {
317 int64_t tsDelta = RTTimeNanoTS() - tsStart;
318 if (tsDelta >= 1000000)
319 {
320 tsDelta /= 1000000;
321 if ((uint64_t)tsDelta < cMilliesInitial)
322 cMilliesInitial = (unsigned)tsDelta;
323 else
324 cMilliesInitial = 1;
325 }
326 }
327#ifdef RTSEMRW_STRICT
328 rc = RTLockValidatorRecSharedCheckBlocking(&pThis->ValidatorRead, hThreadSelf, pSrcPos, true,
329 cMillies, RTTHREADSTATE_RW_READ, false);
330 if (RT_FAILURE(rc))
331 break;
332#else
333 RTThreadBlocking(hThreadSelf, RTTHREADSTATE_RW_READ, false);
334#endif
335 int rcWait;
336 if (fInterruptible)
337 rcWait = rc = RTSemEventMultiWaitNoResume(pThis->ReadEvent, cMillies);
338 else
339 rcWait = rc = RTSemEventMultiWait(pThis->ReadEvent, cMillies);
340 RTThreadUnblocked(hThreadSelf, RTTHREADSTATE_RW_READ);
341 if (RT_FAILURE(rc) && rc != VERR_TIMEOUT) /* handle timeout below */
342 {
343 AssertMsgRC(rc, ("RTSemEventMultiWait failed on rwsem %p, rc=%Rrc\n", RWSem, rc));
344 break;
345 }
346
347 if (pThis->u32Magic != RTSEMRW_MAGIC)
348 {
349 rc = VERR_SEM_DESTROYED;
350 break;
351 }
352
353 /*
354 * Re-take critsect and repeate the check we did before the loop.
355 */
356 rc = RTCritSectEnter(&pThis->CritSect);
357 if (RT_FAILURE(rc))
358 {
359 AssertMsgFailed(("RTCritSectEnter failed on rwsem %p, rc=%Rrc\n", RWSem, rc));
360 break;
361 }
362
363 if ( pThis->hWriter == NIL_RTNATIVETHREAD
364#if 0
365 && ( !pThis->cWritesWaiting
366 || pThis->cReads)
367#endif
368 )
369 {
370 pThis->cReads++;
371 Assert(pThis->cReads > 0);
372#ifdef RTSEMRW_STRICT
373 RTLockValidatorRecSharedAddOwner(&pThis->ValidatorRead, hThreadSelf, pSrcPos);
374#endif
375
376 RTCritSectLeave(&pThis->CritSect);
377 return VINF_SUCCESS;
378 }
379
380 RTCritSectLeave(&pThis->CritSect);
381
382 /*
383 * Quit if the wait already timed out.
384 */
385 if (rcWait == VERR_TIMEOUT)
386 {
387 rc = VERR_TIMEOUT;
388 break;
389 }
390 }
391
392 /* failed */
393 return rc;
394}
395
396
397RTDECL(int) RTSemRWRequestRead(RTSEMRW RWSem, unsigned cMillies)
398{
399#ifndef RTSEMRW_STRICT
400 return rtSemRWRequestRead(RWSem, cMillies, false, NULL);
401#else
402 RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_NORMAL_API();
403 return rtSemRWRequestRead(RWSem, cMillies, false, &SrcPos);
404#endif
405}
406RT_EXPORT_SYMBOL(RTSemRWRequestRead);
407
408
409RTDECL(int) RTSemRWRequestReadDebug(RTSEMRW RWSem, unsigned cMillies, RTHCUINTPTR uId, RT_SRC_POS_DECL)
410{
411 RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_DEBUG_API();
412 return rtSemRWRequestRead(RWSem, cMillies, false, &SrcPos);
413}
414RT_EXPORT_SYMBOL(RTSemRWRequestReadDebug);
415
416
417RTDECL(int) RTSemRWRequestReadNoResume(RTSEMRW RWSem, unsigned cMillies)
418{
419#ifndef RTSEMRW_STRICT
420 return rtSemRWRequestRead(RWSem, cMillies, true, NULL);
421#else
422 RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_NORMAL_API();
423 return rtSemRWRequestRead(RWSem, cMillies, true, &SrcPos);
424#endif
425}
426RT_EXPORT_SYMBOL(RTSemRWRequestReadNoResume);
427
428
429RTDECL(int) RTSemRWRequestReadNoResumeDebug(RTSEMRW RWSem, unsigned cMillies, RTHCUINTPTR uId, RT_SRC_POS_DECL)
430{
431 RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_DEBUG_API();
432 return rtSemRWRequestRead(RWSem, cMillies, true, &SrcPos);
433}
434RT_EXPORT_SYMBOL(RTSemRWRequestReadNoResumeDebug);
435
436
437RTDECL(int) RTSemRWReleaseRead(RTSEMRW RWSem)
438{
439 struct RTSEMRWINTERNAL *pThis = RWSem;
440
441 /*
442 * Validate handle.
443 */
444 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
445 AssertReturn(pThis->u32Magic == RTSEMRW_MAGIC, VERR_INVALID_HANDLE);
446
447 /*
448 * Take critsect.
449 */
450 int rc = RTCritSectEnter(&pThis->CritSect);
451 if (RT_SUCCESS(rc))
452 {
453 if (pThis->hWriter == NIL_RTNATIVETHREAD)
454 {
455#ifdef RTSEMRW_STRICT
456 rc = RTLockValidatorRecSharedCheckAndRelease(&pThis->ValidatorRead, NIL_RTTHREAD);
457 if (RT_SUCCESS(rc))
458#endif
459 {
460 if (RT_LIKELY(pThis->cReads > 0))
461 {
462 pThis->cReads--;
463
464 /* Kick off a writer if appropriate. */
465 if ( pThis->cWritesWaiting > 0
466 && !pThis->cReads)
467 {
468 rc = RTSemEventSignal(pThis->WriteEvent);
469 AssertMsgRC(rc, ("Failed to signal writers on rwsem %p, rc=%Rrc\n", RWSem, rc));
470 }
471 }
472 else
473 {
474 AssertFailed();
475 rc = VERR_NOT_OWNER;
476 }
477 }
478 }
479 else
480 {
481 RTNATIVETHREAD hNativeSelf = pThis->CritSect.NativeThreadOwner;
482 if (pThis->hWriter == hNativeSelf)
483 {
484 if (pThis->cWriterReads > 0)
485 {
486#ifdef RTSEMRW_STRICT
487 rc = RTLockValidatorRecExclUnwindMixed(&pThis->ValidatorWrite, &pThis->ValidatorRead.Core);
488 if (RT_SUCCESS(rc))
489#endif
490 {
491 pThis->cWriterReads--;
492 }
493 }
494 else
495 {
496 AssertFailed();
497 rc = VERR_NOT_OWNER;
498 }
499 }
500 else
501 {
502 AssertFailed();
503 rc = VERR_NOT_OWNER;
504 }
505 }
506
507 RTCritSectLeave(&pThis->CritSect);
508 }
509 else
510 AssertMsgFailed(("RTCritSectEnter failed on rwsem %p, rc=%Rrc\n", RWSem, rc));
511
512 return rc;
513}
514RT_EXPORT_SYMBOL(RTSemRWReleaseRead);
515
516
517DECL_FORCE_INLINE(int) rtSemRWRequestWrite(RTSEMRW RWSem, unsigned cMillies, bool fInterruptible, PCRTLOCKVALSRCPOS pSrcPos)
518{
519 /*
520 * Validate handle.
521 */
522 struct RTSEMRWINTERNAL *pThis = RWSem;
523 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
524 AssertReturn(pThis->u32Magic == RTSEMRW_MAGIC, VERR_INVALID_HANDLE);
525
526 unsigned cMilliesInitial = cMillies;
527 uint64_t tsStart = 0;
528 if (cMillies != RT_INDEFINITE_WAIT && cMillies != 0)
529 tsStart = RTTimeNanoTS();
530
531#ifdef RTSEMRW_STRICT
532 RTTHREAD hThreadSelf = NIL_RTTHREAD;
533 if (cMillies)
534 {
535 hThreadSelf = RTThreadSelfAutoAdopt();
536 int rc9 = RTLockValidatorRecExclCheckOrder(&pThis->ValidatorWrite, hThreadSelf, pSrcPos, cMillies);
537 if (RT_FAILURE(rc9))
538 return rc9;
539 }
540#endif
541
542 /*
543 * Take critsect.
544 */
545 int rc = RTCritSectEnter(&pThis->CritSect);
546 if (RT_FAILURE(rc))
547 {
548 AssertMsgFailed(("RTCritSectEnter failed on rwsem %p, rc=%Rrc\n", RWSem, rc));
549 return rc;
550 }
551
552 /*
553 * Check if the state of affairs allows write access.
554 */
555 RTNATIVETHREAD hNativeSelf = pThis->CritSect.NativeThreadOwner;
556 if ( !pThis->cReads
557 && ( ( !pThis->cWrites
558 && ( !pThis->cWritesWaiting /* play fair if we can wait */
559 || !cMillies)
560 )
561 || pThis->hWriter == hNativeSelf
562 )
563 )
564 {
565 /*
566 * Reset the reader event semaphore if necessary.
567 */
568 if (pThis->fNeedResetReadEvent)
569 {
570 pThis->fNeedResetReadEvent = false;
571 rc = RTSemEventMultiReset(pThis->ReadEvent);
572 AssertMsgRC(rc, ("Failed to reset readers, rwsem %p, rc=%Rrc.\n", RWSem, rc));
573 }
574
575 pThis->cWrites++;
576 pThis->hWriter = hNativeSelf;
577#ifdef RTSEMRW_STRICT
578 RTLockValidatorRecExclSetOwner(&pThis->ValidatorWrite, hThreadSelf, pSrcPos, pThis->cWrites == 1);
579#endif
580 RTCritSectLeave(&pThis->CritSect);
581 return VINF_SUCCESS;
582 }
583
584 /*
585 * Signal writer presence.
586 */
587 if (cMillies != 0)
588 pThis->cWritesWaiting++;
589
590 RTCritSectLeave(&pThis->CritSect);
591
592 /*
593 * Wait till it's ready for writing.
594 */
595 if (cMillies == 0)
596 return VERR_TIMEOUT;
597
598#ifndef RTSEMRW_STRICT
599 RTTHREAD hThreadSelf = RTThreadSelf();
600#endif
601 for (;;)
602 {
603 if (cMillies != RT_INDEFINITE_WAIT)
604 {
605 int64_t tsDelta = RTTimeNanoTS() - tsStart;
606 if (tsDelta >= 1000000)
607 {
608 tsDelta /= 1000000;
609 if ((uint64_t)tsDelta < cMilliesInitial)
610 cMilliesInitial = (unsigned)tsDelta;
611 else
612 cMilliesInitial = 1;
613 }
614 }
615
616#ifdef RTSEMRW_STRICT
617 rc = RTLockValidatorRecExclCheckBlocking(&pThis->ValidatorWrite, hThreadSelf, pSrcPos, true,
618 cMillies, RTTHREADSTATE_RW_WRITE, false);
619 if (RT_FAILURE(rc))
620 break;
621#else
622 RTThreadBlocking(hThreadSelf, RTTHREADSTATE_RW_WRITE, false);
623#endif
624 int rcWait;
625 if (fInterruptible)
626 rcWait = rc = RTSemEventWaitNoResume(pThis->WriteEvent, cMillies);
627 else
628 rcWait = rc = RTSemEventWait(pThis->WriteEvent, cMillies);
629 RTThreadUnblocked(hThreadSelf, RTTHREADSTATE_RW_WRITE);
630 if (RT_UNLIKELY(RT_FAILURE_NP(rc) && rc != VERR_TIMEOUT)) /* timeouts are handled below */
631 {
632 AssertMsgRC(rc, ("RTSemEventWait failed on rwsem %p, rc=%Rrc\n", RWSem, rc));
633 break;
634 }
635
636 if (RT_UNLIKELY(pThis->u32Magic != RTSEMRW_MAGIC))
637 {
638 rc = VERR_SEM_DESTROYED;
639 break;
640 }
641
642 /*
643 * Re-take critsect and repeate the check we did prior to this loop.
644 */
645 rc = RTCritSectEnter(&pThis->CritSect);
646 if (RT_FAILURE(rc))
647 {
648 AssertMsgFailed(("RTCritSectEnter failed on rwsem %p, rc=%Rrc\n", RWSem, rc));
649 break;
650 }
651
652 if (!pThis->cReads && (!pThis->cWrites || pThis->hWriter == hNativeSelf))
653 {
654 /*
655 * Reset the reader event semaphore if necessary.
656 */
657 if (pThis->fNeedResetReadEvent)
658 {
659 pThis->fNeedResetReadEvent = false;
660 rc = RTSemEventMultiReset(pThis->ReadEvent);
661 AssertMsgRC(rc, ("Failed to reset readers, rwsem %p, rc=%Rrc.\n", RWSem, rc));
662 }
663
664 pThis->cWrites++;
665 pThis->hWriter = hNativeSelf;
666 pThis->cWritesWaiting--;
667#ifdef RTSEMRW_STRICT
668 RTLockValidatorRecExclSetOwner(&pThis->ValidatorWrite, hThreadSelf, pSrcPos, true);
669#endif
670
671 RTCritSectLeave(&pThis->CritSect);
672 return VINF_SUCCESS;
673 }
674
675 RTCritSectLeave(&pThis->CritSect);
676
677 /*
678 * Quit if the wait already timed out.
679 */
680 if (rcWait == VERR_TIMEOUT)
681 {
682 rc = VERR_TIMEOUT;
683 break;
684 }
685 }
686
687 /*
688 * Timeout/error case, clean up.
689 */
690 if (pThis->u32Magic == RTSEMRW_MAGIC)
691 {
692 RTCritSectEnter(&pThis->CritSect);
693 /* Adjust this counter, whether we got the critsect or not. */
694 pThis->cWritesWaiting--;
695 RTCritSectLeave(&pThis->CritSect);
696 }
697 return rc;
698}
699
700
701RTDECL(int) RTSemRWRequestWrite(RTSEMRW RWSem, unsigned cMillies)
702{
703#ifndef RTSEMRW_STRICT
704 return rtSemRWRequestWrite(RWSem, cMillies, false, NULL);
705#else
706 RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_NORMAL_API();
707 return rtSemRWRequestWrite(RWSem, cMillies, false, &SrcPos);
708#endif
709}
710RT_EXPORT_SYMBOL(RTSemRWRequestWrite);
711
712
713RTDECL(int) RTSemRWRequestWriteDebug(RTSEMRW RWSem, unsigned cMillies, RTHCUINTPTR uId, RT_SRC_POS_DECL)
714{
715 RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_DEBUG_API();
716 return rtSemRWRequestWrite(RWSem, cMillies, false, &SrcPos);
717}
718RT_EXPORT_SYMBOL(RTSemRWRequestWriteDebug);
719
720
721RTDECL(int) RTSemRWRequestWriteNoResume(RTSEMRW RWSem, unsigned cMillies)
722{
723#ifndef RTSEMRW_STRICT
724 return rtSemRWRequestWrite(RWSem, cMillies, true, NULL);
725#else
726 RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_NORMAL_API();
727 return rtSemRWRequestWrite(RWSem, cMillies, true, &SrcPos);
728#endif
729}
730RT_EXPORT_SYMBOL(RTSemRWRequestWriteNoResume);
731
732
733RTDECL(int) RTSemRWRequestWriteNoResumeDebug(RTSEMRW RWSem, unsigned cMillies, RTHCUINTPTR uId, RT_SRC_POS_DECL)
734{
735 RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_DEBUG_API();
736 return rtSemRWRequestWrite(RWSem, cMillies, true, &SrcPos);
737}
738RT_EXPORT_SYMBOL(RTSemRWRequestWriteNoResumeDebug);
739
740
741RTDECL(int) RTSemRWReleaseWrite(RTSEMRW RWSem)
742{
743
744 /*
745 * Validate handle.
746 */
747 struct RTSEMRWINTERNAL *pThis = RWSem;
748 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
749 AssertReturn(pThis->u32Magic == RTSEMRW_MAGIC, VERR_INVALID_HANDLE);
750
751 /*
752 * Take critsect.
753 */
754 int rc = RTCritSectEnter(&pThis->CritSect);
755 AssertRCReturn(rc, rc);
756
757 /*
758 * Check if owner.
759 */
760 RTNATIVETHREAD hNativeSelf = pThis->CritSect.NativeThreadOwner;
761 if (pThis->hWriter != hNativeSelf)
762 {
763 RTCritSectLeave(&pThis->CritSect);
764 AssertMsgFailed(("Not read-write owner of rwsem %p.\n", RWSem));
765 return VERR_NOT_OWNER;
766 }
767
768#ifdef RTSEMRW_STRICT
769 if (pThis->cWrites > 1 || !pThis->cWriterReads) /* don't check+release if VERR_WRONG_ORDER */
770 {
771 int rc9 = RTLockValidatorRecExclReleaseOwner(&pThis->ValidatorWrite, pThis->cWrites == 1);
772 if (RT_FAILURE(rc9))
773 {
774 RTCritSectLeave(&pThis->CritSect);
775 return rc9;
776 }
777 }
778#endif
779
780 /*
781 * Release ownership and remove ourselves from the writers count.
782 */
783 Assert(pThis->cWrites > 0);
784 pThis->cWrites--;
785 if (!pThis->cWrites)
786 {
787 if (RT_UNLIKELY(pThis->cWriterReads > 0))
788 {
789 pThis->cWrites++;
790 RTCritSectLeave(&pThis->CritSect);
791 AssertMsgFailed(("All recursive read locks need to be released prior to the final write lock! (%p)n\n", pThis));
792 return VERR_WRONG_ORDER;
793 }
794
795 pThis->hWriter = NIL_RTNATIVETHREAD;
796 }
797
798 /*
799 * Release the readers if no more writers waiting, otherwise the writers.
800 */
801 if (!pThis->cWritesWaiting)
802 {
803 rc = RTSemEventMultiSignal(pThis->ReadEvent);
804 AssertMsgRC(rc, ("RTSemEventMultiSignal failed for rwsem %p, rc=%Rrc.\n", RWSem, rc));
805 pThis->fNeedResetReadEvent = true;
806 }
807 else
808 {
809 rc = RTSemEventSignal(pThis->WriteEvent);
810 AssertMsgRC(rc, ("Failed to signal writers on rwsem %p, rc=%Rrc\n", RWSem, rc));
811 }
812 RTCritSectLeave(&pThis->CritSect);
813
814 return rc;
815}
816RT_EXPORT_SYMBOL(RTSemRWReleaseWrite);
817
818
819RTDECL(bool) RTSemRWIsWriteOwner(RTSEMRW RWSem)
820{
821 struct RTSEMRWINTERNAL *pThis = RWSem;
822
823 /*
824 * Validate handle.
825 */
826 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
827 AssertReturn(pThis->u32Magic == RTSEMRW_MAGIC, VERR_INVALID_HANDLE);
828
829 /*
830 * Check ownership.
831 */
832 RTNATIVETHREAD hNativeSelf = RTThreadNativeSelf();
833 RTNATIVETHREAD hWriter;
834 ASMAtomicUoReadHandle(&pThis->hWriter, &hWriter);
835 return hWriter == hNativeSelf;
836}
837RT_EXPORT_SYMBOL(RTSemRWIsWriteOwner);
838
839
840RTDECL(uint32_t) RTSemRWGetWriteRecursion(RTSEMRW RWSem)
841{
842 struct RTSEMRWINTERNAL *pThis = RWSem;
843
844 /*
845 * Validate handle.
846 */
847 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
848 AssertReturn(pThis->u32Magic == RTSEMRW_MAGIC, VERR_INVALID_HANDLE);
849
850 /*
851 * Return the requested data.
852 */
853 return pThis->cWrites;
854}
855RT_EXPORT_SYMBOL(RTSemRWGetWriteRecursion);
856
857
858RTDECL(uint32_t) RTSemRWGetWriterReadRecursion(RTSEMRW RWSem)
859{
860 struct RTSEMRWINTERNAL *pThis = RWSem;
861
862 /*
863 * Validate handle.
864 */
865 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
866 AssertReturn(pThis->u32Magic == RTSEMRW_MAGIC, VERR_INVALID_HANDLE);
867
868 /*
869 * Return the requested data.
870 */
871 return pThis->cWriterReads;
872}
873RT_EXPORT_SYMBOL(RTSemRWGetWriterReadRecursion);
874
875
876RTDECL(uint32_t) RTSemRWGetReadCount(RTSEMRW RWSem)
877{
878 /*
879 * Validate input.
880 */
881 struct RTSEMRWINTERNAL *pThis = RWSem;
882 AssertPtrReturn(pThis, 0);
883 AssertMsgReturn(pThis->u32Magic == RTSEMRW_MAGIC,
884 ("pThis=%p u32Magic=%#x\n", pThis, pThis->u32Magic),
885 0);
886
887 /*
888 * Return the requested data.
889 */
890 return pThis->cReads;
891}
892RT_EXPORT_SYMBOL(RTSemRWGetReadCount);
893
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