VirtualBox

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

Last change on this file since 93554 was 93115, checked in by vboxsync, 3 years ago

scm --update-copyright-year

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

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette