VirtualBox

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

Last change on this file was 98103, checked in by vboxsync, 16 months ago

Copyright year updates by scm.

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

© 2023 Oracle
ContactPrivacy policyTerms of Use