VirtualBox

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

Last change on this file since 80309 was 80281, checked in by vboxsync, 5 years ago

VMM,++: Refactoring code to use VMMC & VMMCPUCC. bugref:9217

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