VirtualBox

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

Last change on this file since 80239 was 80191, checked in by vboxsync, 5 years ago

VMM/r3: Refactored VMCPU enumeration in preparation that aCpus will be replaced with a pointer array. Removed two raw-mode offset members from the CPUM and CPUMCPU sub-structures. bugref:9217 bugref:9517

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 38.8 KB
Line 
1/* $Id: PDMCritSect.cpp 80191 2019-08-08 00:36:57Z vboxsync $ */
2/** @file
3 * PDM - Critical Sections, Ring-3.
4 */
5
6/*
7 * Copyright (C) 2006-2019 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 VBOX_BUGREF_9217_PART_I
23#define LOG_GROUP LOG_GROUP_PDM//_CRITSECT
24#include "PDMInternal.h"
25#include <VBox/vmm/pdmcritsect.h>
26#include <VBox/vmm/pdmcritsectrw.h>
27#include <VBox/vmm/mm.h>
28#include <VBox/vmm/vm.h>
29#include <VBox/vmm/uvm.h>
30
31#include <VBox/err.h>
32#include <VBox/log.h>
33#include <VBox/sup.h>
34#include <iprt/asm.h>
35#include <iprt/assert.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);
46
47
48
49/**
50 * Register statistics related to the critical sections.
51 *
52 * @returns VBox status code.
53 * @param pVM The cross context VM structure.
54 */
55int pdmR3CritSectBothInitStats(PVM pVM)
56{
57 RT_NOREF_PV(pVM);
58 STAM_REG(pVM, &pVM->pdm.s.StatQueuedCritSectLeaves, STAMTYPE_COUNTER, "/PDM/QueuedCritSectLeaves", STAMUNIT_OCCURENCES,
59 "Number of times a critical section leave request needed to be queued for ring-3 execution.");
60 return VINF_SUCCESS;
61}
62
63
64/**
65 * Relocates all the critical sections.
66 *
67 * @param pVM The cross context VM structure.
68 */
69void pdmR3CritSectBothRelocate(PVM pVM)
70{
71 PUVM pUVM = pVM->pUVM;
72 RTCritSectEnter(&pUVM->pdm.s.ListCritSect);
73
74 for (PPDMCRITSECTINT pCur = pUVM->pdm.s.pCritSects;
75 pCur;
76 pCur = pCur->pNext)
77 pCur->pVMRC = pVM->pVMRC;
78
79 for (PPDMCRITSECTRWINT pCur = pUVM->pdm.s.pRwCritSects;
80 pCur;
81 pCur = pCur->pNext)
82 pCur->pVMRC = pVM->pVMRC;
83
84 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
85}
86
87
88/**
89 * Deletes all remaining critical sections.
90 *
91 * This is called at the very end of the termination process. It is also called
92 * at the end of vmR3CreateU failure cleanup, which may cause it to be called
93 * twice depending on where vmR3CreateU actually failed. We have to do the
94 * latter call because other components expect the critical sections to be
95 * automatically deleted.
96 *
97 * @returns VBox status code.
98 * First error code, rest is lost.
99 * @param pVM The cross context VM structure.
100 * @remark Don't confuse this with PDMR3CritSectDelete.
101 */
102VMMR3_INT_DECL(int) PDMR3CritSectBothTerm(PVM pVM)
103{
104 PUVM pUVM = pVM->pUVM;
105 int rc = VINF_SUCCESS;
106 RTCritSectEnter(&pUVM->pdm.s.ListCritSect);
107
108 while (pUVM->pdm.s.pCritSects)
109 {
110 int rc2 = pdmR3CritSectDeleteOne(pVM, pUVM, pUVM->pdm.s.pCritSects, NULL, true /* final */);
111 AssertRC(rc2);
112 if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
113 rc = rc2;
114 }
115
116 while (pUVM->pdm.s.pRwCritSects)
117 {
118 int rc2 = pdmR3CritSectRwDeleteOne(pVM, pUVM, pUVM->pdm.s.pRwCritSects, NULL, true /* final */);
119 AssertRC(rc2);
120 if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
121 rc = rc2;
122 }
123
124 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
125 return rc;
126}
127
128
129/**
130 * Initializes a critical section and inserts it into the list.
131 *
132 * @returns VBox status code.
133 * @param pVM The cross context VM structure.
134 * @param pCritSect The critical section.
135 * @param pvKey The owner key.
136 * @param SRC_POS The source position.
137 * @param pszNameFmt Format string for naming the critical section. For
138 * statistics and lock validation.
139 * @param va Arguments for the format string.
140 */
141static int pdmR3CritSectInitOne(PVM pVM, PPDMCRITSECTINT pCritSect, void *pvKey, RT_SRC_POS_DECL,
142 const char *pszNameFmt, va_list va)
143{
144 VM_ASSERT_EMT(pVM);
145 Assert(pCritSect->Core.u32Magic != RTCRITSECT_MAGIC);
146
147 /*
148 * Allocate the semaphore.
149 */
150 AssertCompile(sizeof(SUPSEMEVENT) == sizeof(pCritSect->Core.EventSem));
151 int rc = SUPSemEventCreate(pVM->pSession, (PSUPSEMEVENT)&pCritSect->Core.EventSem);
152 if (RT_SUCCESS(rc))
153 {
154 /* Only format the name once. */
155 char *pszName = RTStrAPrintf2V(pszNameFmt, va); /** @todo plug the "leak"... */
156 if (pszName)
157 {
158 RT_SRC_POS_NOREF();
159#ifndef PDMCRITSECT_STRICT
160 pCritSect->Core.pValidatorRec = NULL;
161#else
162 rc = RTLockValidatorRecExclCreate(&pCritSect->Core.pValidatorRec,
163# ifdef RT_LOCK_STRICT_ORDER
164 RTLockValidatorClassForSrcPos(RT_SRC_POS_ARGS, "%s", pszName),
165# else
166 NIL_RTLOCKVALCLASS,
167# endif
168 RTLOCKVAL_SUB_CLASS_NONE,
169 pCritSect, true, "%s", pszName);
170#endif
171 if (RT_SUCCESS(rc))
172 {
173 /*
174 * Initialize the structure (first bit is c&p from RTCritSectInitEx).
175 */
176 pCritSect->Core.u32Magic = RTCRITSECT_MAGIC;
177 pCritSect->Core.fFlags = 0;
178 pCritSect->Core.cNestings = 0;
179 pCritSect->Core.cLockers = -1;
180 pCritSect->Core.NativeThreadOwner = NIL_RTNATIVETHREAD;
181 pCritSect->pVMR3 = pVM;
182 pCritSect->pVMR0 = pVM->pVMR0;
183 pCritSect->pVMRC = pVM->pVMRC;
184 pCritSect->pvKey = pvKey;
185 pCritSect->fAutomaticDefaultCritsect = false;
186 pCritSect->fUsedByTimerOrSimilar = false;
187 pCritSect->hEventToSignal = NIL_SUPSEMEVENT;
188 pCritSect->pszName = pszName;
189
190 STAMR3RegisterF(pVM, &pCritSect->StatContentionRZLock, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, NULL, "/PDM/CritSects/%s/ContentionRZLock", pCritSect->pszName);
191 STAMR3RegisterF(pVM, &pCritSect->StatContentionRZUnlock,STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, NULL, "/PDM/CritSects/%s/ContentionRZUnlock", pCritSect->pszName);
192 STAMR3RegisterF(pVM, &pCritSect->StatContentionR3, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, NULL, "/PDM/CritSects/%s/ContentionR3", pCritSect->pszName);
193#ifdef VBOX_WITH_STATISTICS
194 STAMR3RegisterF(pVM, &pCritSect->StatLocked, STAMTYPE_PROFILE_ADV, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_OCCURENCE, NULL, "/PDM/CritSects/%s/Locked", pCritSect->pszName);
195#endif
196
197 PUVM pUVM = pVM->pUVM;
198 RTCritSectEnter(&pUVM->pdm.s.ListCritSect);
199 pCritSect->pNext = pUVM->pdm.s.pCritSects;
200 pUVM->pdm.s.pCritSects = pCritSect;
201 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
202
203 return VINF_SUCCESS;
204 }
205
206 RTStrFree(pszName);
207 }
208 else
209 rc = VERR_NO_STR_MEMORY;
210 SUPSemEventClose(pVM->pSession, (SUPSEMEVENT)pCritSect->Core.EventSem);
211 }
212 return rc;
213}
214
215
216/**
217 * Initializes a read/write critical section and inserts it into the list.
218 *
219 * @returns VBox status code.
220 * @param pVM The cross context VM structure.
221 * @param pCritSect The read/write critical section.
222 * @param pvKey The owner key.
223 * @param SRC_POS The source position.
224 * @param pszNameFmt Format string for naming the critical section. For
225 * statistics and lock validation.
226 * @param va Arguments for the format string.
227 */
228static int pdmR3CritSectRwInitOne(PVM pVM, PPDMCRITSECTRWINT pCritSect, void *pvKey, RT_SRC_POS_DECL,
229 const char *pszNameFmt, va_list va)
230{
231 VM_ASSERT_EMT(pVM);
232 Assert(pCritSect->Core.u32Magic != RTCRITSECTRW_MAGIC);
233
234 /*
235 * Allocate the semaphores.
236 */
237 AssertCompile(sizeof(SUPSEMEVENT) == sizeof(pCritSect->Core.hEvtWrite));
238 int rc = SUPSemEventCreate(pVM->pSession, (PSUPSEMEVENT)&pCritSect->Core.hEvtWrite);
239 if (RT_SUCCESS(rc))
240 {
241 AssertCompile(sizeof(SUPSEMEVENTMULTI) == sizeof(pCritSect->Core.hEvtRead));
242 rc = SUPSemEventMultiCreate(pVM->pSession, (PSUPSEMEVENT)&pCritSect->Core.hEvtRead);
243 if (RT_SUCCESS(rc))
244 {
245 /* Only format the name once. */
246 char *pszName = RTStrAPrintf2V(pszNameFmt, va); /** @todo plug the "leak"... */
247 if (pszName)
248 {
249 pCritSect->Core.pValidatorRead = NULL;
250 pCritSect->Core.pValidatorWrite = NULL;
251 RT_SRC_POS_NOREF();
252#ifdef PDMCRITSECTRW_STRICT
253# ifdef RT_LOCK_STRICT_ORDER
254 RTLOCKVALCLASS hClass = RTLockValidatorClassForSrcPos(RT_SRC_POS_ARGS, "%s", pszName);
255# else
256 RTLOCKVALCLASS hClass = NIL_RTLOCKVALCLASS;
257# endif
258 rc = RTLockValidatorRecExclCreate(&pCritSect->Core.pValidatorWrite, hClass, RTLOCKVAL_SUB_CLASS_NONE,
259 pCritSect, true, "%s", pszName);
260 if (RT_SUCCESS(rc))
261 rc = RTLockValidatorRecSharedCreate(&pCritSect->Core.pValidatorRead, hClass, RTLOCKVAL_SUB_CLASS_NONE,
262 pCritSect, false /*fSignaller*/, true, "%s", pszName);
263#endif
264 if (RT_SUCCESS(rc))
265 {
266 /*
267 * Initialize the structure (first bit is c&p from RTCritSectRwInitEx).
268 */
269 pCritSect->Core.u32Magic = RTCRITSECTRW_MAGIC;
270 pCritSect->Core.fNeedReset = false;
271 pCritSect->Core.u64State = 0;
272 pCritSect->Core.hNativeWriter = NIL_RTNATIVETHREAD;
273 pCritSect->Core.cWriterReads = 0;
274 pCritSect->Core.cWriteRecursions = 0;
275#if HC_ARCH_BITS == 32
276 pCritSect->Core.HCPtrPadding = NIL_RTHCPTR;
277#endif
278 pCritSect->pVMR3 = pVM;
279 pCritSect->pVMR0 = pVM->pVMR0;
280 pCritSect->pVMRC = pVM->pVMRC;
281 pCritSect->pvKey = pvKey;
282 pCritSect->pszName = pszName;
283
284 STAMR3RegisterF(pVM, &pCritSect->StatContentionRZEnterExcl, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, NULL, "/PDM/CritSectsRw/%s/ContentionRZEnterExcl", pCritSect->pszName);
285 STAMR3RegisterF(pVM, &pCritSect->StatContentionRZLeaveExcl, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, NULL, "/PDM/CritSectsRw/%s/ContentionRZLeaveExcl", pCritSect->pszName);
286 STAMR3RegisterF(pVM, &pCritSect->StatContentionRZEnterShared, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, NULL, "/PDM/CritSectsRw/%s/ContentionRZEnterShared", pCritSect->pszName);
287 STAMR3RegisterF(pVM, &pCritSect->StatContentionRZLeaveShared, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, NULL, "/PDM/CritSectsRw/%s/ContentionRZLeaveShared", pCritSect->pszName);
288 STAMR3RegisterF(pVM, &pCritSect->StatContentionR3EnterExcl, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, NULL, "/PDM/CritSectsRw/%s/ContentionR3EnterExcl", pCritSect->pszName);
289 STAMR3RegisterF(pVM, &pCritSect->StatContentionR3EnterShared, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, NULL, "/PDM/CritSectsRw/%s/ContentionR3EnterShared", pCritSect->pszName);
290 STAMR3RegisterF(pVM, &pCritSect->StatRZEnterExcl, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, NULL, "/PDM/CritSectsRw/%s/RZEnterExcl", pCritSect->pszName);
291 STAMR3RegisterF(pVM, &pCritSect->StatRZEnterShared, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, NULL, "/PDM/CritSectsRw/%s/RZEnterShared", pCritSect->pszName);
292 STAMR3RegisterF(pVM, &pCritSect->StatR3EnterExcl, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, NULL, "/PDM/CritSectsRw/%s/R3EnterExcl", pCritSect->pszName);
293 STAMR3RegisterF(pVM, &pCritSect->StatR3EnterShared, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, NULL, "/PDM/CritSectsRw/%s/R3EnterShared", pCritSect->pszName);
294#ifdef VBOX_WITH_STATISTICS
295 STAMR3RegisterF(pVM, &pCritSect->StatWriteLocked, STAMTYPE_PROFILE_ADV, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_OCCURENCE, NULL, "/PDM/CritSectsRw/%s/WriteLocked", pCritSect->pszName);
296#endif
297
298 PUVM pUVM = pVM->pUVM;
299 RTCritSectEnter(&pUVM->pdm.s.ListCritSect);
300 pCritSect->pNext = pUVM->pdm.s.pRwCritSects;
301 pUVM->pdm.s.pRwCritSects = pCritSect;
302 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
303
304 return VINF_SUCCESS;
305 }
306
307 RTStrFree(pszName);
308 }
309 else
310 rc = VERR_NO_STR_MEMORY;
311 SUPSemEventMultiClose(pVM->pSession, (SUPSEMEVENT)pCritSect->Core.hEvtRead);
312 }
313 SUPSemEventClose(pVM->pSession, (SUPSEMEVENT)pCritSect->Core.hEvtWrite);
314 }
315 return rc;
316}
317
318
319/**
320 * Initializes a PDM critical section for internal use.
321 *
322 * The PDM critical sections are derived from the IPRT critical sections, but
323 * works in ring-0 and raw-mode context as well.
324 *
325 * @returns VBox status code.
326 * @param pVM The cross context VM structure.
327 * @param pCritSect Pointer to the critical section.
328 * @param SRC_POS Use RT_SRC_POS.
329 * @param pszNameFmt Format string for naming the critical section. For
330 * statistics and lock validation.
331 * @param ... Arguments for the format string.
332 * @thread EMT
333 */
334VMMR3DECL(int) PDMR3CritSectInit(PVM pVM, PPDMCRITSECT pCritSect, RT_SRC_POS_DECL, const char *pszNameFmt, ...)
335{
336#if HC_ARCH_BITS == 64 && GC_ARCH_BITS == 32
337 AssertCompile(sizeof(pCritSect->padding) >= sizeof(pCritSect->s));
338#endif
339 Assert(RT_ALIGN_P(pCritSect, sizeof(uintptr_t)) == pCritSect);
340 va_list va;
341 va_start(va, pszNameFmt);
342 int rc = pdmR3CritSectInitOne(pVM, &pCritSect->s, pCritSect, RT_SRC_POS_ARGS, pszNameFmt, va);
343 va_end(va);
344 return rc;
345}
346
347
348/**
349 * Initializes a PDM read/write critical section for internal use.
350 *
351 * The PDM read/write critical sections are derived from the IPRT read/write
352 * critical sections, but works in ring-0 and raw-mode context as well.
353 *
354 * @returns VBox status code.
355 * @param pVM The cross context VM structure.
356 * @param pCritSect Pointer to the read/write critical section.
357 * @param SRC_POS Use RT_SRC_POS.
358 * @param pszNameFmt Format string for naming the critical section. For
359 * statistics and lock validation.
360 * @param ... Arguments for the format string.
361 * @thread EMT
362 */
363VMMR3DECL(int) PDMR3CritSectRwInit(PVM pVM, PPDMCRITSECTRW pCritSect, RT_SRC_POS_DECL, const char *pszNameFmt, ...)
364{
365#if HC_ARCH_BITS == 64 && GC_ARCH_BITS == 32
366 AssertCompile(sizeof(pCritSect->padding) >= sizeof(pCritSect->s));
367#endif
368 Assert(RT_ALIGN_P(pCritSect, sizeof(uintptr_t)) == pCritSect);
369 va_list va;
370 va_start(va, pszNameFmt);
371 int rc = pdmR3CritSectRwInitOne(pVM, &pCritSect->s, pCritSect, RT_SRC_POS_ARGS, pszNameFmt, va);
372 va_end(va);
373 return rc;
374}
375
376
377/**
378 * Initializes a PDM critical section for a device.
379 *
380 * @returns VBox status code.
381 * @param pVM The cross context VM structure.
382 * @param pDevIns Device instance.
383 * @param pCritSect Pointer to the critical section.
384 * @param SRC_POS The source position. Optional.
385 * @param pszNameFmt Format string for naming the critical section. For
386 * statistics and lock validation.
387 * @param va Arguments for the format string.
388 */
389int pdmR3CritSectInitDevice(PVM pVM, PPDMDEVINS pDevIns, PPDMCRITSECT pCritSect, RT_SRC_POS_DECL,
390 const char *pszNameFmt, va_list va)
391{
392 return pdmR3CritSectInitOne(pVM, &pCritSect->s, pDevIns, RT_SRC_POS_ARGS, pszNameFmt, va);
393}
394
395
396/**
397 * Initializes a PDM read/write critical section for a device.
398 *
399 * @returns VBox status code.
400 * @param pVM The cross context VM structure.
401 * @param pDevIns Device instance.
402 * @param pCritSect Pointer to the read/write critical section.
403 * @param SRC_POS The source position. Optional.
404 * @param pszNameFmt Format string for naming the critical section. For
405 * statistics and lock validation.
406 * @param va Arguments for the format string.
407 */
408int pdmR3CritSectRwInitDevice(PVM pVM, PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect, RT_SRC_POS_DECL,
409 const char *pszNameFmt, va_list va)
410{
411 return pdmR3CritSectRwInitOne(pVM, &pCritSect->s, pDevIns, RT_SRC_POS_ARGS, pszNameFmt, va);
412}
413
414
415/**
416 * Initializes the automatic default 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 SRC_POS The source position. Optional.
422 * @param pCritSect Pointer to the critical section.
423 * @param pszNameFmt Format string for naming the critical section. For
424 * statistics and lock validation.
425 * @param ... Arguments for the format string.
426 */
427int pdmR3CritSectInitDeviceAuto(PVM pVM, PPDMDEVINS pDevIns, PPDMCRITSECT pCritSect, RT_SRC_POS_DECL,
428 const char *pszNameFmt, ...)
429{
430 va_list va;
431 va_start(va, pszNameFmt);
432 int rc = pdmR3CritSectInitOne(pVM, &pCritSect->s, pDevIns, RT_SRC_POS_ARGS, pszNameFmt, va);
433 if (RT_SUCCESS(rc))
434 pCritSect->s.fAutomaticDefaultCritsect = true;
435 va_end(va);
436 return rc;
437}
438
439
440/**
441 * Initializes a PDM critical section for a driver.
442 *
443 * @returns VBox status code.
444 * @param pVM The cross context VM structure.
445 * @param pDrvIns Driver instance.
446 * @param pCritSect Pointer to the critical section.
447 * @param SRC_POS The source position. Optional.
448 * @param pszNameFmt Format string for naming the critical section. For
449 * statistics and lock validation.
450 * @param ... Arguments for the format string.
451 */
452int pdmR3CritSectInitDriver(PVM pVM, PPDMDRVINS pDrvIns, PPDMCRITSECT pCritSect, RT_SRC_POS_DECL,
453 const char *pszNameFmt, ...)
454{
455 va_list va;
456 va_start(va, pszNameFmt);
457 int rc = pdmR3CritSectInitOne(pVM, &pCritSect->s, pDrvIns, RT_SRC_POS_ARGS, pszNameFmt, va);
458 va_end(va);
459 return rc;
460}
461
462
463/**
464 * Initializes a PDM read/write critical section for a driver.
465 *
466 * @returns VBox status code.
467 * @param pVM The cross context VM structure.
468 * @param pDrvIns Driver instance.
469 * @param pCritSect Pointer to the read/write critical section.
470 * @param SRC_POS The source position. Optional.
471 * @param pszNameFmt Format string for naming the critical section. For
472 * statistics and lock validation.
473 * @param ... Arguments for the format string.
474 */
475int pdmR3CritSectRwInitDriver(PVM pVM, PPDMDRVINS pDrvIns, PPDMCRITSECTRW pCritSect, RT_SRC_POS_DECL,
476 const char *pszNameFmt, ...)
477{
478 va_list va;
479 va_start(va, pszNameFmt);
480 int rc = pdmR3CritSectRwInitOne(pVM, &pCritSect->s, pDrvIns, RT_SRC_POS_ARGS, pszNameFmt, va);
481 va_end(va);
482 return rc;
483}
484
485
486/**
487 * Deletes one critical section.
488 *
489 * @returns Return code from RTCritSectDelete.
490 *
491 * @param pVM The cross context VM structure.
492 * @param pUVM The user mode VM handle.
493 * @param pCritSect The critical section.
494 * @param pPrev The previous critical section in the list.
495 * @param fFinal Set if this is the final call and statistics shouldn't be deregistered.
496 *
497 * @remarks Caller must have entered the ListCritSect.
498 */
499static int pdmR3CritSectDeleteOne(PVM pVM, PUVM pUVM, PPDMCRITSECTINT pCritSect, PPDMCRITSECTINT pPrev, bool fFinal)
500{
501 /*
502 * Assert free waiters and so on (c&p from RTCritSectDelete).
503 */
504 Assert(pCritSect->Core.u32Magic == RTCRITSECT_MAGIC);
505 //Assert(pCritSect->Core.cNestings == 0); - we no longer reset this when leaving.
506 Assert(pCritSect->Core.cLockers == -1);
507 Assert(pCritSect->Core.NativeThreadOwner == NIL_RTNATIVETHREAD);
508 Assert(RTCritSectIsOwner(&pUVM->pdm.s.ListCritSect));
509
510 /*
511 * Unlink it.
512 */
513 if (pPrev)
514 pPrev->pNext = pCritSect->pNext;
515 else
516 pUVM->pdm.s.pCritSects = pCritSect->pNext;
517
518 /*
519 * Delete it (parts taken from RTCritSectDelete).
520 * In case someone is waiting we'll signal the semaphore cLockers + 1 times.
521 */
522 ASMAtomicWriteU32(&pCritSect->Core.u32Magic, 0);
523 SUPSEMEVENT hEvent = (SUPSEMEVENT)pCritSect->Core.EventSem;
524 pCritSect->Core.EventSem = NIL_RTSEMEVENT;
525 while (pCritSect->Core.cLockers-- >= 0)
526 SUPSemEventSignal(pVM->pSession, hEvent);
527 ASMAtomicWriteS32(&pCritSect->Core.cLockers, -1);
528 int rc = SUPSemEventClose(pVM->pSession, hEvent);
529 AssertRC(rc);
530 RTLockValidatorRecExclDestroy(&pCritSect->Core.pValidatorRec);
531 pCritSect->pNext = NULL;
532 pCritSect->pvKey = NULL;
533 pCritSect->pVMR3 = NULL;
534 pCritSect->pVMR0 = NIL_RTR0PTR;
535 pCritSect->pVMRC = NIL_RTRCPTR;
536 if (!fFinal)
537 STAMR3DeregisterF(pVM->pUVM, "/PDM/CritSects/%s/*", pCritSect->pszName);
538 RTStrFree((char *)pCritSect->pszName);
539 pCritSect->pszName = NULL;
540 return rc;
541}
542
543
544/**
545 * Deletes one read/write critical section.
546 *
547 * @returns VBox status code.
548 *
549 * @param pVM The cross context VM structure.
550 * @param pUVM The user mode VM handle.
551 * @param pCritSect The read/write critical section.
552 * @param pPrev The previous critical section in the list.
553 * @param fFinal Set if this is the final call and statistics shouldn't be deregistered.
554 *
555 * @remarks Caller must have entered the ListCritSect.
556 */
557static int pdmR3CritSectRwDeleteOne(PVM pVM, PUVM pUVM, PPDMCRITSECTRWINT pCritSect, PPDMCRITSECTRWINT pPrev, bool fFinal)
558{
559 /*
560 * Assert free waiters and so on (c&p from RTCritSectRwDelete).
561 */
562 Assert(pCritSect->Core.u32Magic == RTCRITSECTRW_MAGIC);
563 //Assert(pCritSect->Core.cNestings == 0);
564 //Assert(pCritSect->Core.cLockers == -1);
565 Assert(pCritSect->Core.hNativeWriter == NIL_RTNATIVETHREAD);
566
567 /*
568 * Invalidate the structure and free the semaphores.
569 */
570 if (!ASMAtomicCmpXchgU32(&pCritSect->Core.u32Magic, RTCRITSECTRW_MAGIC_DEAD, RTCRITSECTRW_MAGIC))
571 AssertFailed();
572
573 /*
574 * Unlink it.
575 */
576 if (pPrev)
577 pPrev->pNext = pCritSect->pNext;
578 else
579 pUVM->pdm.s.pRwCritSects = pCritSect->pNext;
580
581 /*
582 * Delete it (parts taken from RTCritSectRwDelete).
583 * In case someone is waiting we'll signal the semaphore cLockers + 1 times.
584 */
585 pCritSect->Core.fFlags = 0;
586 pCritSect->Core.u64State = 0;
587
588 SUPSEMEVENT hEvtWrite = (SUPSEMEVENT)pCritSect->Core.hEvtWrite;
589 pCritSect->Core.hEvtWrite = NIL_RTSEMEVENT;
590 AssertCompile(sizeof(hEvtWrite) == sizeof(pCritSect->Core.hEvtWrite));
591
592 SUPSEMEVENTMULTI hEvtRead = (SUPSEMEVENTMULTI)pCritSect->Core.hEvtRead;
593 pCritSect->Core.hEvtRead = NIL_RTSEMEVENTMULTI;
594 AssertCompile(sizeof(hEvtRead) == sizeof(pCritSect->Core.hEvtRead));
595
596 int rc1 = SUPSemEventClose(pVM->pSession, hEvtWrite); AssertRC(rc1);
597 int rc2 = SUPSemEventMultiClose(pVM->pSession, hEvtRead); AssertRC(rc2);
598
599 RTLockValidatorRecSharedDestroy(&pCritSect->Core.pValidatorRead);
600 RTLockValidatorRecExclDestroy(&pCritSect->Core.pValidatorWrite);
601
602 pCritSect->pNext = NULL;
603 pCritSect->pvKey = NULL;
604 pCritSect->pVMR3 = NULL;
605 pCritSect->pVMR0 = NIL_RTR0PTR;
606 pCritSect->pVMRC = NIL_RTRCPTR;
607 if (!fFinal)
608 STAMR3DeregisterF(pVM->pUVM, "/PDM/CritSectsRw/%s/*", pCritSect->pszName);
609 RTStrFree((char *)pCritSect->pszName);
610 pCritSect->pszName = NULL;
611
612 return RT_SUCCESS(rc1) ? rc2 : rc1;
613}
614
615
616/**
617 * Deletes all critical sections with a give initializer key.
618 *
619 * @returns VBox status code.
620 * The entire list is processed on failure, so we'll only
621 * return the first error code. This shouldn't be a problem
622 * since errors really shouldn't happen here.
623 * @param pVM The cross context VM structure.
624 * @param pvKey The initializer key.
625 */
626static int pdmR3CritSectDeleteByKey(PVM pVM, void *pvKey)
627{
628 /*
629 * Iterate the list and match key.
630 */
631 PUVM pUVM = pVM->pUVM;
632 int rc = VINF_SUCCESS;
633 PPDMCRITSECTINT pPrev = NULL;
634 RTCritSectEnter(&pUVM->pdm.s.ListCritSect);
635 PPDMCRITSECTINT pCur = pUVM->pdm.s.pCritSects;
636 while (pCur)
637 {
638 if (pCur->pvKey == pvKey)
639 {
640 int rc2 = pdmR3CritSectDeleteOne(pVM, pUVM, pCur, pPrev, false /* not final */);
641 AssertRC(rc2);
642 if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
643 rc = rc2;
644 }
645
646 /* next */
647 pPrev = pCur;
648 pCur = pCur->pNext;
649 }
650 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
651 return rc;
652}
653
654
655/**
656 * Deletes all read/write critical sections with a give initializer key.
657 *
658 * @returns VBox status code.
659 * The entire list is processed on failure, so we'll only
660 * return the first error code. This shouldn't be a problem
661 * since errors really shouldn't happen here.
662 * @param pVM The cross context VM structure.
663 * @param pvKey The initializer key.
664 */
665static int pdmR3CritSectRwDeleteByKey(PVM pVM, void *pvKey)
666{
667 /*
668 * Iterate the list and match key.
669 */
670 PUVM pUVM = pVM->pUVM;
671 int rc = VINF_SUCCESS;
672 PPDMCRITSECTRWINT pPrev = NULL;
673 RTCritSectEnter(&pUVM->pdm.s.ListCritSect);
674 PPDMCRITSECTRWINT pCur = pUVM->pdm.s.pRwCritSects;
675 while (pCur)
676 {
677 if (pCur->pvKey == pvKey)
678 {
679 int rc2 = pdmR3CritSectRwDeleteOne(pVM, pUVM, pCur, pPrev, false /* not final */);
680 AssertRC(rc2);
681 if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
682 rc = rc2;
683 }
684
685 /* next */
686 pPrev = pCur;
687 pCur = pCur->pNext;
688 }
689 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
690 return rc;
691}
692
693
694/**
695 * Deletes all undeleted critical sections (both types) initialized by a given
696 * device.
697 *
698 * @returns VBox status code.
699 * @param pVM The cross context VM structure.
700 * @param pDevIns The device handle.
701 */
702int pdmR3CritSectBothDeleteDevice(PVM pVM, PPDMDEVINS pDevIns)
703{
704 int rc1 = pdmR3CritSectDeleteByKey(pVM, pDevIns);
705 int rc2 = pdmR3CritSectRwDeleteByKey(pVM, pDevIns);
706 return RT_SUCCESS(rc1) ? rc2 : rc1;
707}
708
709
710/**
711 * Deletes all undeleted critical sections (both types) initialized by a given
712 * driver.
713 *
714 * @returns VBox status code.
715 * @param pVM The cross context VM structure.
716 * @param pDrvIns The driver handle.
717 */
718int pdmR3CritSectBothDeleteDriver(PVM pVM, PPDMDRVINS pDrvIns)
719{
720 int rc1 = pdmR3CritSectDeleteByKey(pVM, pDrvIns);
721 int rc2 = pdmR3CritSectRwDeleteByKey(pVM, pDrvIns);
722 return RT_SUCCESS(rc1) ? rc2 : rc1;
723}
724
725
726/**
727 * Deletes the critical section.
728 *
729 * @returns VBox status code.
730 * @param pCritSect The PDM critical section to destroy.
731 */
732VMMR3DECL(int) PDMR3CritSectDelete(PPDMCRITSECT pCritSect)
733{
734 if (!RTCritSectIsInitialized(&pCritSect->s.Core))
735 return VINF_SUCCESS;
736
737 /*
738 * Find and unlink it.
739 */
740 PVM pVM = pCritSect->s.pVMR3;
741 PUVM pUVM = pVM->pUVM;
742 AssertReleaseReturn(pVM, VERR_PDM_CRITSECT_IPE);
743 PPDMCRITSECTINT pPrev = NULL;
744 RTCritSectEnter(&pUVM->pdm.s.ListCritSect);
745 PPDMCRITSECTINT pCur = pUVM->pdm.s.pCritSects;
746 while (pCur)
747 {
748 if (pCur == &pCritSect->s)
749 {
750 int rc = pdmR3CritSectDeleteOne(pVM, pUVM, pCur, pPrev, false /* not final */);
751 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
752 return rc;
753 }
754
755 /* next */
756 pPrev = pCur;
757 pCur = pCur->pNext;
758 }
759 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
760 AssertReleaseMsgFailed(("pCritSect=%p wasn't found!\n", pCritSect));
761 return VERR_PDM_CRITSECT_NOT_FOUND;
762}
763
764
765/**
766 * Deletes the read/write critical section.
767 *
768 * @returns VBox status code.
769 * @param pCritSect The PDM read/write critical section to destroy.
770 */
771VMMR3DECL(int) PDMR3CritSectRwDelete(PPDMCRITSECTRW pCritSect)
772{
773 if (!PDMCritSectRwIsInitialized(pCritSect))
774 return VINF_SUCCESS;
775
776 /*
777 * Find and unlink it.
778 */
779 PVM pVM = pCritSect->s.pVMR3;
780 PUVM pUVM = pVM->pUVM;
781 AssertReleaseReturn(pVM, VERR_PDM_CRITSECT_IPE);
782 PPDMCRITSECTRWINT pPrev = NULL;
783 RTCritSectEnter(&pUVM->pdm.s.ListCritSect);
784 PPDMCRITSECTRWINT pCur = pUVM->pdm.s.pRwCritSects;
785 while (pCur)
786 {
787 if (pCur == &pCritSect->s)
788 {
789 int rc = pdmR3CritSectRwDeleteOne(pVM, pUVM, pCur, pPrev, false /* not final */);
790 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
791 return rc;
792 }
793
794 /* next */
795 pPrev = pCur;
796 pCur = pCur->pNext;
797 }
798 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
799 AssertReleaseMsgFailed(("pCritSect=%p wasn't found!\n", pCritSect));
800 return VERR_PDM_CRITSECT_NOT_FOUND;
801}
802
803
804/**
805 * Gets the name of the critical section.
806 *
807 *
808 * @returns Pointer to the critical section name (read only) on success,
809 * NULL on failure (invalid critical section).
810 * @param pCritSect The critical section.
811 */
812VMMR3DECL(const char *) PDMR3CritSectName(PCPDMCRITSECT pCritSect)
813{
814 AssertPtrReturn(pCritSect, NULL);
815 AssertReturn(pCritSect->s.Core.u32Magic == RTCRITSECT_MAGIC, NULL);
816 return pCritSect->s.pszName;
817}
818
819
820/**
821 * Gets the name of the read/write critical section.
822 *
823 *
824 * @returns Pointer to the critical section name (read only) on success,
825 * NULL on failure (invalid critical section).
826 * @param pCritSect The read/write critical section.
827 */
828VMMR3DECL(const char *) PDMR3CritSectRwName(PCPDMCRITSECTRW pCritSect)
829{
830 AssertPtrReturn(pCritSect, NULL);
831 AssertReturn(pCritSect->s.Core.u32Magic == RTCRITSECTRW_MAGIC, NULL);
832 return pCritSect->s.pszName;
833}
834
835
836/**
837 * Yield the critical section if someone is waiting on it.
838 *
839 * When yielding, we'll leave the critical section and try to make sure the
840 * other waiting threads get a chance of entering before we reclaim it.
841 *
842 * @retval true if yielded.
843 * @retval false if not yielded.
844 * @param pCritSect The critical section.
845 */
846VMMR3DECL(bool) PDMR3CritSectYield(PPDMCRITSECT pCritSect)
847{
848 AssertPtrReturn(pCritSect, false);
849 AssertReturn(pCritSect->s.Core.u32Magic == RTCRITSECT_MAGIC, false);
850 Assert(pCritSect->s.Core.NativeThreadOwner == RTThreadNativeSelf());
851 Assert(!(pCritSect->s.Core.fFlags & RTCRITSECT_FLAGS_NOP));
852
853 /* No recursion allowed here. */
854 int32_t const cNestings = pCritSect->s.Core.cNestings;
855 AssertReturn(cNestings == 1, false);
856
857 int32_t const cLockers = ASMAtomicReadS32(&pCritSect->s.Core.cLockers);
858 if (cLockers < cNestings)
859 return false;
860
861#ifdef PDMCRITSECT_STRICT
862 RTLOCKVALSRCPOS const SrcPos = pCritSect->s.Core.pValidatorRec->SrcPos;
863#endif
864 PDMCritSectLeave(pCritSect);
865
866 /*
867 * If we're lucky, then one of the waiters has entered the lock already.
868 * We spin a little bit in hope for this to happen so we can avoid the
869 * yield detour.
870 */
871 if (ASMAtomicUoReadS32(&pCritSect->s.Core.cNestings) == 0)
872 {
873 int cLoops = 20;
874 while ( cLoops > 0
875 && ASMAtomicUoReadS32(&pCritSect->s.Core.cNestings) == 0
876 && ASMAtomicUoReadS32(&pCritSect->s.Core.cLockers) >= 0)
877 {
878 ASMNopPause();
879 cLoops--;
880 }
881 if (cLoops == 0)
882 RTThreadYield();
883 }
884
885#ifdef PDMCRITSECT_STRICT
886 int rc = PDMCritSectEnterDebug(pCritSect, VERR_IGNORED,
887 SrcPos.uId, SrcPos.pszFile, SrcPos.uLine, SrcPos.pszFunction);
888#else
889 int rc = PDMCritSectEnter(pCritSect, VERR_IGNORED);
890#endif
891 AssertLogRelRC(rc);
892 return true;
893}
894
895
896/**
897 * PDMR3CritSectBothCountOwned worker.
898 *
899 * @param pszName The critical section name.
900 * @param ppszNames Pointer to the pszNames variable.
901 * @param pcchLeft Pointer to the cchLeft variable.
902 * @param fFirst Whether this is the first name or not.
903 */
904static void pdmR3CritSectAppendNameToList(char const *pszName, char **ppszNames, size_t *pcchLeft, bool fFirst)
905{
906 size_t cchLeft = *pcchLeft;
907 if (cchLeft)
908 {
909 char *pszNames = *ppszNames;
910
911 /* try add comma. */
912 if (fFirst)
913 {
914 *pszNames++ = ',';
915 if (--cchLeft)
916 {
917 *pszNames++ = ' ';
918 cchLeft--;
919 }
920 }
921
922 /* try copy the name. */
923 if (cchLeft)
924 {
925 size_t const cchName = strlen(pszName);
926 if (cchName < cchLeft)
927 {
928 memcpy(pszNames, pszName, cchName);
929 pszNames += cchName;
930 cchLeft -= cchName;
931 }
932 else
933 {
934 if (cchLeft > 2)
935 {
936 memcpy(pszNames, pszName, cchLeft - 2);
937 pszNames += cchLeft - 2;
938 cchLeft = 2;
939 }
940 while (cchLeft-- > 0)
941 *pszNames++ = '+';
942 }
943 }
944 *pszNames = '\0';
945
946 *pcchLeft = cchLeft;
947 *ppszNames = pszNames;
948 }
949}
950
951
952/**
953 * Counts the critical sections (both type) owned by the calling thread,
954 * optionally returning a comma separated list naming them.
955 *
956 * Read ownerships are not included in non-strict builds.
957 *
958 * This is for diagnostic purposes only.
959 *
960 * @returns Lock count.
961 *
962 * @param pVM The cross context VM structure.
963 * @param pszNames Where to return the critical section names.
964 * @param cbNames The size of the buffer.
965 */
966VMMR3DECL(uint32_t) PDMR3CritSectCountOwned(PVM pVM, char *pszNames, size_t cbNames)
967{
968 /*
969 * Init the name buffer.
970 */
971 size_t cchLeft = cbNames;
972 if (cchLeft)
973 {
974 cchLeft--;
975 pszNames[0] = pszNames[cchLeft] = '\0';
976 }
977
978 /*
979 * Iterate the critical sections.
980 */
981 uint32_t cCritSects = 0;
982 RTNATIVETHREAD const hNativeThread = RTThreadNativeSelf();
983 /* This is unsafe, but wtf. */
984 for (PPDMCRITSECTINT pCur = pVM->pUVM->pdm.s.pCritSects;
985 pCur;
986 pCur = pCur->pNext)
987 {
988 /* Same as RTCritSectIsOwner(). */
989 if (pCur->Core.NativeThreadOwner == hNativeThread)
990 {
991 cCritSects++;
992 pdmR3CritSectAppendNameToList(pCur->pszName, &pszNames, &cchLeft, cCritSects == 1);
993 }
994 }
995
996 /* This is unsafe, but wtf. */
997 for (PPDMCRITSECTRWINT pCur = pVM->pUVM->pdm.s.pRwCritSects;
998 pCur;
999 pCur = pCur->pNext)
1000 {
1001 if ( pCur->Core.hNativeWriter == hNativeThread
1002 || PDMCritSectRwIsReadOwner((PPDMCRITSECTRW)pCur, false /*fWannaHear*/) )
1003 {
1004 cCritSects++;
1005 pdmR3CritSectAppendNameToList(pCur->pszName, &pszNames, &cchLeft, cCritSects == 1);
1006 }
1007 }
1008
1009 return cCritSects;
1010}
1011
1012
1013/**
1014 * Leave all critical sections the calling thread owns.
1015 *
1016 * This is only used when entering guru meditation in order to prevent other
1017 * EMTs and I/O threads from deadlocking.
1018 *
1019 * @param pVM The cross context VM structure.
1020 */
1021VMMR3_INT_DECL(void) PDMR3CritSectLeaveAll(PVM pVM)
1022{
1023 RTNATIVETHREAD const hNativeSelf = RTThreadNativeSelf();
1024 PUVM pUVM = pVM->pUVM;
1025
1026 RTCritSectEnter(&pUVM->pdm.s.ListCritSect);
1027 for (PPDMCRITSECTINT pCur = pUVM->pdm.s.pCritSects;
1028 pCur;
1029 pCur = pCur->pNext)
1030 {
1031 while ( pCur->Core.NativeThreadOwner == hNativeSelf
1032 && pCur->Core.cNestings > 0)
1033 PDMCritSectLeave((PPDMCRITSECT)pCur);
1034 }
1035 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
1036}
1037
1038
1039/**
1040 * Gets the address of the NOP critical section.
1041 *
1042 * The NOP critical section will not perform any thread serialization but let
1043 * all enter immediately and concurrently.
1044 *
1045 * @returns The address of the NOP critical section.
1046 * @param pVM The cross context VM structure.
1047 */
1048VMMR3DECL(PPDMCRITSECT) PDMR3CritSectGetNop(PVM pVM)
1049{
1050 VM_ASSERT_VALID_EXT_RETURN(pVM, NULL);
1051 return &pVM->pdm.s.NopCritSect;
1052}
1053
1054
1055/**
1056 * Gets the ring-0 address of the NOP critical section.
1057 *
1058 * @returns The ring-0 address of the NOP critical section.
1059 * @param pVM The cross context VM structure.
1060 */
1061VMMR3DECL(R0PTRTYPE(PPDMCRITSECT)) PDMR3CritSectGetNopR0(PVM pVM)
1062{
1063 VM_ASSERT_VALID_EXT_RETURN(pVM, NIL_RTR0PTR);
1064 return MMHyperR3ToR0(pVM, &pVM->pdm.s.NopCritSect);
1065}
1066
1067
1068/**
1069 * Gets the raw-mode context address of the NOP critical section.
1070 *
1071 * @returns The raw-mode context address of the NOP critical section.
1072 * @param pVM The cross context VM structure.
1073 */
1074VMMR3DECL(RCPTRTYPE(PPDMCRITSECT)) PDMR3CritSectGetNopRC(PVM pVM)
1075{
1076 VM_ASSERT_VALID_EXT_RETURN(pVM, NIL_RTRCPTR);
1077 return MMHyperR3ToRC(pVM, &pVM->pdm.s.NopCritSect);
1078}
1079
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