VirtualBox

source: vbox/trunk/src/VBox/Runtime/generic/critsectrw-generic.cpp@ 45110

Last change on this file since 45110 was 45110, checked in by vboxsync, 12 years ago

Raw conversion of semrw-lockless-generic.cpp into RTCritSectEx.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 31.6 KB
Line 
1/* $Id: critsectrw-generic.cpp 45110 2013-03-20 18:17:29Z vboxsync $ */
2/** @file
3 * IPRT - Read/Write Critical Section, Generic.
4 */
5
6/*
7 * Copyright (C) 2009-2013 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.215389.xyz. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27
28/*******************************************************************************
29* Header Files *
30*******************************************************************************/
31#define RTCRITSECTRW_WITHOUT_REMAPPING
32#define RTASSERT_QUIET
33#include <iprt/critsect.h>
34#include "internal/iprt.h"
35
36#include <iprt/asm.h>
37#include <iprt/assert.h>
38#include <iprt/err.h>
39#include <iprt/lockvalidator.h>
40#include <iprt/mem.h>
41#include <iprt/semaphore.h>
42#include <iprt/thread.h>
43
44#include "internal/magics.h"
45#include "internal/strict.h"
46
47
48/*******************************************************************************
49* Defined Constants And Macros *
50*******************************************************************************/
51/* Note! Using RTCSRW instead of RTCRITSECTRW to save space. */
52#define RTCSRW_CNT_BITS 15
53#define RTCSRW_CNT_MASK UINT64_C(0x00007fff)
54
55#define RTCSRW_CNT_RD_SHIFT 0
56#define RTCSRW_CNT_RD_MASK (RTCSRW_CNT_MASK << RTCSRW_CNT_RD_SHIFT)
57#define RTCSRW_CNT_WR_SHIFT 16
58#define RTCSRW_CNT_WR_MASK (RTCSRW_CNT_MASK << RTCSRW_CNT_WR_SHIFT)
59#define RTCSRW_DIR_SHIFT 31
60#define RTCSRW_DIR_MASK RT_BIT_64(RTCSRW_DIR_SHIFT)
61#define RTCSRW_DIR_READ UINT64_C(0)
62#define RTCSRW_DIR_WRITE UINT64_C(1)
63
64#define RTCSRW_WAIT_CNT_RD_SHIFT 32
65#define RTCSRW_WAIT_CNT_RD_MASK (RTCSRW_CNT_MASK << RTCSRW_WAIT_CNT_RD_SHIFT)
66//#define RTCSRW_WAIT_CNT_WR_SHIFT 48
67//#define RTCSRW_WAIT_CNT_WR_MASK (RTCSRW_CNT_MASK << RTCSRW_WAIT_CNT_WR_SHIFT)
68
69
70RTDECL(int) RTCritSectRwInit(PRTCRITSECTRW pThis)
71{
72 return RTCritSectRwInitEx(pThis, 0, NIL_RTLOCKVALCLASS, RTLOCKVAL_SUB_CLASS_NONE, "RTCritSectRw");
73}
74RT_EXPORT_SYMBOL(RTCritSectRwInit);
75
76
77RTDECL(int) RTCritSectRwInitEx(PRTCRITSECTRW pThis, uint32_t fFlags,
78 RTLOCKVALCLASS hClass, uint32_t uSubClass, const char *pszNameFmt, ...)
79{
80 int rc;
81 AssertReturn(!(fFlags & ~( RTCRITSECT_FLAGS_NO_NESTING | RTCRITSECT_FLAGS_NO_LOCK_VAL | RTCRITSECT_FLAGS_BOOTSTRAP_HACK
82 | RTCRITSECT_FLAGS_NOP )),
83 VERR_INVALID_PARAMETER);
84
85 /*
86 * Initialize the structure, allocate the lock validator stuff and sems.
87 */
88 pThis->u32Magic = RTCRITSECTRW_MAGIC_DEAD;
89 pThis->fNeedReset = false;
90 pThis->u64State = 0;
91 pThis->hNativeWriter = NIL_RTNATIVETHREAD;
92 pThis->cWriterReads = 0;
93 pThis->cWriteRecursions = 0;
94 pThis->hEvtWrite = NIL_RTSEMEVENT;
95 pThis->hEvtRead = NIL_RTSEMEVENTMULTI;
96 pThis->pValidatorWrite = NULL;
97 pThis->pValidatorRead = NULL;
98#if HC_ARCH_BITS == 32
99 pThis->HCPtrPadding = NIL_RTHCPTR;
100#endif
101
102#ifdef RTCRITSECTRW_STRICT
103 bool const fLVEnabled = !(fFlags & RTSEMRW_FLAGS_NO_LOCK_VAL);
104 if (!pszNameFmt)
105 {
106 static uint32_t volatile s_iAnon = 0;
107 uint32_t i = ASMAtomicIncU32(&s_iAnon) - 1;
108 rc = RTLockValidatorRecExclCreate(&pThis->pValidatorWrite, hClass, uSubClass, pThis,
109 fLVEnabled, "RTCritSectRw-%u", i);
110 if (RT_SUCCESS(rc))
111 rc = RTLockValidatorRecSharedCreate(&pThis->pValidatorRead, hClass, uSubClass, pThis,
112 false /*fSignaller*/, fLVEnabled, "RTCritSectRw-%u", i);
113 }
114 else
115 {
116 va_list va;
117 va_start(va, pszNameFmt);
118 rc = RTLockValidatorRecExclCreateV(&pThis->pValidatorWrite, hClass, uSubClass, pThis,
119 fLVEnabled, pszNameFmt, va);
120 va_end(va);
121 if (RT_SUCCESS(rc))
122 {
123 va_start(va, pszNameFmt);
124 RTLockValidatorRecSharedCreateV(&pThis->pValidatorRead, hClass, uSubClass, pThis,
125 false /*fSignaller*/, fLVEnabled, pszNameFmt, va);
126 va_end(va);
127 }
128 }
129 if (RT_SUCCESS(rc))
130 rc = RTLockValidatorRecMakeSiblings(&pThis->pValidatorWrite->Core, &pThis->pValidatorRead->Core);
131
132 if (RT_SUCCESS(rc))
133#endif
134 {
135 rc = RTSemEventMultiCreate(&pThis->hEvtRead);
136 if (RT_SUCCESS(rc))
137 {
138 rc = RTSemEventCreate(&pThis->hEvtWrite);
139 if (RT_SUCCESS(rc))
140 {
141 pThis->u32Magic = RTCRITSECTRW_MAGIC;
142 return VINF_SUCCESS;
143 }
144 RTSemEventMultiDestroy(pThis->hEvtRead);
145 }
146 }
147
148#ifdef RTCRITSECTRW_STRICT
149 RTLockValidatorRecSharedDestroy(&pThis->pValidatorRead);
150 RTLockValidatorRecExclDestroy(&pThis->pValidatorWrite);
151#endif
152 return rc;
153}
154RT_EXPORT_SYMBOL(RTCritSectRwInitEx);
155
156
157RTDECL(uint32_t) RTCritSectRwSetSubClass(PRTCRITSECTRW pThis, uint32_t uSubClass)
158{
159 AssertPtrReturn(pThis, RTLOCKVAL_SUB_CLASS_INVALID);
160 AssertReturn(pThis->u32Magic == RTCRITSECTRW_MAGIC, RTLOCKVAL_SUB_CLASS_INVALID);
161#ifdef RTCRITSECTRW_STRICT
162 AssertReturn(!(pThis->fFlags & RTCRITSECT_FLAGS_NOP), RTLOCKVAL_SUB_CLASS_INVALID);
163
164 RTLockValidatorRecSharedSetSubClass(pThis->pValidatorRead, uSubClass);
165 return RTLockValidatorRecExclSetSubClass(pThis->pValidatorWrite, uSubClass);
166#else
167 NOREF(uSubClass);
168 return RTLOCKVAL_SUB_CLASS_INVALID;
169#endif
170}
171RT_EXPORT_SYMBOL(RTCritSectRwSetSubClass);
172
173
174static int rtCritSectRwEnterShared(PRTCRITSECTRW pThis, PCRTLOCKVALSRCPOS pSrcPos, bool fTryOnly)
175{
176 /*
177 * Validate input.
178 */
179 AssertPtr(pThis);
180 AssertReturn(pThis->u32Magic == RTCRITSECTRW_MAGIC, VERR_SEM_DESTROYED);
181
182#ifdef RTCRITSECTRW_STRICT
183 RTTHREAD hThreadSelf = RTThreadSelfAutoAdopt();
184 if (!fTryOnly)
185 {
186 int rc9;
187 RTNATIVETHREAD hNativeWriter;
188 ASMAtomicUoReadHandle(&pThis->hNativeWriter, &hNativeWriter);
189 if (hNativeWriter != NIL_RTTHREAD && hNativeWriter == RTThreadNativeSelf())
190 rc9 = RTLockValidatorRecExclCheckOrder(pThis->pValidatorWrite, hThreadSelf, pSrcPos, RT_INDEFINITE_WAIT);
191 else
192 rc9 = RTLockValidatorRecSharedCheckOrder(pThis->pValidatorRead, hThreadSelf, pSrcPos, RT_INDEFINITE_WAIT);
193 if (RT_FAILURE(rc9))
194 return rc9;
195 }
196#endif
197
198 /*
199 * Get cracking...
200 */
201 uint64_t u64State = ASMAtomicReadU64(&pThis->u64State);
202 uint64_t u64OldState = u64State;
203
204 for (;;)
205 {
206 if ((u64State & RTCSRW_DIR_MASK) == (RTCSRW_DIR_READ << RTCSRW_DIR_SHIFT))
207 {
208 /* It flows in the right direction, try follow it before it changes. */
209 uint64_t c = (u64State & RTCSRW_CNT_RD_MASK) >> RTCSRW_CNT_RD_SHIFT;
210 c++;
211 Assert(c < RTCSRW_CNT_MASK / 2);
212 u64State &= ~RTCSRW_CNT_RD_MASK;
213 u64State |= c << RTCSRW_CNT_RD_SHIFT;
214 if (ASMAtomicCmpXchgU64(&pThis->u64State, u64State, u64OldState))
215 {
216#ifdef RTCRITSECTRW_STRICT
217 RTLockValidatorRecSharedAddOwner(pThis->pValidatorRead, hThreadSelf, pSrcPos);
218#endif
219 break;
220 }
221 }
222 else if ((u64State & (RTCSRW_CNT_RD_MASK | RTCSRW_CNT_WR_MASK)) == 0)
223 {
224 /* Wrong direction, but we're alone here and can simply try switch the direction. */
225 u64State &= ~(RTCSRW_CNT_RD_MASK | RTCSRW_CNT_WR_MASK | RTCSRW_DIR_MASK);
226 u64State |= (UINT64_C(1) << RTCSRW_CNT_RD_SHIFT) | (RTCSRW_DIR_READ << RTCSRW_DIR_SHIFT);
227 if (ASMAtomicCmpXchgU64(&pThis->u64State, u64State, u64OldState))
228 {
229 Assert(!pThis->fNeedReset);
230#ifdef RTCRITSECTRW_STRICT
231 RTLockValidatorRecSharedAddOwner(pThis->pValidatorRead, hThreadSelf, pSrcPos);
232#endif
233 break;
234 }
235 }
236 else
237 {
238 /* Is the writer perhaps doing a read recursion? */
239 RTNATIVETHREAD hNativeSelf = RTThreadNativeSelf();
240 RTNATIVETHREAD hNativeWriter;
241 ASMAtomicUoReadHandle(&pThis->hNativeWriter, &hNativeWriter);
242 if (hNativeSelf == hNativeWriter)
243 {
244#ifdef RTCRITSECTRW_STRICT
245 int rc9 = RTLockValidatorRecExclRecursionMixed(pThis->pValidatorWrite, &pThis->pValidatorRead->Core, pSrcPos);
246 if (RT_FAILURE(rc9))
247 return rc9;
248#endif
249 Assert(pThis->cWriterReads < UINT32_MAX / 2);
250 ASMAtomicIncU32(&pThis->cWriterReads);
251 return VINF_SUCCESS; /* don't break! */
252 }
253
254 /* If we're only trying, return already. */
255 if (fTryOnly)
256 return VERR_SEM_BUSY;
257
258 /* Add ourselves to the queue and wait for the direction to change. */
259 uint64_t c = (u64State & RTCSRW_CNT_RD_MASK) >> RTCSRW_CNT_RD_SHIFT;
260 c++;
261 Assert(c < RTCSRW_CNT_MASK / 2);
262
263 uint64_t cWait = (u64State & RTCSRW_WAIT_CNT_RD_MASK) >> RTCSRW_WAIT_CNT_RD_SHIFT;
264 cWait++;
265 Assert(cWait <= c);
266 Assert(cWait < RTCSRW_CNT_MASK / 2);
267
268 u64State &= ~(RTCSRW_CNT_RD_MASK | RTCSRW_WAIT_CNT_RD_MASK);
269 u64State |= (c << RTCSRW_CNT_RD_SHIFT) | (cWait << RTCSRW_WAIT_CNT_RD_SHIFT);
270
271 if (ASMAtomicCmpXchgU64(&pThis->u64State, u64State, u64OldState))
272 {
273 for (uint32_t iLoop = 0; ; iLoop++)
274 {
275 int rc;
276#ifdef RTCRITSECTRW_STRICT
277 rc = RTLockValidatorRecSharedCheckBlocking(pThis->pValidatorRead, hThreadSelf, pSrcPos, true,
278 RT_INDEFINITE_WAIT, RTTHREADSTATE_RW_READ, false);
279 if (RT_SUCCESS(rc))
280#else
281 RTTHREAD hThreadSelf = RTThreadSelf();
282 RTThreadBlocking(hThreadSelf, RTTHREADSTATE_RW_READ, false);
283#endif
284 {
285 rc = RTSemEventMultiWait(pThis->hEvtRead, RT_INDEFINITE_WAIT);
286 RTThreadUnblocked(hThreadSelf, RTTHREADSTATE_RW_READ);
287 if (pThis->u32Magic != RTCRITSECTRW_MAGIC)
288 return VERR_SEM_DESTROYED;
289 }
290 if (RT_FAILURE(rc))
291 {
292 /* Decrement the counts and return the error. */
293 for (;;)
294 {
295 u64OldState = u64State = ASMAtomicReadU64(&pThis->u64State);
296 c = (u64State & RTCSRW_CNT_RD_MASK) >> RTCSRW_CNT_RD_SHIFT; Assert(c > 0);
297 c--;
298 cWait = (u64State & RTCSRW_WAIT_CNT_RD_MASK) >> RTCSRW_WAIT_CNT_RD_SHIFT; Assert(cWait > 0);
299 cWait--;
300 u64State &= ~(RTCSRW_CNT_RD_MASK | RTCSRW_WAIT_CNT_RD_MASK);
301 u64State |= (c << RTCSRW_CNT_RD_SHIFT) | (cWait << RTCSRW_WAIT_CNT_RD_SHIFT);
302 if (ASMAtomicCmpXchgU64(&pThis->u64State, u64State, u64OldState))
303 break;
304 }
305 return rc;
306 }
307
308 Assert(pThis->fNeedReset);
309 u64State = ASMAtomicReadU64(&pThis->u64State);
310 if ((u64State & RTCSRW_DIR_MASK) == (RTCSRW_DIR_READ << RTCSRW_DIR_SHIFT))
311 break;
312 AssertMsg(iLoop < 1, ("%u\n", iLoop));
313 }
314
315 /* Decrement the wait count and maybe reset the semaphore (if we're last). */
316 for (;;)
317 {
318 u64OldState = u64State;
319
320 cWait = (u64State & RTCSRW_WAIT_CNT_RD_MASK) >> RTCSRW_WAIT_CNT_RD_SHIFT;
321 Assert(cWait > 0);
322 cWait--;
323 u64State &= ~RTCSRW_WAIT_CNT_RD_MASK;
324 u64State |= cWait << RTCSRW_WAIT_CNT_RD_SHIFT;
325
326 if (ASMAtomicCmpXchgU64(&pThis->u64State, u64State, u64OldState))
327 {
328 if (cWait == 0)
329 {
330 if (ASMAtomicXchgBool(&pThis->fNeedReset, false))
331 {
332 int rc = RTSemEventMultiReset(pThis->hEvtRead);
333 AssertRCReturn(rc, rc);
334 }
335 }
336 break;
337 }
338 u64State = ASMAtomicReadU64(&pThis->u64State);
339 }
340
341#ifdef RTCRITSECTRW_STRICT
342 RTLockValidatorRecSharedAddOwner(pThis->pValidatorRead, hThreadSelf, pSrcPos);
343#endif
344 break;
345 }
346 }
347
348 if (pThis->u32Magic != RTCRITSECTRW_MAGIC)
349 return VERR_SEM_DESTROYED;
350
351 ASMNopPause();
352 u64State = ASMAtomicReadU64(&pThis->u64State);
353 u64OldState = u64State;
354 }
355
356 /* got it! */
357 Assert((ASMAtomicReadU64(&pThis->u64State) & RTCSRW_DIR_MASK) == (RTCSRW_DIR_READ << RTCSRW_DIR_SHIFT));
358 return VINF_SUCCESS;
359
360}
361
362
363RTDECL(int) RTCritSectRwEnterShared(PRTCRITSECTRW pThis)
364{
365#ifndef RTCRITSECTRW_STRICT
366 return rtCritSectRwEnterShared(pThis, NULL, false /*fTryOnly*/);
367#else
368 RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_NORMAL_API();
369 return rtCritSectRwEnterShared(pThis, &SrcPos, false /*fTryOnly*/);
370#endif
371}
372RT_EXPORT_SYMBOL(RTCritSectRwEnterShared);
373
374
375RTDECL(int) RTCritSectRwEnterSharedDebug(PRTCRITSECTRW pThis, RTHCUINTPTR uId, RT_SRC_POS_DECL)
376{
377 RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_DEBUG_API();
378 return rtCritSectRwEnterShared(pThis, &SrcPos, false /*fTryOnly*/);
379}
380RT_EXPORT_SYMBOL(RTCritSectRwEnterSharedDebug);
381
382
383RTDECL(int) RTCritSectRwTryEnterShared(PRTCRITSECTRW pThis)
384{
385#ifndef RTCRITSECTRW_STRICT
386 return rtCritSectRwEnterShared(pThis, NULL, true /*fTryOnly*/);
387#else
388 RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_NORMAL_API();
389 return rtCritSectRwEnterShared(pThis, &SrcPos, true /*fTryOnly*/);
390#endif
391}
392RT_EXPORT_SYMBOL(RTCritSectRwEnterShared);
393
394
395RTDECL(int) RTCritSectRwTryEnterSharedDebug(PRTCRITSECTRW pThis, RTHCUINTPTR uId, RT_SRC_POS_DECL)
396{
397 RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_DEBUG_API();
398 return rtCritSectRwEnterShared(pThis, &SrcPos, true /*fTryOnly*/);
399}
400RT_EXPORT_SYMBOL(RTCritSectRwEnterSharedDebug);
401
402
403
404RTDECL(int) RTCritSectRwLeaveShared(PRTCRITSECTRW pThis)
405{
406 /*
407 * Validate handle.
408 */
409 AssertPtr(pThis);
410 AssertReturn(pThis->u32Magic == RTCRITSECTRW_MAGIC, VERR_SEM_DESTROYED);
411
412 /*
413 * Check the direction and take action accordingly.
414 */
415 uint64_t u64State = ASMAtomicReadU64(&pThis->u64State);
416 uint64_t u64OldState = u64State;
417 if ((u64State & RTCSRW_DIR_MASK) == (RTCSRW_DIR_READ << RTCSRW_DIR_SHIFT))
418 {
419#ifdef RTCRITSECTRW_STRICT
420 int rc9 = RTLockValidatorRecSharedCheckAndRelease(pThis->pValidatorRead, NIL_RTTHREAD);
421 if (RT_FAILURE(rc9))
422 return rc9;
423#endif
424 for (;;)
425 {
426 uint64_t c = (u64State & RTCSRW_CNT_RD_MASK) >> RTCSRW_CNT_RD_SHIFT;
427 AssertReturn(c > 0, VERR_NOT_OWNER);
428 c--;
429
430 if ( c > 0
431 || (u64State & RTCSRW_CNT_RD_MASK) == 0)
432 {
433 /* Don't change the direction. */
434 u64State &= ~RTCSRW_CNT_RD_MASK;
435 u64State |= c << RTCSRW_CNT_RD_SHIFT;
436 if (ASMAtomicCmpXchgU64(&pThis->u64State, u64State, u64OldState))
437 break;
438 }
439 else
440 {
441 /* Reverse the direction and signal the reader threads. */
442 u64State &= ~(RTCSRW_CNT_RD_MASK | RTCSRW_DIR_MASK);
443 u64State |= RTCSRW_DIR_WRITE << RTCSRW_DIR_SHIFT;
444 if (ASMAtomicCmpXchgU64(&pThis->u64State, u64State, u64OldState))
445 {
446 int rc = RTSemEventSignal(pThis->hEvtWrite);
447 AssertRC(rc);
448 break;
449 }
450 }
451
452 ASMNopPause();
453 u64State = ASMAtomicReadU64(&pThis->u64State);
454 u64OldState = u64State;
455 }
456 }
457 else
458 {
459 RTNATIVETHREAD hNativeSelf = RTThreadNativeSelf();
460 RTNATIVETHREAD hNativeWriter;
461 ASMAtomicUoReadHandle(&pThis->hNativeWriter, &hNativeWriter);
462 AssertReturn(hNativeSelf == hNativeWriter, VERR_NOT_OWNER);
463 AssertReturn(pThis->cWriterReads > 0, VERR_NOT_OWNER);
464#ifdef RTCRITSECTRW_STRICT
465 int rc = RTLockValidatorRecExclUnwindMixed(pThis->pValidatorWrite, &pThis->pValidatorRead->Core);
466 if (RT_FAILURE(rc))
467 return rc;
468#endif
469 ASMAtomicDecU32(&pThis->cWriterReads);
470 }
471
472 return VINF_SUCCESS;
473}
474RT_EXPORT_SYMBOL(RTCritSectRwLeaveShared);
475
476
477static int rtCritSectRwEnterExcl(PRTCRITSECTRW pThis, PCRTLOCKVALSRCPOS pSrcPos, bool fTryOnly)
478{
479 /*
480 * Validate input.
481 */
482 AssertPtr(pThis);
483 AssertReturn(pThis->u32Magic == RTCRITSECTRW_MAGIC, VERR_SEM_DESTROYED);
484
485#ifdef RTCRITSECTRW_STRICT
486 RTTHREAD hThreadSelf = NIL_RTTHREAD;
487 if (!fTryOnly)
488 {
489 hThreadSelf = RTThreadSelfAutoAdopt();
490 int rc9 = RTLockValidatorRecExclCheckOrder(pThis->pValidatorWrite, hThreadSelf, pSrcPos, RT_INDEFINITE_WAIT);
491 if (RT_FAILURE(rc9))
492 return rc9;
493 }
494#endif
495
496 /*
497 * Check if we're already the owner and just recursing.
498 */
499 RTNATIVETHREAD hNativeSelf = RTThreadNativeSelf();
500 RTNATIVETHREAD hNativeWriter;
501 ASMAtomicUoReadHandle(&pThis->hNativeWriter, &hNativeWriter);
502 if (hNativeSelf == hNativeWriter)
503 {
504 Assert((ASMAtomicReadU64(&pThis->u64State) & RTCSRW_DIR_MASK) == (RTCSRW_DIR_WRITE << RTCSRW_DIR_SHIFT));
505#ifdef RTCRITSECTRW_STRICT
506 int rc9 = RTLockValidatorRecExclRecursion(pThis->pValidatorWrite, pSrcPos);
507 if (RT_FAILURE(rc9))
508 return rc9;
509#endif
510 Assert(pThis->cWriteRecursions < UINT32_MAX / 2);
511 ASMAtomicIncU32(&pThis->cWriteRecursions);
512 return VINF_SUCCESS;
513 }
514
515 /*
516 * Get cracking.
517 */
518 uint64_t u64State = ASMAtomicReadU64(&pThis->u64State);
519 uint64_t u64OldState = u64State;
520
521 for (;;)
522 {
523 if ( (u64State & RTCSRW_DIR_MASK) == (RTCSRW_DIR_WRITE << RTCSRW_DIR_SHIFT)
524 || (u64State & (RTCSRW_CNT_RD_MASK | RTCSRW_CNT_WR_MASK)) != 0)
525 {
526 /* It flows in the right direction, try follow it before it changes. */
527 uint64_t c = (u64State & RTCSRW_CNT_WR_MASK) >> RTCSRW_CNT_WR_SHIFT;
528 c++;
529 Assert(c < RTCSRW_CNT_MASK / 2);
530 u64State &= ~RTCSRW_CNT_WR_MASK;
531 u64State |= c << RTCSRW_CNT_WR_SHIFT;
532 if (ASMAtomicCmpXchgU64(&pThis->u64State, u64State, u64OldState))
533 break;
534 }
535 else if ((u64State & (RTCSRW_CNT_RD_MASK | RTCSRW_CNT_WR_MASK)) == 0)
536 {
537 /* Wrong direction, but we're alone here and can simply try switch the direction. */
538 u64State &= ~(RTCSRW_CNT_RD_MASK | RTCSRW_CNT_WR_MASK | RTCSRW_DIR_MASK);
539 u64State |= (UINT64_C(1) << RTCSRW_CNT_WR_SHIFT) | (RTCSRW_DIR_WRITE << RTCSRW_DIR_SHIFT);
540 if (ASMAtomicCmpXchgU64(&pThis->u64State, u64State, u64OldState))
541 break;
542 }
543 else if (fTryOnly)
544 /* Wrong direction and we're not supposed to wait, just return. */
545 return VERR_SEM_BUSY;
546 else
547 {
548 /* Add ourselves to the write count and break out to do the wait. */
549 uint64_t c = (u64State & RTCSRW_CNT_WR_MASK) >> RTCSRW_CNT_WR_SHIFT;
550 c++;
551 Assert(c < RTCSRW_CNT_MASK / 2);
552 u64State &= ~RTCSRW_CNT_WR_MASK;
553 u64State |= c << RTCSRW_CNT_WR_SHIFT;
554 if (ASMAtomicCmpXchgU64(&pThis->u64State, u64State, u64OldState))
555 break;
556 }
557
558 if (pThis->u32Magic != RTCRITSECTRW_MAGIC)
559 return VERR_SEM_DESTROYED;
560
561 ASMNopPause();
562 u64State = ASMAtomicReadU64(&pThis->u64State);
563 u64OldState = u64State;
564 }
565
566 /*
567 * If we're in write mode now try grab the ownership. Play fair if there
568 * are threads already waiting.
569 */
570 bool fDone = (u64State & RTCSRW_DIR_MASK) == (RTCSRW_DIR_WRITE << RTCSRW_DIR_SHIFT)
571 && ( ((u64State & RTCSRW_CNT_WR_MASK) >> RTCSRW_CNT_WR_SHIFT) == 1
572 || fTryOnly);
573 if (fDone)
574 ASMAtomicCmpXchgHandle(&pThis->hNativeWriter, hNativeSelf, NIL_RTNATIVETHREAD, fDone);
575 if (!fDone)
576 {
577 /*
578 * Wait for our turn.
579 */
580 for (uint32_t iLoop = 0; ; iLoop++)
581 {
582 int rc;
583#ifdef RTCRITSECTRW_STRICT
584 if (!fTryOnly)
585 {
586 if (hThreadSelf == NIL_RTTHREAD)
587 hThreadSelf = RTThreadSelfAutoAdopt();
588 rc = RTLockValidatorRecExclCheckBlocking(pThis->pValidatorWrite, hThreadSelf, pSrcPos, true,
589 RT_INDEFINITE_WAIT, RTTHREADSTATE_RW_WRITE, false);
590 }
591 else
592 rc = VINF_SUCCESS;
593 if (RT_SUCCESS(rc))
594#else
595 RTTHREAD hThreadSelf = RTThreadSelf();
596 RTThreadBlocking(hThreadSelf, RTTHREADSTATE_RW_WRITE, false);
597#endif
598 {
599 rc = RTSemEventWait(pThis->hEvtWrite, RT_INDEFINITE_WAIT);
600 RTThreadUnblocked(hThreadSelf, RTTHREADSTATE_RW_WRITE);
601 if (pThis->u32Magic != RTCRITSECTRW_MAGIC)
602 return VERR_SEM_DESTROYED;
603 }
604 if (RT_FAILURE(rc))
605 {
606 /* Decrement the counts and return the error. */
607 for (;;)
608 {
609 u64OldState = u64State = ASMAtomicReadU64(&pThis->u64State);
610 uint64_t c = (u64State & RTCSRW_CNT_WR_MASK) >> RTCSRW_CNT_WR_SHIFT; Assert(c > 0);
611 c--;
612 u64State &= ~RTCSRW_CNT_WR_MASK;
613 u64State |= c << RTCSRW_CNT_WR_SHIFT;
614 if (ASMAtomicCmpXchgU64(&pThis->u64State, u64State, u64OldState))
615 break;
616 }
617 return rc;
618 }
619
620 u64State = ASMAtomicReadU64(&pThis->u64State);
621 if ((u64State & RTCSRW_DIR_MASK) == (RTCSRW_DIR_WRITE << RTCSRW_DIR_SHIFT))
622 {
623 ASMAtomicCmpXchgHandle(&pThis->hNativeWriter, hNativeSelf, NIL_RTNATIVETHREAD, fDone);
624 if (fDone)
625 break;
626 }
627 AssertMsg(iLoop < 1000, ("%u\n", iLoop)); /* may loop a few times here... */
628 }
629 }
630
631 /*
632 * Got it!
633 */
634 Assert((ASMAtomicReadU64(&pThis->u64State) & RTCSRW_DIR_MASK) == (RTCSRW_DIR_WRITE << RTCSRW_DIR_SHIFT));
635 ASMAtomicWriteU32(&pThis->cWriteRecursions, 1);
636 Assert(pThis->cWriterReads == 0);
637#ifdef RTCRITSECTRW_STRICT
638 RTLockValidatorRecExclSetOwner(pThis->pValidatorWrite, hThreadSelf, pSrcPos, true);
639#endif
640
641 return VINF_SUCCESS;
642}
643
644
645RTDECL(int) RTCritSectRwEnterExcl(PRTCRITSECTRW pThis)
646{
647#ifndef RTCRITSECTRW_STRICT
648 return rtCritSectRwEnterExcl(pThis, NULL, false /*fTryAgain*/);
649#else
650 RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_NORMAL_API();
651 return rtCritSectRwEnterExcl(pThis, &SrcPos, false /*fTryAgain*/);
652#endif
653}
654RT_EXPORT_SYMBOL(RTCritSectRwEnterExcl);
655
656
657RTDECL(int) RTCritSectRwEnterExclDebug(PRTCRITSECTRW pThis, RTHCUINTPTR uId, RT_SRC_POS_DECL)
658{
659 RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_DEBUG_API();
660 return rtCritSectRwEnterExcl(pThis, &SrcPos, false /*fTryAgain*/);
661}
662RT_EXPORT_SYMBOL(RTCritSectRwEnterExclDebug);
663
664
665RTDECL(int) RTCritSectRwTryEnterExcl(PRTCRITSECTRW pThis)
666{
667#ifndef RTCRITSECTRW_STRICT
668 return rtCritSectRwEnterExcl(pThis, NULL, true /*fTryAgain*/);
669#else
670 RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_NORMAL_API();
671 return rtCritSectRwEnterExcl(pThis, &SrcPos, true /*fTryAgain*/);
672#endif
673}
674RT_EXPORT_SYMBOL(RTCritSectRwTryEnterExcl);
675
676
677RTDECL(int) RTCritSectRwTryEnterExclDebug(PRTCRITSECTRW pThis, RTHCUINTPTR uId, RT_SRC_POS_DECL)
678{
679 RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_DEBUG_API();
680 return rtCritSectRwEnterExcl(pThis, &SrcPos, true /*fTryAgain*/);
681}
682RT_EXPORT_SYMBOL(RTCritSectRwTryEnterExclDebug);
683
684
685RTDECL(int) RTCritSectRwLeaveExcl(PRTCRITSECTRW pThis)
686{
687 /*
688 * Validate handle.
689 */
690 AssertPtr(pThis);
691 AssertReturn(pThis->u32Magic == RTCRITSECTRW_MAGIC, VERR_SEM_DESTROYED);
692
693 RTNATIVETHREAD hNativeSelf = RTThreadNativeSelf();
694 RTNATIVETHREAD hNativeWriter;
695 ASMAtomicUoReadHandle(&pThis->hNativeWriter, &hNativeWriter);
696 AssertReturn(hNativeSelf == hNativeWriter, VERR_NOT_OWNER);
697
698 /*
699 * Unwind a recursion.
700 */
701 if (pThis->cWriteRecursions == 1)
702 {
703 AssertReturn(pThis->cWriterReads == 0, VERR_WRONG_ORDER); /* (must release all read recursions before the final write.) */
704#ifdef RTCRITSECTRW_STRICT
705 int rc9 = RTLockValidatorRecExclReleaseOwner(pThis->pValidatorWrite, true);
706 if (RT_FAILURE(rc9))
707 return rc9;
708#endif
709 /*
710 * Update the state.
711 */
712 ASMAtomicWriteU32(&pThis->cWriteRecursions, 0);
713 ASMAtomicWriteHandle(&pThis->hNativeWriter, NIL_RTNATIVETHREAD);
714
715 for (;;)
716 {
717 uint64_t u64State = ASMAtomicReadU64(&pThis->u64State);
718 uint64_t u64OldState = u64State;
719
720 uint64_t c = (u64State & RTCSRW_CNT_WR_MASK) >> RTCSRW_CNT_WR_SHIFT;
721 Assert(c > 0);
722 c--;
723
724 if ( c > 0
725 || (u64State & RTCSRW_CNT_RD_MASK) == 0)
726 {
727 /* Don't change the direction, wait up the next writer if any. */
728 u64State &= ~RTCSRW_CNT_WR_MASK;
729 u64State |= c << RTCSRW_CNT_WR_SHIFT;
730 if (ASMAtomicCmpXchgU64(&pThis->u64State, u64State, u64OldState))
731 {
732 if (c > 0)
733 {
734 int rc = RTSemEventSignal(pThis->hEvtWrite);
735 AssertRC(rc);
736 }
737 break;
738 }
739 }
740 else
741 {
742 /* Reverse the direction and signal the reader threads. */
743 u64State &= ~(RTCSRW_CNT_WR_MASK | RTCSRW_DIR_MASK);
744 u64State |= RTCSRW_DIR_READ << RTCSRW_DIR_SHIFT;
745 if (ASMAtomicCmpXchgU64(&pThis->u64State, u64State, u64OldState))
746 {
747 Assert(!pThis->fNeedReset);
748 ASMAtomicWriteBool(&pThis->fNeedReset, true);
749 int rc = RTSemEventMultiSignal(pThis->hEvtRead);
750 AssertRC(rc);
751 break;
752 }
753 }
754
755 ASMNopPause();
756 if (pThis->u32Magic != RTCRITSECTRW_MAGIC)
757 return VERR_SEM_DESTROYED;
758 }
759 }
760 else
761 {
762 Assert(pThis->cWriteRecursions != 0);
763#ifdef RTCRITSECTRW_STRICT
764 int rc9 = RTLockValidatorRecExclUnwind(pThis->pValidatorWrite);
765 if (RT_FAILURE(rc9))
766 return rc9;
767#endif
768 ASMAtomicDecU32(&pThis->cWriteRecursions);
769 }
770
771 return VINF_SUCCESS;
772}
773RT_EXPORT_SYMBOL(RTSemRWReleaseWrite);
774
775
776RTDECL(bool) RTCritSectRwIsWriteOwner(PRTCRITSECTRW pThis)
777{
778 /*
779 * Validate handle.
780 */
781 AssertPtr(pThis);
782 AssertReturn(pThis->u32Magic == RTCRITSECTRW_MAGIC, false);
783
784 /*
785 * Check ownership.
786 */
787 RTNATIVETHREAD hNativeSelf = RTThreadNativeSelf();
788 RTNATIVETHREAD hNativeWriter;
789 ASMAtomicUoReadHandle(&pThis->hNativeWriter, &hNativeWriter);
790 return hNativeWriter == hNativeSelf;
791}
792RT_EXPORT_SYMBOL(RTCritSectRwIsWriteOwner);
793
794
795RTDECL(bool) RTCritSectRwIsReadOwner(PRTCRITSECTRW pThis, bool fWannaHear)
796{
797 /*
798 * Validate handle.
799 */
800 AssertPtr(pThis);
801 AssertReturn(pThis->u32Magic == RTCRITSECTRW_MAGIC, false);
802
803 /*
804 * Inspect the state.
805 */
806 uint64_t u64State = ASMAtomicReadU64(&pThis->u64State);
807 if ((u64State & RTCSRW_DIR_MASK) == (RTCSRW_DIR_WRITE << RTCSRW_DIR_SHIFT))
808 {
809 /*
810 * It's in write mode, so we can only be a reader if we're also the
811 * current writer.
812 */
813 RTNATIVETHREAD hNativeSelf = RTThreadNativeSelf();
814 RTNATIVETHREAD hWriter;
815 ASMAtomicUoReadHandle(&pThis->hNativeWriter, &hWriter);
816 return hWriter == hNativeSelf;
817 }
818
819 /*
820 * Read mode. If there are no current readers, then we cannot be a reader.
821 */
822 if (!(u64State & RTCSRW_CNT_RD_MASK))
823 return false;
824
825#ifdef RTCRITSECTRW_STRICT
826 /*
827 * Ask the lock validator.
828 */
829 return RTLockValidatorRecSharedIsOwner(pThis->pValidatorRead, NIL_RTTHREAD);
830#else
831 /*
832 * Ok, we don't know, just tell the caller what he want to hear.
833 */
834 return fWannaHear;
835#endif
836}
837RT_EXPORT_SYMBOL(RTCritSectRwIsReadOwner);
838
839
840RTDECL(uint32_t) RTCritSectRwGetWriteRecursion(PRTCRITSECTRW pThis)
841{
842 /*
843 * Validate handle.
844 */
845 AssertPtr(pThis);
846 AssertReturn(pThis->u32Magic == RTCRITSECTRW_MAGIC, 0);
847
848 /*
849 * Return the requested data.
850 */
851 return pThis->cWriteRecursions;
852}
853RT_EXPORT_SYMBOL(RTCritSectRwGetWriteRecursion);
854
855
856RTDECL(uint32_t) RTCritSectRwGetWriterReadRecursion(PRTCRITSECTRW pThis)
857{
858 /*
859 * Validate handle.
860 */
861 AssertPtr(pThis);
862 AssertReturn(pThis->u32Magic == RTCRITSECTRW_MAGIC, 0);
863
864 /*
865 * Return the requested data.
866 */
867 return pThis->cWriterReads;
868}
869RT_EXPORT_SYMBOL(RTSemRWGetWriterReadRecursion);
870
871
872RTDECL(uint32_t) RTSemRWGetReadCount(PRTCRITSECTRW pThis)
873{
874 /*
875 * Validate input.
876 */
877 AssertPtr(pThis);
878 AssertReturn(pThis->u32Magic == RTCRITSECTRW_MAGIC, 0);
879
880 /*
881 * Return the requested data.
882 */
883 uint64_t u64State = ASMAtomicReadU64(&pThis->u64State);
884 if ((u64State & RTCSRW_DIR_MASK) != (RTCSRW_DIR_READ << RTCSRW_DIR_SHIFT))
885 return 0;
886 return (u64State & RTCSRW_CNT_RD_MASK) >> RTCSRW_CNT_RD_SHIFT;
887}
888RT_EXPORT_SYMBOL(RTSemRWGetReadCount);
889
890
891RTDECL(int) RTCritSectRwDelete(PRTCRITSECTRW pThis)
892{
893 /*
894 * Assert free waiters and so on.
895 */
896 AssertPtr(pThis);
897 Assert(pThis->u32Magic == RTCRITSECTRW_MAGIC);
898 //Assert(pThis->cNestings == 0);
899 //Assert(pThis->cLockers == -1);
900 Assert(pThis->hNativeWriter == NIL_RTNATIVETHREAD);
901
902 /*
903 * Invalidate the structure and free the semaphores.
904 */
905 if (!ASMAtomicCmpXchgU32(&pThis->u32Magic, RTCRITSECTRW_MAGIC_DEAD, RTCRITSECTRW_MAGIC))
906 return VERR_INVALID_PARAMETER;
907
908 pThis->fFlags = 0;
909 pThis->u64State = 0;
910
911 RTSEMEVENT hEvtWrite = pThis->hEvtWrite;
912 pThis->hEvtWrite = NIL_RTSEMEVENT;
913 RTSEMEVENTMULTI hEvtRead = pThis->hEvtRead;
914 pThis->hEvtRead = NIL_RTSEMEVENTMULTI;
915
916 int rc1 = RTSemEventDestroy(hEvtWrite); AssertRC(rc1);
917 int rc2 = RTSemEventMultiDestroy(hEvtRead); AssertRC(rc2);
918
919 RTLockValidatorRecSharedDestroy(&pThis->pValidatorRead);
920 RTLockValidatorRecExclDestroy(&pThis->pValidatorWrite);
921
922 return RT_SUCCESS(rc1) ? rc2 : rc1;
923}
924RT_EXPORT_SYMBOL(RTCritSectRwDelete);
925
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