VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMR3/PDMCritSect.cpp@ 90672

Last change on this file since 90672 was 90672, checked in by vboxsync, 4 years ago

VMM/PDMCritSectRwEnterShared: Some more code refactoring. Added StatContentionR3LeaveExcl. bugref:6695

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 52.5 KB
Line 
1/* $Id: PDMCritSect.cpp 90672 2021-08-12 21:27:26Z vboxsync $ */
2/** @file
3 * PDM - Critical Sections, Ring-3.
4 */
5
6/*
7 * Copyright (C) 2006-2020 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. 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
18
19/*********************************************************************************************************************************
20* Header Files *
21*********************************************************************************************************************************/
22#define LOG_GROUP LOG_GROUP_PDM//_CRITSECT
23#include "PDMInternal.h"
24#include <VBox/vmm/pdmcritsect.h>
25#include <VBox/vmm/pdmcritsectrw.h>
26#include <VBox/vmm/mm.h>
27#include <VBox/vmm/vm.h>
28#include <VBox/vmm/uvm.h>
29
30#include <VBox/err.h>
31#include <VBox/log.h>
32#include <VBox/sup.h>
33#include <iprt/asm.h>
34#include <iprt/assert.h>
35#include <iprt/getopt.h>
36#include <iprt/lockvalidator.h>
37#include <iprt/string.h>
38#include <iprt/thread.h>
39
40
41/*********************************************************************************************************************************
42* Internal Functions *
43*********************************************************************************************************************************/
44static int pdmR3CritSectDeleteOne(PVM pVM, PUVM pUVM, PPDMCRITSECTINT pCritSect, PPDMCRITSECTINT pPrev, bool fFinal);
45static int pdmR3CritSectRwDeleteOne(PVM pVM, PUVM pUVM, PPDMCRITSECTRWINT pCritSect, PPDMCRITSECTRWINT pPrev, bool fFinal);
46static FNDBGFINFOARGVINT pdmR3CritSectInfo;
47static FNDBGFINFOARGVINT pdmR3CritSectRwInfo;
48
49
50
51/**
52 * Register statistics and info items related to the critical sections.
53 *
54 * @returns VBox status code.
55 * @param pVM The cross context VM structure.
56 */
57int pdmR3CritSectBothInitStatsAndInfo(PVM pVM)
58{
59 /*
60 * Statistics.
61 */
62 STAM_REL_REG(pVM, &pVM->pdm.s.StatQueuedCritSectLeaves, STAMTYPE_COUNTER, "/PDM/CritSects/00-QueuedLeaves", STAMUNIT_OCCURENCES,
63 "Number of times a critical section leave request needed to be queued for ring-3 execution.");
64 STAM_REL_REG(pVM, &pVM->pdm.s.StatAbortedCritSectEnters, STAMTYPE_COUNTER, "/PDM/CritSects/00-AbortedEnters", STAMUNIT_OCCURENCES,
65 "Number of times we've successfully aborted a wait in ring-0.");
66 STAM_REL_REG(pVM, &pVM->pdm.s.StatCritSectEntersWhileAborting, STAMTYPE_COUNTER, "/PDM/CritSects/00-EntersWhileAborting", STAMUNIT_OCCURENCES,
67 "Number of times we've got the critical section ownership while trying to abort a wait due to VERR_INTERRUPTED.");
68 STAM_REL_REG(pVM, &pVM->pdm.s.StatCritSectVerrInterrupted, STAMTYPE_COUNTER, "/PDM/CritSects/00-VERR_INTERRUPTED", STAMUNIT_OCCURENCES,
69 "Number of VERR_INTERRUPTED returns.");
70 STAM_REL_REG(pVM, &pVM->pdm.s.StatCritSectVerrTimeout, STAMTYPE_COUNTER, "/PDM/CritSects/00-VERR_TIMEOUT", STAMUNIT_OCCURENCES,
71 "Number of VERR_TIMEOUT returns.");
72 STAM_REL_REG(pVM, &pVM->pdm.s.StatCritSectNonInterruptibleWaits, STAMTYPE_COUNTER, "/PDM/CritSects/00-Non-interruptible-Waits-VINF_SUCCESS",
73 STAMUNIT_OCCURENCES, "Number of non-interruptible waits for rcBusy=VINF_SUCCESS");
74
75 STAM_REL_REG(pVM, &pVM->pdm.s.StatCritSectRwExclVerrInterrupted, STAMTYPE_COUNTER, "/PDM/CritSectsRw/00-Excl-VERR_INTERRUPTED", STAMUNIT_OCCURENCES,
76 "Number of VERR_INTERRUPTED returns in exclusive mode.");
77 STAM_REL_REG(pVM, &pVM->pdm.s.StatCritSectRwExclVerrTimeout, STAMTYPE_COUNTER, "/PDM/CritSectsRw/00-Excl-VERR_TIMEOUT", STAMUNIT_OCCURENCES,
78 "Number of VERR_TIMEOUT returns in exclusive mode.");
79 STAM_REL_REG(pVM, &pVM->pdm.s.StatCritSectRwExclNonInterruptibleWaits, STAMTYPE_COUNTER, "/PDM/CritSectsRw/00-Excl-Non-interruptible-Waits-VINF_SUCCESS",
80 STAMUNIT_OCCURENCES, "Number of non-interruptible waits for rcBusy=VINF_SUCCESS in exclusive mode");
81
82 /*
83 * Info items.
84 */
85 DBGFR3InfoRegisterInternalArgv(pVM, "critsect", "Show critical section: critsect [-v] [pattern[...]]", pdmR3CritSectInfo, 0);
86 DBGFR3InfoRegisterInternalArgv(pVM, "critsectrw", "Show read/write critical section: critsectrw [-v] [pattern[...]]",
87 pdmR3CritSectRwInfo, 0);
88
89 return VINF_SUCCESS;
90}
91
92
93/**
94 * Deletes all remaining critical sections.
95 *
96 * This is called at the very end of the termination process. It is also called
97 * at the end of vmR3CreateU failure cleanup, which may cause it to be called
98 * twice depending on where vmR3CreateU actually failed. We have to do the
99 * latter call because other components expect the critical sections to be
100 * automatically deleted.
101 *
102 * @returns VBox status code.
103 * First error code, rest is lost.
104 * @param pVM The cross context VM structure.
105 * @remark Don't confuse this with PDMR3CritSectDelete.
106 */
107VMMR3_INT_DECL(int) PDMR3CritSectBothTerm(PVM pVM)
108{
109 PUVM pUVM = pVM->pUVM;
110 int rc = VINF_SUCCESS;
111 RTCritSectEnter(&pUVM->pdm.s.ListCritSect);
112
113 while (pUVM->pdm.s.pCritSects)
114 {
115 int rc2 = pdmR3CritSectDeleteOne(pVM, pUVM, pUVM->pdm.s.pCritSects, NULL, true /* final */);
116 AssertRC(rc2);
117 if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
118 rc = rc2;
119 }
120
121 while (pUVM->pdm.s.pRwCritSects)
122 {
123 int rc2 = pdmR3CritSectRwDeleteOne(pVM, pUVM, pUVM->pdm.s.pRwCritSects, NULL, true /* final */);
124 AssertRC(rc2);
125 if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
126 rc = rc2;
127 }
128
129 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
130 return rc;
131}
132
133
134/**
135 * Initializes a critical section and inserts it into the list.
136 *
137 * @returns VBox status code.
138 * @param pVM The cross context VM structure.
139 * @param pCritSect The critical section.
140 * @param pvKey The owner key.
141 * @param SRC_POS The source position.
142 * @param fUniqueClass Whether to create a unique lock validator class for
143 * it or not.
144 * @param pszNameFmt Format string for naming the critical section. For
145 * statistics and lock validation.
146 * @param va Arguments for the format string.
147 */
148static int pdmR3CritSectInitOne(PVM pVM, PPDMCRITSECTINT pCritSect, void *pvKey, RT_SRC_POS_DECL, bool fUniqueClass,
149 const char *pszNameFmt, va_list va)
150{
151 VM_ASSERT_EMT(pVM);
152 Assert(pCritSect->Core.u32Magic != RTCRITSECT_MAGIC);
153
154 /*
155 * Allocate the semaphore.
156 */
157 AssertCompile(sizeof(SUPSEMEVENT) == sizeof(pCritSect->Core.EventSem));
158 int rc = SUPSemEventCreate(pVM->pSession, (PSUPSEMEVENT)&pCritSect->Core.EventSem);
159 if (RT_SUCCESS(rc))
160 {
161 /* Only format the name once. */
162 char *pszName = RTStrAPrintf2V(pszNameFmt, va); /** @todo plug the "leak"... */
163 if (pszName)
164 {
165 RT_SRC_POS_NOREF(); RT_NOREF(fUniqueClass);
166#ifndef PDMCRITSECT_STRICT
167 pCritSect->Core.pValidatorRec = NULL;
168#else
169 rc = RTLockValidatorRecExclCreate(&pCritSect->Core.pValidatorRec,
170# ifdef RT_LOCK_STRICT_ORDER
171 fUniqueClass
172 ? RTLockValidatorClassCreateUnique(RT_SRC_POS_ARGS, "%s", pszName)
173 : RTLockValidatorClassForSrcPos(RT_SRC_POS_ARGS, "%s", pszName),
174# else
175 NIL_RTLOCKVALCLASS,
176# endif
177 RTLOCKVAL_SUB_CLASS_NONE,
178 pCritSect, true, "%s", pszName);
179#endif
180 if (RT_SUCCESS(rc))
181 {
182 /*
183 * Initialize the structure (first bit is c&p from RTCritSectInitEx).
184 */
185 pCritSect->Core.u32Magic = RTCRITSECT_MAGIC;
186 pCritSect->Core.fFlags = 0;
187 pCritSect->Core.cNestings = 0;
188 pCritSect->Core.cLockers = -1;
189 pCritSect->Core.NativeThreadOwner = NIL_RTNATIVETHREAD;
190 pCritSect->pvKey = pvKey;
191 pCritSect->fAutomaticDefaultCritsect = false;
192 pCritSect->fUsedByTimerOrSimilar = false;
193 pCritSect->hEventToSignal = NIL_SUPSEMEVENT;
194 pCritSect->pszName = pszName;
195 pCritSect->pSelfR3 = (PPDMCRITSECT)pCritSect;
196
197 STAMR3RegisterF(pVM, &pCritSect->StatContentionRZLock, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS,
198 STAMUNIT_OCCURENCES, NULL, "/PDM/CritSects/%s/ContentionRZLock", pCritSect->pszName);
199 STAMR3RegisterF(pVM, &pCritSect->StatContentionRZLockBusy, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS,
200 STAMUNIT_OCCURENCES, NULL, "/PDM/CritSects/%s/ContentionRZLockBusy", pCritSect->pszName);
201 STAMR3RegisterF(pVM, &pCritSect->StatContentionRZUnlock, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS,
202 STAMUNIT_OCCURENCES, NULL, "/PDM/CritSects/%s/ContentionRZUnlock", pCritSect->pszName);
203 STAMR3RegisterF(pVM, &pCritSect->StatContentionRZWait, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS,
204 STAMUNIT_TICKS_PER_OCCURENCE, NULL, "/PDM/CritSects/%s/ContentionRZWait", pCritSect->pszName);
205 STAMR3RegisterF(pVM, &pCritSect->StatContentionR3, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS,
206 STAMUNIT_OCCURENCES, NULL, "/PDM/CritSects/%s/ContentionR3", pCritSect->pszName);
207 STAMR3RegisterF(pVM, &pCritSect->StatContentionR3Wait, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS,
208 STAMUNIT_TICKS_PER_OCCURENCE, NULL, "/PDM/CritSects/%s/ContentionR3Wait", pCritSect->pszName);
209#ifdef VBOX_WITH_STATISTICS
210 STAMR3RegisterF(pVM, &pCritSect->StatLocked, STAMTYPE_PROFILE_ADV, STAMVISIBILITY_ALWAYS,
211 STAMUNIT_TICKS_PER_OCCURENCE, NULL, "/PDM/CritSects/%s/Locked", pCritSect->pszName);
212#endif
213
214 /*
215 * Prepend to the list.
216 */
217 PUVM pUVM = pVM->pUVM;
218 RTCritSectEnter(&pUVM->pdm.s.ListCritSect);
219 pCritSect->pNext = pUVM->pdm.s.pCritSects;
220 pUVM->pdm.s.pCritSects = pCritSect;
221 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
222
223 return VINF_SUCCESS;
224 }
225
226 RTStrFree(pszName);
227 }
228 else
229 rc = VERR_NO_STR_MEMORY;
230 SUPSemEventClose(pVM->pSession, (SUPSEMEVENT)pCritSect->Core.EventSem);
231 }
232 return rc;
233}
234
235
236/**
237 * Initializes a read/write critical section and inserts it into the list.
238 *
239 * @returns VBox status code.
240 * @param pVM The cross context VM structure.
241 * @param pCritSect The read/write critical section.
242 * @param pvKey The owner key.
243 * @param SRC_POS The source position.
244 * @param pszNameFmt Format string for naming the critical section. For
245 * statistics and lock validation.
246 * @param va Arguments for the format string.
247 */
248static int pdmR3CritSectRwInitOne(PVM pVM, PPDMCRITSECTRWINT pCritSect, void *pvKey, RT_SRC_POS_DECL,
249 const char *pszNameFmt, va_list va)
250{
251 VM_ASSERT_EMT(pVM);
252 Assert(pCritSect->Core.u32Magic != RTCRITSECTRW_MAGIC);
253 AssertMsgReturn(((uintptr_t)&pCritSect->Core & 63) == 0, ("&Core=%p, must be 64-byte aligned!\n", &pCritSect->Core),
254 VERR_PDM_CRITSECTRW_MISALIGNED);
255 AssertMsgReturn(((uintptr_t)&pCritSect->Core.u & (sizeof(pCritSect->Core.u.u128) - 1)) == 0 /* paranoia */,
256 ("&Core.u=%p, must be 16-byte aligned!\n", &pCritSect->Core.u),
257 VERR_PDM_CRITSECTRW_MISALIGNED);
258
259 /*
260 * Allocate the semaphores.
261 */
262 AssertCompile(sizeof(SUPSEMEVENT) == sizeof(pCritSect->Core.hEvtWrite));
263 int rc = SUPSemEventCreate(pVM->pSession, (PSUPSEMEVENT)&pCritSect->Core.hEvtWrite);
264 if (RT_SUCCESS(rc))
265 {
266 AssertCompile(sizeof(SUPSEMEVENTMULTI) == sizeof(pCritSect->Core.hEvtRead));
267 rc = SUPSemEventMultiCreate(pVM->pSession, (PSUPSEMEVENT)&pCritSect->Core.hEvtRead);
268 if (RT_SUCCESS(rc))
269 {
270 /* Only format the name once. */
271 char *pszName = RTStrAPrintf2V(pszNameFmt, va); /** @todo plug the "leak"... */
272 if (pszName)
273 {
274 pCritSect->Core.pValidatorRead = NULL;
275 pCritSect->Core.pValidatorWrite = NULL;
276 RT_SRC_POS_NOREF();
277#ifdef PDMCRITSECTRW_STRICT
278# ifdef RT_LOCK_STRICT_ORDER
279 RTLOCKVALCLASS hClass = RTLockValidatorClassForSrcPos(RT_SRC_POS_ARGS, "%s", pszName);
280# else
281 RTLOCKVALCLASS hClass = NIL_RTLOCKVALCLASS;
282# endif
283 rc = RTLockValidatorRecExclCreate(&pCritSect->Core.pValidatorWrite, hClass, RTLOCKVAL_SUB_CLASS_NONE,
284 pCritSect, true, "%s", pszName);
285 if (RT_SUCCESS(rc))
286 rc = RTLockValidatorRecSharedCreate(&pCritSect->Core.pValidatorRead, hClass, RTLOCKVAL_SUB_CLASS_NONE,
287 pCritSect, false /*fSignaller*/, true, "%s", pszName);
288#endif
289 if (RT_SUCCESS(rc))
290 {
291 /*
292 * Initialize the structure (first bit is c&p from RTCritSectRwInitEx).
293 */
294 pCritSect->Core.u32Magic = RTCRITSECTRW_MAGIC;
295 pCritSect->Core.fNeedReset = false;
296 pCritSect->Core.afPadding[0] = false;
297 pCritSect->Core.fFlags = 0;
298 pCritSect->Core.u.u128.s.Lo = 0;
299 pCritSect->Core.u.u128.s.Hi = 0;
300 pCritSect->Core.u.s.hNativeWriter = NIL_RTNATIVETHREAD;
301 pCritSect->Core.cWriterReads = 0;
302 pCritSect->Core.cWriteRecursions = 0;
303 pCritSect->pvKey = pvKey;
304 pCritSect->pszName = pszName;
305 pCritSect->pSelfR3 = (PPDMCRITSECTRW)pCritSect;
306
307 STAMR3RegisterF(pVM, &pCritSect->StatContentionRZEnterExcl, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, NULL, "/PDM/CritSectsRw/%s/ContentionRZEnterExcl", pCritSect->pszName);
308 STAMR3RegisterF(pVM, &pCritSect->StatContentionRZLeaveExcl, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, NULL, "/PDM/CritSectsRw/%s/ContentionRZLeaveExcl", pCritSect->pszName);
309 STAMR3RegisterF(pVM, &pCritSect->StatContentionRZEnterShared, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, NULL, "/PDM/CritSectsRw/%s/ContentionRZEnterShared", pCritSect->pszName);
310 STAMR3RegisterF(pVM, &pCritSect->StatContentionRZLeaveShared, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, NULL, "/PDM/CritSectsRw/%s/ContentionRZLeaveShared", pCritSect->pszName);
311 STAMR3RegisterF(pVM, &pCritSect->StatContentionR3EnterExcl, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, NULL, "/PDM/CritSectsRw/%s/ContentionR3EnterExcl", pCritSect->pszName);
312 STAMR3RegisterF(pVM, &pCritSect->StatContentionR3LeaveExcl, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, NULL, "/PDM/CritSectsRw/%s/ContentionR3LeaveExcl", pCritSect->pszName);
313 STAMR3RegisterF(pVM, &pCritSect->StatContentionR3EnterShared, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, NULL, "/PDM/CritSectsRw/%s/ContentionR3EnterShared", pCritSect->pszName);
314 STAMR3RegisterF(pVM, &pCritSect->StatRZEnterExcl, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, NULL, "/PDM/CritSectsRw/%s/RZEnterExcl", pCritSect->pszName);
315 STAMR3RegisterF(pVM, &pCritSect->StatRZEnterShared, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, NULL, "/PDM/CritSectsRw/%s/RZEnterShared", pCritSect->pszName);
316 STAMR3RegisterF(pVM, &pCritSect->StatR3EnterExcl, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, NULL, "/PDM/CritSectsRw/%s/R3EnterExcl", pCritSect->pszName);
317 STAMR3RegisterF(pVM, &pCritSect->StatR3EnterShared, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, NULL, "/PDM/CritSectsRw/%s/R3EnterShared", pCritSect->pszName);
318#ifdef VBOX_WITH_STATISTICS
319 STAMR3RegisterF(pVM, &pCritSect->StatWriteLocked, STAMTYPE_PROFILE_ADV, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_OCCURENCE, NULL, "/PDM/CritSectsRw/%s/WriteLocked", pCritSect->pszName);
320#endif
321
322 /*
323 * Prepend to the list.
324 */
325 PUVM pUVM = pVM->pUVM;
326 RTCritSectEnter(&pUVM->pdm.s.ListCritSect);
327 pCritSect->pNext = pUVM->pdm.s.pRwCritSects;
328 pUVM->pdm.s.pRwCritSects = pCritSect;
329 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
330
331 return VINF_SUCCESS;
332 }
333
334 RTStrFree(pszName);
335 }
336 else
337 rc = VERR_NO_STR_MEMORY;
338 SUPSemEventMultiClose(pVM->pSession, (SUPSEMEVENT)pCritSect->Core.hEvtRead);
339 }
340 SUPSemEventClose(pVM->pSession, (SUPSEMEVENT)pCritSect->Core.hEvtWrite);
341 }
342 return rc;
343}
344
345
346/**
347 * Initializes a PDM critical section for internal use.
348 *
349 * The PDM critical sections are derived from the IPRT critical sections, but
350 * works in ring-0 and raw-mode context as well.
351 *
352 * @returns VBox status code.
353 * @param pVM The cross context VM structure.
354 * @param pCritSect Pointer to the critical section.
355 * @param SRC_POS Use RT_SRC_POS.
356 * @param pszNameFmt Format string for naming the critical section. For
357 * statistics and lock validation.
358 * @param ... Arguments for the format string.
359 * @thread EMT
360 */
361VMMR3DECL(int) PDMR3CritSectInit(PVM pVM, PPDMCRITSECT pCritSect, RT_SRC_POS_DECL, const char *pszNameFmt, ...)
362{
363#if HC_ARCH_BITS == 64 && GC_ARCH_BITS == 32
364 AssertCompile(sizeof(pCritSect->padding) >= sizeof(pCritSect->s));
365#endif
366 Assert(RT_ALIGN_P(pCritSect, sizeof(uintptr_t)) == pCritSect);
367 va_list va;
368 va_start(va, pszNameFmt);
369 int rc = pdmR3CritSectInitOne(pVM, &pCritSect->s, pCritSect, RT_SRC_POS_ARGS, false /*fUniqueClass*/, pszNameFmt, va);
370 va_end(va);
371 return rc;
372}
373
374
375/**
376 * Initializes a PDM read/write critical section for internal use.
377 *
378 * The PDM read/write critical sections are derived from the IPRT read/write
379 * critical sections, but works in ring-0 and raw-mode context as well.
380 *
381 * @returns VBox status code.
382 * @param pVM The cross context VM structure.
383 * @param pCritSect Pointer to the read/write critical section.
384 * @param SRC_POS Use RT_SRC_POS.
385 * @param pszNameFmt Format string for naming the critical section. For
386 * statistics and lock validation.
387 * @param ... Arguments for the format string.
388 * @thread EMT
389 */
390VMMR3DECL(int) PDMR3CritSectRwInit(PVM pVM, PPDMCRITSECTRW pCritSect, RT_SRC_POS_DECL, const char *pszNameFmt, ...)
391{
392#if HC_ARCH_BITS == 64 && GC_ARCH_BITS == 32
393 AssertCompile(sizeof(pCritSect->padding) >= sizeof(pCritSect->s));
394#endif
395 Assert(RT_ALIGN_P(pCritSect, sizeof(uintptr_t)) == pCritSect);
396 va_list va;
397 va_start(va, pszNameFmt);
398 int rc = pdmR3CritSectRwInitOne(pVM, &pCritSect->s, pCritSect, RT_SRC_POS_ARGS, pszNameFmt, va);
399 va_end(va);
400 return rc;
401}
402
403
404/**
405 * Initializes a PDM critical section for a device.
406 *
407 * @returns VBox status code.
408 * @param pVM The cross context VM structure.
409 * @param pDevIns Device instance.
410 * @param pCritSect Pointer to the critical section.
411 * @param SRC_POS The source position. Optional.
412 * @param pszNameFmt Format string for naming the critical section. For
413 * statistics and lock validation.
414 * @param va Arguments for the format string.
415 */
416int pdmR3CritSectInitDevice(PVM pVM, PPDMDEVINS pDevIns, PPDMCRITSECT pCritSect, RT_SRC_POS_DECL,
417 const char *pszNameFmt, va_list va)
418{
419 return pdmR3CritSectInitOne(pVM, &pCritSect->s, pDevIns, RT_SRC_POS_ARGS, false /*fUniqueClass*/, pszNameFmt, va);
420}
421
422
423/**
424 * Initializes a PDM read/write critical section for a device.
425 *
426 * @returns VBox status code.
427 * @param pVM The cross context VM structure.
428 * @param pDevIns Device instance.
429 * @param pCritSect Pointer to the read/write critical section.
430 * @param SRC_POS The source position. Optional.
431 * @param pszNameFmt Format string for naming the critical section. For
432 * statistics and lock validation.
433 * @param va Arguments for the format string.
434 */
435int pdmR3CritSectRwInitDevice(PVM pVM, PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect, RT_SRC_POS_DECL,
436 const char *pszNameFmt, va_list va)
437{
438 return pdmR3CritSectRwInitOne(pVM, &pCritSect->s, pDevIns, RT_SRC_POS_ARGS, pszNameFmt, va);
439}
440
441
442/**
443 * Initializes the automatic default PDM critical section for a device.
444 *
445 * @returns VBox status code.
446 * @param pVM The cross context VM structure.
447 * @param pDevIns Device instance.
448 * @param SRC_POS The source position. Optional.
449 * @param pCritSect Pointer to the critical section.
450 * @param pszNameFmt Format string for naming the critical section. For
451 * statistics and lock validation.
452 * @param ... Arguments for the format string.
453 */
454int pdmR3CritSectInitDeviceAuto(PVM pVM, PPDMDEVINS pDevIns, PPDMCRITSECT pCritSect, RT_SRC_POS_DECL,
455 const char *pszNameFmt, ...)
456{
457 va_list va;
458 va_start(va, pszNameFmt);
459 int rc = pdmR3CritSectInitOne(pVM, &pCritSect->s, pDevIns, RT_SRC_POS_ARGS, true /*fUniqueClass*/, pszNameFmt, va);
460 if (RT_SUCCESS(rc))
461 pCritSect->s.fAutomaticDefaultCritsect = true;
462 va_end(va);
463 return rc;
464}
465
466
467/**
468 * Initializes a PDM critical section for a driver.
469 *
470 * @returns VBox status code.
471 * @param pVM The cross context VM structure.
472 * @param pDrvIns Driver instance.
473 * @param pCritSect Pointer to the critical section.
474 * @param SRC_POS The source position. Optional.
475 * @param pszNameFmt Format string for naming the critical section. For
476 * statistics and lock validation.
477 * @param ... Arguments for the format string.
478 */
479int pdmR3CritSectInitDriver(PVM pVM, PPDMDRVINS pDrvIns, PPDMCRITSECT pCritSect, RT_SRC_POS_DECL,
480 const char *pszNameFmt, ...)
481{
482 va_list va;
483 va_start(va, pszNameFmt);
484 int rc = pdmR3CritSectInitOne(pVM, &pCritSect->s, pDrvIns, RT_SRC_POS_ARGS, false /*fUniqueClass*/, pszNameFmt, va);
485 va_end(va);
486 return rc;
487}
488
489
490/**
491 * Initializes a PDM read/write critical section for a driver.
492 *
493 * @returns VBox status code.
494 * @param pVM The cross context VM structure.
495 * @param pDrvIns Driver instance.
496 * @param pCritSect Pointer to the read/write critical section.
497 * @param SRC_POS The source position. Optional.
498 * @param pszNameFmt Format string for naming the critical section. For
499 * statistics and lock validation.
500 * @param ... Arguments for the format string.
501 */
502int pdmR3CritSectRwInitDriver(PVM pVM, PPDMDRVINS pDrvIns, PPDMCRITSECTRW pCritSect, RT_SRC_POS_DECL,
503 const char *pszNameFmt, ...)
504{
505 va_list va;
506 va_start(va, pszNameFmt);
507 int rc = pdmR3CritSectRwInitOne(pVM, &pCritSect->s, pDrvIns, RT_SRC_POS_ARGS, pszNameFmt, va);
508 va_end(va);
509 return rc;
510}
511
512
513/**
514 * Deletes one critical section.
515 *
516 * @returns Return code from RTCritSectDelete.
517 *
518 * @param pVM The cross context VM structure.
519 * @param pUVM The user mode VM handle.
520 * @param pCritSect The critical section.
521 * @param pPrev The previous critical section in the list.
522 * @param fFinal Set if this is the final call and statistics shouldn't be deregistered.
523 *
524 * @remarks Caller must have entered the ListCritSect.
525 */
526static int pdmR3CritSectDeleteOne(PVM pVM, PUVM pUVM, PPDMCRITSECTINT pCritSect, PPDMCRITSECTINT pPrev, bool fFinal)
527{
528 /*
529 * Assert free waiters and so on (c&p from RTCritSectDelete).
530 */
531 Assert(pCritSect->Core.u32Magic == RTCRITSECT_MAGIC);
532 //Assert(pCritSect->Core.cNestings == 0); - we no longer reset this when leaving.
533 Assert(pCritSect->Core.cLockers == -1);
534 Assert(pCritSect->Core.NativeThreadOwner == NIL_RTNATIVETHREAD);
535 Assert(RTCritSectIsOwner(&pUVM->pdm.s.ListCritSect));
536
537 /*
538 * Unlink it.
539 */
540 if (pPrev)
541 pPrev->pNext = pCritSect->pNext;
542 else
543 pUVM->pdm.s.pCritSects = pCritSect->pNext;
544
545 /*
546 * Delete it (parts taken from RTCritSectDelete).
547 * In case someone is waiting we'll signal the semaphore cLockers + 1 times.
548 */
549 ASMAtomicWriteU32(&pCritSect->Core.u32Magic, 0);
550 SUPSEMEVENT hEvent = (SUPSEMEVENT)pCritSect->Core.EventSem;
551 pCritSect->Core.EventSem = NIL_RTSEMEVENT;
552 while (pCritSect->Core.cLockers-- >= 0)
553 SUPSemEventSignal(pVM->pSession, hEvent);
554 ASMAtomicWriteS32(&pCritSect->Core.cLockers, -1);
555 int rc = SUPSemEventClose(pVM->pSession, hEvent);
556 AssertRC(rc);
557 RTLockValidatorRecExclDestroy(&pCritSect->Core.pValidatorRec);
558 pCritSect->pNext = NULL;
559 pCritSect->pvKey = NULL;
560 if (!fFinal)
561 STAMR3DeregisterF(pVM->pUVM, "/PDM/CritSects/%s/*", pCritSect->pszName);
562 RTStrFree((char *)pCritSect->pszName);
563 pCritSect->pszName = NULL;
564 return rc;
565}
566
567
568/**
569 * Deletes one read/write critical section.
570 *
571 * @returns VBox status code.
572 *
573 * @param pVM The cross context VM structure.
574 * @param pUVM The user mode VM handle.
575 * @param pCritSect The read/write critical section.
576 * @param pPrev The previous critical section in the list.
577 * @param fFinal Set if this is the final call and statistics shouldn't be deregistered.
578 *
579 * @remarks Caller must have entered the ListCritSect.
580 */
581static int pdmR3CritSectRwDeleteOne(PVM pVM, PUVM pUVM, PPDMCRITSECTRWINT pCritSect, PPDMCRITSECTRWINT pPrev, bool fFinal)
582{
583 /*
584 * Assert free waiters and so on (c&p from RTCritSectRwDelete).
585 */
586 Assert(pCritSect->Core.u32Magic == RTCRITSECTRW_MAGIC);
587 //Assert(pCritSect->Core.cNestings == 0);
588 //Assert(pCritSect->Core.cLockers == -1);
589 Assert(pCritSect->Core.u.s.hNativeWriter == NIL_RTNATIVETHREAD);
590
591 /*
592 * Invalidate the structure and free the semaphores.
593 */
594 if (!ASMAtomicCmpXchgU32(&pCritSect->Core.u32Magic, RTCRITSECTRW_MAGIC_DEAD, RTCRITSECTRW_MAGIC))
595 AssertFailed();
596
597 /*
598 * Unlink it.
599 */
600 if (pPrev)
601 pPrev->pNext = pCritSect->pNext;
602 else
603 pUVM->pdm.s.pRwCritSects = pCritSect->pNext;
604
605 /*
606 * Delete it (parts taken from RTCritSectRwDelete).
607 * In case someone is waiting we'll signal the semaphore cLockers + 1 times.
608 */
609 pCritSect->Core.fFlags = 0;
610 pCritSect->Core.u.s.u64State = 0;
611
612 SUPSEMEVENT hEvtWrite = (SUPSEMEVENT)pCritSect->Core.hEvtWrite;
613 pCritSect->Core.hEvtWrite = NIL_RTSEMEVENT;
614 AssertCompile(sizeof(hEvtWrite) == sizeof(pCritSect->Core.hEvtWrite));
615
616 SUPSEMEVENTMULTI hEvtRead = (SUPSEMEVENTMULTI)pCritSect->Core.hEvtRead;
617 pCritSect->Core.hEvtRead = NIL_RTSEMEVENTMULTI;
618 AssertCompile(sizeof(hEvtRead) == sizeof(pCritSect->Core.hEvtRead));
619
620 int rc1 = SUPSemEventClose(pVM->pSession, hEvtWrite); AssertRC(rc1);
621 int rc2 = SUPSemEventMultiClose(pVM->pSession, hEvtRead); AssertRC(rc2);
622
623 RTLockValidatorRecSharedDestroy(&pCritSect->Core.pValidatorRead);
624 RTLockValidatorRecExclDestroy(&pCritSect->Core.pValidatorWrite);
625
626 pCritSect->pNext = NULL;
627 pCritSect->pvKey = NULL;
628 if (!fFinal)
629 STAMR3DeregisterF(pVM->pUVM, "/PDM/CritSectsRw/%s/*", pCritSect->pszName);
630 RTStrFree((char *)pCritSect->pszName);
631 pCritSect->pszName = NULL;
632
633 return RT_SUCCESS(rc1) ? rc2 : rc1;
634}
635
636
637/**
638 * Deletes all critical sections with a give initializer key.
639 *
640 * @returns VBox status code.
641 * The entire list is processed on failure, so we'll only
642 * return the first error code. This shouldn't be a problem
643 * since errors really shouldn't happen here.
644 * @param pVM The cross context VM structure.
645 * @param pvKey The initializer key.
646 */
647static int pdmR3CritSectDeleteByKey(PVM pVM, void *pvKey)
648{
649 /*
650 * Iterate the list and match key.
651 */
652 PUVM pUVM = pVM->pUVM;
653 int rc = VINF_SUCCESS;
654 PPDMCRITSECTINT pPrev = NULL;
655 RTCritSectEnter(&pUVM->pdm.s.ListCritSect);
656 PPDMCRITSECTINT pCur = pUVM->pdm.s.pCritSects;
657 while (pCur)
658 {
659 if (pCur->pvKey == pvKey)
660 {
661 int rc2 = pdmR3CritSectDeleteOne(pVM, pUVM, pCur, pPrev, false /* not final */);
662 AssertRC(rc2);
663 if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
664 rc = rc2;
665 }
666
667 /* next */
668 pPrev = pCur;
669 pCur = pCur->pNext;
670 }
671 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
672 return rc;
673}
674
675
676/**
677 * Deletes all read/write critical sections with a give initializer key.
678 *
679 * @returns VBox status code.
680 * The entire list is processed on failure, so we'll only
681 * return the first error code. This shouldn't be a problem
682 * since errors really shouldn't happen here.
683 * @param pVM The cross context VM structure.
684 * @param pvKey The initializer key.
685 */
686static int pdmR3CritSectRwDeleteByKey(PVM pVM, void *pvKey)
687{
688 /*
689 * Iterate the list and match key.
690 */
691 PUVM pUVM = pVM->pUVM;
692 int rc = VINF_SUCCESS;
693 PPDMCRITSECTRWINT pPrev = NULL;
694 RTCritSectEnter(&pUVM->pdm.s.ListCritSect);
695 PPDMCRITSECTRWINT pCur = pUVM->pdm.s.pRwCritSects;
696 while (pCur)
697 {
698 if (pCur->pvKey == pvKey)
699 {
700 int rc2 = pdmR3CritSectRwDeleteOne(pVM, pUVM, pCur, pPrev, false /* not final */);
701 AssertRC(rc2);
702 if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
703 rc = rc2;
704 }
705
706 /* next */
707 pPrev = pCur;
708 pCur = pCur->pNext;
709 }
710 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
711 return rc;
712}
713
714
715/**
716 * Deletes all undeleted critical sections (both types) initialized by a given
717 * device.
718 *
719 * @returns VBox status code.
720 * @param pVM The cross context VM structure.
721 * @param pDevIns The device handle.
722 */
723int pdmR3CritSectBothDeleteDevice(PVM pVM, PPDMDEVINS pDevIns)
724{
725 int rc1 = pdmR3CritSectDeleteByKey(pVM, pDevIns);
726 int rc2 = pdmR3CritSectRwDeleteByKey(pVM, pDevIns);
727 return RT_SUCCESS(rc1) ? rc2 : rc1;
728}
729
730
731/**
732 * Deletes all undeleted critical sections (both types) initialized by a given
733 * driver.
734 *
735 * @returns VBox status code.
736 * @param pVM The cross context VM structure.
737 * @param pDrvIns The driver handle.
738 */
739int pdmR3CritSectBothDeleteDriver(PVM pVM, PPDMDRVINS pDrvIns)
740{
741 int rc1 = pdmR3CritSectDeleteByKey(pVM, pDrvIns);
742 int rc2 = pdmR3CritSectRwDeleteByKey(pVM, pDrvIns);
743 return RT_SUCCESS(rc1) ? rc2 : rc1;
744}
745
746
747/**
748 * Deletes the critical section.
749 *
750 * @returns VBox status code.
751 * @param pVM The cross context VM structure.
752 * @param pCritSect The PDM critical section to destroy.
753 */
754VMMR3DECL(int) PDMR3CritSectDelete(PVM pVM, PPDMCRITSECT pCritSect)
755{
756 if (!RTCritSectIsInitialized(&pCritSect->s.Core))
757 return VINF_SUCCESS;
758
759 /*
760 * Find and unlink it.
761 */
762 PUVM pUVM = pVM->pUVM;
763 AssertReleaseReturn(pVM, VERR_PDM_CRITSECT_IPE);
764 PPDMCRITSECTINT pPrev = NULL;
765 RTCritSectEnter(&pUVM->pdm.s.ListCritSect);
766 PPDMCRITSECTINT pCur = pUVM->pdm.s.pCritSects;
767 while (pCur)
768 {
769 if (pCur == &pCritSect->s)
770 {
771 int rc = pdmR3CritSectDeleteOne(pVM, pUVM, pCur, pPrev, false /* not final */);
772 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
773 return rc;
774 }
775
776 /* next */
777 pPrev = pCur;
778 pCur = pCur->pNext;
779 }
780 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
781 AssertReleaseMsgFailed(("pCritSect=%p wasn't found!\n", pCritSect));
782 return VERR_PDM_CRITSECT_NOT_FOUND;
783}
784
785
786/**
787 * Deletes the read/write critical section.
788 *
789 * @returns VBox status code.
790 * @param pVM The cross context VM structure.
791 * @param pCritSect The PDM read/write critical section to destroy.
792 */
793VMMR3DECL(int) PDMR3CritSectRwDelete(PVM pVM, PPDMCRITSECTRW pCritSect)
794{
795 if (!PDMCritSectRwIsInitialized(pCritSect))
796 return VINF_SUCCESS;
797
798 /*
799 * Find and unlink it.
800 */
801 PUVM pUVM = pVM->pUVM;
802 AssertReleaseReturn(pVM, VERR_PDM_CRITSECT_IPE);
803 PPDMCRITSECTRWINT pPrev = NULL;
804 RTCritSectEnter(&pUVM->pdm.s.ListCritSect);
805 PPDMCRITSECTRWINT pCur = pUVM->pdm.s.pRwCritSects;
806 while (pCur)
807 {
808 if (pCur == &pCritSect->s)
809 {
810 int rc = pdmR3CritSectRwDeleteOne(pVM, pUVM, pCur, pPrev, false /* not final */);
811 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
812 return rc;
813 }
814
815 /* next */
816 pPrev = pCur;
817 pCur = pCur->pNext;
818 }
819 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
820 AssertReleaseMsgFailed(("pCritSect=%p wasn't found!\n", pCritSect));
821 return VERR_PDM_CRITSECT_NOT_FOUND;
822}
823
824
825/**
826 * Gets the name of the critical section.
827 *
828 *
829 * @returns Pointer to the critical section name (read only) on success,
830 * NULL on failure (invalid critical section).
831 * @param pCritSect The critical section.
832 */
833VMMR3DECL(const char *) PDMR3CritSectName(PCPDMCRITSECT pCritSect)
834{
835 AssertPtrReturn(pCritSect, NULL);
836 AssertReturn(pCritSect->s.Core.u32Magic == RTCRITSECT_MAGIC, NULL);
837 return pCritSect->s.pszName;
838}
839
840
841/**
842 * Gets the name of the read/write critical section.
843 *
844 *
845 * @returns Pointer to the critical section name (read only) on success,
846 * NULL on failure (invalid critical section).
847 * @param pCritSect The read/write critical section.
848 */
849VMMR3DECL(const char *) PDMR3CritSectRwName(PCPDMCRITSECTRW pCritSect)
850{
851 AssertPtrReturn(pCritSect, NULL);
852 AssertReturn(pCritSect->s.Core.u32Magic == RTCRITSECTRW_MAGIC, NULL);
853 return pCritSect->s.pszName;
854}
855
856
857/**
858 * Yield the critical section if someone is waiting on it.
859 *
860 * When yielding, we'll leave the critical section and try to make sure the
861 * other waiting threads get a chance of entering before we reclaim it.
862 *
863 * @retval true if yielded.
864 * @retval false if not yielded.
865 * @param pVM The cross context VM structure.
866 * @param pCritSect The critical section.
867 */
868VMMR3DECL(bool) PDMR3CritSectYield(PVM pVM, PPDMCRITSECT pCritSect)
869{
870 AssertPtrReturn(pCritSect, false);
871 AssertReturn(pCritSect->s.Core.u32Magic == RTCRITSECT_MAGIC, false);
872 Assert(pCritSect->s.Core.NativeThreadOwner == RTThreadNativeSelf());
873 Assert(!(pCritSect->s.Core.fFlags & RTCRITSECT_FLAGS_NOP));
874 RT_NOREF(pVM);
875
876 /* No recursion allowed here. */
877 int32_t const cNestings = pCritSect->s.Core.cNestings;
878 AssertReturn(cNestings == 1, false);
879
880 int32_t const cLockers = ASMAtomicReadS32(&pCritSect->s.Core.cLockers);
881 if (cLockers < cNestings)
882 return false;
883
884#ifdef PDMCRITSECT_STRICT
885 RTLOCKVALSRCPOS const SrcPos = pCritSect->s.Core.pValidatorRec->SrcPos;
886#endif
887 PDMCritSectLeave(pVM, pCritSect);
888
889 /*
890 * If we're lucky, then one of the waiters has entered the lock already.
891 * We spin a little bit in hope for this to happen so we can avoid the
892 * yield detour.
893 */
894 if (ASMAtomicUoReadS32(&pCritSect->s.Core.cNestings) == 0)
895 {
896 int cLoops = 20;
897 while ( cLoops > 0
898 && ASMAtomicUoReadS32(&pCritSect->s.Core.cNestings) == 0
899 && ASMAtomicUoReadS32(&pCritSect->s.Core.cLockers) >= 0)
900 {
901 ASMNopPause();
902 cLoops--;
903 }
904 if (cLoops == 0)
905 RTThreadYield();
906 }
907
908#ifdef PDMCRITSECT_STRICT
909 int rc = PDMCritSectEnterDebug(pVM, pCritSect, VERR_IGNORED,
910 SrcPos.uId, SrcPos.pszFile, SrcPos.uLine, SrcPos.pszFunction);
911#else
912 int rc = PDMCritSectEnter(pVM, pCritSect, VERR_IGNORED);
913#endif
914 PDM_CRITSECT_RELEASE_ASSERT_RC(pVM, pCritSect, rc);
915 return true;
916}
917
918
919/**
920 * PDMR3CritSectBothCountOwned worker.
921 *
922 * @param pszName The critical section name.
923 * @param ppszNames Pointer to the pszNames variable.
924 * @param pcchLeft Pointer to the cchLeft variable.
925 * @param fFirst Whether this is the first name or not.
926 */
927static void pdmR3CritSectAppendNameToList(char const *pszName, char **ppszNames, size_t *pcchLeft, bool fFirst)
928{
929 size_t cchLeft = *pcchLeft;
930 if (cchLeft)
931 {
932 char *pszNames = *ppszNames;
933
934 /* try add comma. */
935 if (fFirst)
936 {
937 *pszNames++ = ',';
938 if (--cchLeft)
939 {
940 *pszNames++ = ' ';
941 cchLeft--;
942 }
943 }
944
945 /* try copy the name. */
946 if (cchLeft)
947 {
948 size_t const cchName = strlen(pszName);
949 if (cchName < cchLeft)
950 {
951 memcpy(pszNames, pszName, cchName);
952 pszNames += cchName;
953 cchLeft -= cchName;
954 }
955 else
956 {
957 if (cchLeft > 2)
958 {
959 memcpy(pszNames, pszName, cchLeft - 2);
960 pszNames += cchLeft - 2;
961 cchLeft = 2;
962 }
963 while (cchLeft-- > 0)
964 *pszNames++ = '+';
965 }
966 }
967 *pszNames = '\0';
968
969 *pcchLeft = cchLeft;
970 *ppszNames = pszNames;
971 }
972}
973
974
975/**
976 * Counts the critical sections (both type) owned by the calling thread,
977 * optionally returning a comma separated list naming them.
978 *
979 * Read ownerships are not included in non-strict builds.
980 *
981 * This is for diagnostic purposes only.
982 *
983 * @returns Lock count.
984 *
985 * @param pVM The cross context VM structure.
986 * @param pszNames Where to return the critical section names.
987 * @param cbNames The size of the buffer.
988 */
989VMMR3DECL(uint32_t) PDMR3CritSectCountOwned(PVM pVM, char *pszNames, size_t cbNames)
990{
991 /*
992 * Init the name buffer.
993 */
994 size_t cchLeft = cbNames;
995 if (cchLeft)
996 {
997 cchLeft--;
998 pszNames[0] = pszNames[cchLeft] = '\0';
999 }
1000
1001 /*
1002 * Iterate the critical sections.
1003 */
1004 uint32_t cCritSects = 0;
1005 RTNATIVETHREAD const hNativeThread = RTThreadNativeSelf();
1006 /* This is unsafe, but wtf. */
1007 for (PPDMCRITSECTINT pCur = pVM->pUVM->pdm.s.pCritSects;
1008 pCur;
1009 pCur = pCur->pNext)
1010 {
1011 /* Same as RTCritSectIsOwner(). */
1012 if (pCur->Core.NativeThreadOwner == hNativeThread)
1013 {
1014 cCritSects++;
1015 pdmR3CritSectAppendNameToList(pCur->pszName, &pszNames, &cchLeft, cCritSects == 1);
1016 }
1017 }
1018
1019 /* This is unsafe, but wtf. */
1020 for (PPDMCRITSECTRWINT pCur = pVM->pUVM->pdm.s.pRwCritSects;
1021 pCur;
1022 pCur = pCur->pNext)
1023 {
1024 if ( pCur->Core.u.s.hNativeWriter == hNativeThread
1025 || PDMCritSectRwIsReadOwner(pVM, (PPDMCRITSECTRW)pCur, false /*fWannaHear*/) )
1026 {
1027 cCritSects++;
1028 pdmR3CritSectAppendNameToList(pCur->pszName, &pszNames, &cchLeft, cCritSects == 1);
1029 }
1030 }
1031
1032 return cCritSects;
1033}
1034
1035
1036/**
1037 * Leave all critical sections the calling thread owns.
1038 *
1039 * This is only used when entering guru meditation in order to prevent other
1040 * EMTs and I/O threads from deadlocking.
1041 *
1042 * @param pVM The cross context VM structure.
1043 */
1044VMMR3_INT_DECL(void) PDMR3CritSectLeaveAll(PVM pVM)
1045{
1046 RTNATIVETHREAD const hNativeSelf = RTThreadNativeSelf();
1047 PUVM pUVM = pVM->pUVM;
1048
1049 RTCritSectEnter(&pUVM->pdm.s.ListCritSect);
1050 for (PPDMCRITSECTINT pCur = pUVM->pdm.s.pCritSects;
1051 pCur;
1052 pCur = pCur->pNext)
1053 {
1054 while ( pCur->Core.NativeThreadOwner == hNativeSelf
1055 && pCur->Core.cNestings > 0)
1056 PDMCritSectLeave(pVM, (PPDMCRITSECT)pCur);
1057 }
1058 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
1059}
1060
1061
1062/**
1063 * Gets the address of the NOP critical section.
1064 *
1065 * The NOP critical section will not perform any thread serialization but let
1066 * all enter immediately and concurrently.
1067 *
1068 * @returns The address of the NOP critical section.
1069 * @param pVM The cross context VM structure.
1070 */
1071VMMR3DECL(PPDMCRITSECT) PDMR3CritSectGetNop(PVM pVM)
1072{
1073 VM_ASSERT_VALID_EXT_RETURN(pVM, NULL);
1074 return &pVM->pdm.s.NopCritSect;
1075}
1076
1077
1078/**
1079 * Gets the ring-0 address of the NOP critical section.
1080 *
1081 * @returns The ring-0 address of the NOP critical section.
1082 * @param pVM The cross context VM structure.
1083 */
1084VMMR3DECL(R0PTRTYPE(PPDMCRITSECT)) PDMR3CritSectGetNopR0(PVM pVM)
1085{
1086 VM_ASSERT_VALID_EXT_RETURN(pVM, NIL_RTR0PTR);
1087 return MMHyperR3ToR0(pVM, &pVM->pdm.s.NopCritSect);
1088}
1089
1090
1091/**
1092 * Gets the raw-mode context address of the NOP critical section.
1093 *
1094 * @returns The raw-mode context address of the NOP critical section.
1095 * @param pVM The cross context VM structure.
1096 */
1097VMMR3DECL(RCPTRTYPE(PPDMCRITSECT)) PDMR3CritSectGetNopRC(PVM pVM)
1098{
1099 VM_ASSERT_VALID_EXT_RETURN(pVM, NIL_RTRCPTR);
1100 return MMHyperR3ToRC(pVM, &pVM->pdm.s.NopCritSect);
1101}
1102
1103
1104/**
1105 * Display matching critical sections.
1106 */
1107static void pdmR3CritSectInfoWorker(PUVM pUVM, const char *pszPatterns, PCDBGFINFOHLP pHlp, unsigned cVerbosity)
1108{
1109 size_t const cchPatterns = pszPatterns ? strlen(pszPatterns) : 0;
1110 RTCritSectEnter(&pUVM->pdm.s.ListCritSect);
1111
1112 for (PPDMCRITSECTINT pCritSect = pUVM->pdm.s.pCritSects; pCritSect; pCritSect = pCritSect->pNext)
1113 if ( !pszPatterns
1114 || RTStrSimplePatternMultiMatch(pszPatterns, cchPatterns, pCritSect->pszName, RTSTR_MAX, NULL))
1115 {
1116 uint32_t fFlags = pCritSect->Core.fFlags;
1117 pHlp->pfnPrintf(pHlp, "%p: '%s'%s%s%s%s%s\n", pCritSect, pCritSect->pszName,
1118 pCritSect->fAutomaticDefaultCritsect ? " default" : "",
1119 pCritSect->fUsedByTimerOrSimilar ? " used-by-timer-or-similar" : "",
1120 fFlags & RTCRITSECT_FLAGS_NO_NESTING ? " no-testing" : "",
1121 fFlags & RTCRITSECT_FLAGS_NO_LOCK_VAL ? " no-lock-val" : "",
1122 fFlags & RTCRITSECT_FLAGS_NOP ? " nop" : "");
1123
1124
1125 /*
1126 * Get the volatile data:
1127 */
1128 RTNATIVETHREAD hOwner;
1129 int32_t cLockers;
1130 int32_t cNestings;
1131 uint32_t uMagic;
1132 for (uint32_t iTry = 0; iTry < 16; iTry++)
1133 {
1134 hOwner = pCritSect->Core.NativeThreadOwner;
1135 cLockers = pCritSect->Core.cLockers;
1136 cNestings = pCritSect->Core.cNestings;
1137 fFlags = pCritSect->Core.fFlags;
1138 uMagic = pCritSect->Core.u32Magic;
1139 if ( hOwner == pCritSect->Core.NativeThreadOwner
1140 && cLockers == pCritSect->Core.cLockers
1141 && cNestings == pCritSect->Core.cNestings
1142 && fFlags == pCritSect->Core.fFlags
1143 && uMagic == pCritSect->Core.u32Magic)
1144 break;
1145 }
1146
1147 /*
1148 * Check and resolve the magic to a string, print if not RTCRITSECT_MAGIC.
1149 */
1150 const char *pszMagic;
1151 switch (uMagic)
1152 {
1153 case RTCRITSECT_MAGIC: pszMagic = NULL; break;
1154 case ~RTCRITSECT_MAGIC: pszMagic = " deleted"; break;
1155 case PDMCRITSECT_MAGIC_CORRUPTED: pszMagic = " PDMCRITSECT_MAGIC_CORRUPTED!"; break;
1156 case PDMCRITSECT_MAGIC_FAILED_ABORT: pszMagic = " PDMCRITSECT_MAGIC_FAILED_ABORT!"; break;
1157 default: pszMagic = " !unknown!"; break;
1158 }
1159 if (pszMagic || cVerbosity > 1)
1160 pHlp->pfnPrintf(pHlp, " uMagic=%#x%s\n", uMagic, pszMagic ? pszMagic : "");
1161
1162 /*
1163 * If locked, print details
1164 */
1165 if (cLockers != -1 || cNestings > 1 || cNestings < 0 || hOwner != NIL_RTNATIVETHREAD || cVerbosity > 1)
1166 {
1167 /* Translate the owner to a name if we have one and can. */
1168 const char *pszOwner = NULL;
1169 if (hOwner != NIL_RTNATIVETHREAD)
1170 {
1171 RTTHREAD hOwnerThread = RTThreadFromNative(hOwner); /* Note! Does not return a reference (crazy). */
1172 if (hOwnerThread != NIL_RTTHREAD)
1173 pszOwner = RTThreadGetName(hOwnerThread);
1174 }
1175 else
1176 pszOwner = "<no-owner>";
1177
1178 pHlp->pfnPrintf(pHlp, " cLockers=%d cNestings=%d hOwner=%p %s%s\n", cLockers, cNestings, hOwner,
1179 pszOwner ? pszOwner : "???", fFlags & PDMCRITSECT_FLAGS_PENDING_UNLOCK ? " pending-unlock" : "");
1180 }
1181 }
1182 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
1183}
1184
1185
1186/**
1187 * Display matching read/write critical sections.
1188 */
1189static void pdmR3CritSectInfoRwWorker(PUVM pUVM, const char *pszPatterns, PCDBGFINFOHLP pHlp, unsigned cVerbosity)
1190{
1191 size_t const cchPatterns = pszPatterns ? strlen(pszPatterns) : 0;
1192 RTCritSectEnter(&pUVM->pdm.s.ListCritSect);
1193
1194 for (PPDMCRITSECTRWINT pCritSect = pUVM->pdm.s.pRwCritSects; pCritSect; pCritSect = pCritSect->pNext)
1195 if ( !pszPatterns
1196 || RTStrSimplePatternMultiMatch(pszPatterns, cchPatterns, pCritSect->pszName, RTSTR_MAX, NULL))
1197 {
1198 uint16_t const fFlags = pCritSect->Core.fFlags;
1199 pHlp->pfnPrintf(pHlp, "%p: '%s'%s%s%s\n", pCritSect, pCritSect->pszName,
1200 fFlags & RTCRITSECT_FLAGS_NO_NESTING ? " no-testing" : "",
1201 fFlags & RTCRITSECT_FLAGS_NO_LOCK_VAL ? " no-lock-val" : "",
1202 fFlags & RTCRITSECT_FLAGS_NOP ? " nop" : "");
1203
1204 /*
1205 * Get the volatile data:
1206 */
1207 RTNATIVETHREAD hOwner;
1208 uint64_t u64State;
1209 uint32_t cWriterReads;
1210 uint32_t cWriteRecursions;
1211 bool fNeedReset;
1212 uint32_t uMagic;
1213 unsigned cTries = 16;
1214 do
1215 {
1216 u64State = pCritSect->Core.u.s.u64State;
1217 hOwner = pCritSect->Core.u.s.hNativeWriter;
1218 cWriterReads = pCritSect->Core.cWriterReads;
1219 cWriteRecursions = pCritSect->Core.cWriteRecursions;
1220 fNeedReset = pCritSect->Core.fNeedReset;
1221 uMagic = pCritSect->Core.u32Magic;
1222 } while ( cTries-- > 0
1223 && ( u64State != pCritSect->Core.u.s.u64State
1224 || hOwner != pCritSect->Core.u.s.hNativeWriter
1225 || cWriterReads != pCritSect->Core.cWriterReads
1226 || cWriteRecursions != pCritSect->Core.cWriteRecursions
1227 || fNeedReset != pCritSect->Core.fNeedReset
1228 || uMagic != pCritSect->Core.u32Magic));
1229
1230 /*
1231 * Check and resolve the magic to a string, print if not RTCRITSECT_MAGIC.
1232 */
1233 const char *pszMagic;
1234 switch (uMagic)
1235 {
1236 case RTCRITSECTRW_MAGIC: pszMagic = NULL; break;
1237 case ~RTCRITSECTRW_MAGIC: pszMagic = " deleted"; break;
1238 case PDMCRITSECTRW_MAGIC_CORRUPT: pszMagic = " PDMCRITSECTRW_MAGIC_CORRUPT!"; break;
1239 default: pszMagic = " !unknown!"; break;
1240 }
1241 if (pszMagic || cVerbosity > 1)
1242 pHlp->pfnPrintf(pHlp, " uMagic=%#x%s\n", uMagic, pszMagic ? pszMagic : "");
1243
1244 /*
1245 * If locked, print details
1246 */
1247 if ((u64State & ~RTCSRW_DIR_MASK) || hOwner != NIL_RTNATIVETHREAD || cVerbosity > 1)
1248 {
1249 /* Translate the owner to a name if we have one and can. */
1250 const char *pszOwner = NULL;
1251 if (hOwner != NIL_RTNATIVETHREAD)
1252 {
1253 RTTHREAD hOwnerThread = RTThreadFromNative(hOwner); /* Note! Does not return a reference (crazy). */
1254 if (hOwnerThread != NIL_RTTHREAD)
1255 pszOwner = RTThreadGetName(hOwnerThread);
1256 }
1257 else
1258 pszOwner = "<no-owner>";
1259
1260 pHlp->pfnPrintf(pHlp, " u64State=%#RX64 %s cReads=%u cWrites=%u cWaitingReads=%u\n",
1261 u64State, (u64State & RTCSRW_DIR_MASK) == RTCSRW_DIR_WRITE ? "writing" : "reading",
1262 (unsigned)((u64State & RTCSRW_CNT_RD_MASK) >> RTCSRW_CNT_RD_SHIFT),
1263 (unsigned)((u64State & RTCSRW_CNT_WR_MASK) >> RTCSRW_CNT_RD_SHIFT),
1264 (unsigned)((u64State & RTCSRW_WAIT_CNT_RD_MASK) >> RTCSRW_WAIT_CNT_RD_SHIFT));
1265 if (hOwner != NIL_RTNATIVETHREAD || cVerbosity > 2)
1266 pHlp->pfnPrintf(pHlp, " cNestings=%u cReadNestings=%u hWriter=%p %s\n",
1267 cWriteRecursions, cWriterReads, hOwner, pszOwner ? pszOwner : "???");
1268 }
1269 }
1270 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
1271}
1272
1273
1274/**
1275 * Common worker for critsect and critsectrw info items.
1276 */
1277static void pdmR3CritSectInfoCommon(PVM pVM, PCDBGFINFOHLP pHlp, int cArgs, char **papszArgs, bool fReadWrite)
1278{
1279 PUVM pUVM = pVM->pUVM;
1280
1281 /*
1282 * Process arguments.
1283 */
1284 static const RTGETOPTDEF s_aOptions[] =
1285 {
1286 { "--verbose", 'v', RTGETOPT_REQ_NOTHING },
1287 };
1288 RTGETOPTSTATE State;
1289 int rc = RTGetOptInit(&State, cArgs, papszArgs, s_aOptions, RT_ELEMENTS(s_aOptions), 0, RTGETOPTINIT_FLAGS_NO_STD_OPTS);
1290 AssertRC(rc);
1291
1292 unsigned cVerbosity = 1;
1293 unsigned cProcessed = 0;
1294
1295 RTGETOPTUNION ValueUnion;
1296 while ((rc = RTGetOpt(&State, &ValueUnion)) != 0)
1297 {
1298 switch (rc)
1299 {
1300 case 'v':
1301 cVerbosity++;
1302 break;
1303
1304 case VINF_GETOPT_NOT_OPTION:
1305 if (!fReadWrite)
1306 pdmR3CritSectInfoWorker(pUVM, ValueUnion.psz, pHlp, cVerbosity);
1307 else
1308 pdmR3CritSectInfoRwWorker(pUVM, ValueUnion.psz, pHlp, cVerbosity);
1309 cProcessed++;
1310 break;
1311
1312 default:
1313 pHlp->pfnGetOptError(pHlp, rc, &ValueUnion, &State);
1314 return;
1315 }
1316 }
1317
1318 /*
1319 * If we did nothing above, dump all.
1320 */
1321 if (!cProcessed)
1322 {
1323 if (!fReadWrite)
1324 pdmR3CritSectInfoWorker(pUVM, NULL, pHlp, cVerbosity);
1325 else
1326 pdmR3CritSectInfoRwWorker(pUVM, NULL, pHlp, cVerbosity);
1327 }
1328}
1329
1330
1331/**
1332 * @callback_method_impl{FNDBGFINFOARGVINT, critsect}
1333 */
1334static DECLCALLBACK(void) pdmR3CritSectInfo(PVM pVM, PCDBGFINFOHLP pHlp, int cArgs, char **papszArgs)
1335{
1336 return pdmR3CritSectInfoCommon(pVM, pHlp, cArgs, papszArgs, false);
1337}
1338
1339
1340/**
1341 * @callback_method_impl{FNDBGFINFOARGVINT, critsectrw}
1342 */
1343static DECLCALLBACK(void) pdmR3CritSectRwInfo(PVM pVM, PCDBGFINFOHLP pHlp, int cArgs, char **papszArgs)
1344{
1345 return pdmR3CritSectInfoCommon(pVM, pHlp, cArgs, papszArgs, true);
1346}
1347
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