VirtualBox

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

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

VMM,VMMDev: Force 32-byte alignment of PDMCRITSECTRW so all members that are being updated atomically are in the same cacheline. This also ensures that the 128-bit union is correctly aligned. bugref:6695

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