VirtualBox

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

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

VMM/PGMCritSectRw: Added 'critsectrw' info item. [build fix] bugref:6695

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