VirtualBox

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

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

RTSemRWIsReadOwner: For assertion in main.

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