VirtualBox

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

Last change on this file since 37507 was 37466, checked in by vboxsync, 14 years ago

VMM,Devices: Automatically use a per-device lock instead of the giant IOM lock. With exception of the PIC, APIC, IOAPIC and PCI buses which are all using the PDM crit sect, there should be no calls between devices. So, this change should be relatively safe.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 23.1 KB
Line 
1/* $Id: PDMCritSect.cpp 37466 2011-06-15 12:44:16Z vboxsync $ */
2/** @file
3 * PDM - Critical Sections, Ring-3.
4 */
5
6/*
7 * Copyright (C) 2006-2009 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/mm.h>
26#include <VBox/vmm/vm.h>
27#include <VBox/vmm/uvm.h>
28
29#include <VBox/err.h>
30#include <VBox/log.h>
31#include <VBox/sup.h>
32#include <iprt/asm.h>
33#include <iprt/assert.h>
34#include <iprt/lockvalidator.h>
35#include <iprt/string.h>
36#include <iprt/thread.h>
37
38
39/*******************************************************************************
40* Internal Functions *
41*******************************************************************************/
42static int pdmR3CritSectDeleteOne(PVM pVM, PUVM pUVM, PPDMCRITSECTINT pCritSect, PPDMCRITSECTINT pPrev, bool fFinal);
43
44
45
46/**
47 * Register statistics related to the critical sections.
48 *
49 * @returns VBox status code.
50 * @param pVM The VM handle.
51 */
52int pdmR3CritSectInitStats(PVM pVM)
53{
54 STAM_REG(pVM, &pVM->pdm.s.StatQueuedCritSectLeaves, STAMTYPE_COUNTER, "/PDM/QueuedCritSectLeaves", STAMUNIT_OCCURENCES,
55 "Number of times a critical section leave request needed to be queued for ring-3 execution.");
56 return VINF_SUCCESS;
57}
58
59
60/**
61 * Relocates all the critical sections.
62 *
63 * @param pVM The VM handle.
64 */
65void pdmR3CritSectRelocate(PVM pVM)
66{
67 PUVM pUVM = pVM->pUVM;
68 RTCritSectEnter(&pUVM->pdm.s.ListCritSect);
69
70 for (PPDMCRITSECTINT pCur = pUVM->pdm.s.pCritSects;
71 pCur;
72 pCur = pCur->pNext)
73 pCur->pVMRC = pVM->pVMRC;
74
75 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
76}
77
78
79/**
80 * Deletes all remaining critical sections.
81 *
82 * This is called at the very end of the termination process. It is also called
83 * at the end of vmR3CreateU failure cleanup, which may cause it to be called
84 * twice depending on where vmR3CreateU actually failed. We have to do the
85 * latter call because other components expect the critical sections to be
86 * automatically deleted.
87 *
88 * @returns VBox status.
89 * First error code, rest is lost.
90 * @param pVMU The user mode VM handle.
91 * @remark Don't confuse this with PDMR3CritSectDelete.
92 */
93VMMDECL(int) PDMR3CritSectTerm(PVM pVM)
94{
95 PUVM pUVM = pVM->pUVM;
96 int rc = VINF_SUCCESS;
97 RTCritSectEnter(&pUVM->pdm.s.ListCritSect);
98
99 while (pUVM->pdm.s.pCritSects)
100 {
101 int rc2 = pdmR3CritSectDeleteOne(pVM, pUVM, pUVM->pdm.s.pCritSects, NULL, true /* final */);
102 AssertRC(rc2);
103 if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
104 rc = rc2;
105 }
106
107 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
108 return rc;
109}
110
111
112/**
113 * Initializes a critical section and inserts it into the list.
114 *
115 * @returns VBox status code.
116 * @param pVM The Vm handle.
117 * @param pCritSect The critical section.
118 * @param pvKey The owner key.
119 * @param RT_SRC_POS_DECL The source position.
120 * @param pszName The name of the critical section (for statistics).
121 * @param pszNameFmt Format string for naming the critical section. For
122 * statistics and lock validation.
123 * @param va Arguments for the format string.
124 */
125static int pdmR3CritSectInitOne(PVM pVM, PPDMCRITSECTINT pCritSect, void *pvKey, RT_SRC_POS_DECL,
126 const char *pszNameFmt, va_list va)
127{
128 VM_ASSERT_EMT(pVM);
129
130 /*
131 * Allocate the semaphore.
132 */
133 AssertCompile(sizeof(SUPSEMEVENT) == sizeof(pCritSect->Core.EventSem));
134 int rc = SUPSemEventCreate(pVM->pSession, (PSUPSEMEVENT)&pCritSect->Core.EventSem);
135 if (RT_SUCCESS(rc))
136 {
137 /* Only format the name once. */
138 char *pszName = RTStrAPrintf2V(pszNameFmt, va); /** @todo plug the "leak"... */
139 if (pszName)
140 {
141#ifndef PDMCRITSECT_STRICT
142 pCritSect->Core.pValidatorRec = NULL;
143#else
144 rc = RTLockValidatorRecExclCreate(&pCritSect->Core.pValidatorRec,
145# ifdef RT_LOCK_STRICT_ORDER
146 RTLockValidatorClassForSrcPos(RT_SRC_POS_ARGS, "%s", pszName),
147# else
148 NIL_RTLOCKVALCLASS,
149# endif
150 RTLOCKVAL_SUB_CLASS_NONE,
151 pCritSect, true, "%s", pszName);
152#endif
153 if (RT_SUCCESS(rc))
154 {
155 /*
156 * Initialize the structure (first bit is c&p from RTCritSectInitEx).
157 */
158 pCritSect->Core.u32Magic = RTCRITSECT_MAGIC;
159 pCritSect->Core.fFlags = 0;
160 pCritSect->Core.cNestings = 0;
161 pCritSect->Core.cLockers = -1;
162 pCritSect->Core.NativeThreadOwner = NIL_RTNATIVETHREAD;
163 pCritSect->pVMR3 = pVM;
164 pCritSect->pVMR0 = pVM->pVMR0;
165 pCritSect->pVMRC = pVM->pVMRC;
166 pCritSect->pvKey = pvKey;
167 pCritSect->fAutomaticDefaultCritsect = false;
168 pCritSect->fUsedByTimerOrSimilar = false;
169 pCritSect->EventToSignal = NIL_RTSEMEVENT;
170 pCritSect->pNext = pVM->pUVM->pdm.s.pCritSects;
171 pCritSect->pszName = pszName;
172 pVM->pUVM->pdm.s.pCritSects = pCritSect;
173 STAMR3RegisterF(pVM, &pCritSect->StatContentionRZLock, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, NULL, "/PDM/CritSects/%s/ContentionRZLock", pCritSect->pszName);
174 STAMR3RegisterF(pVM, &pCritSect->StatContentionRZUnlock,STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, NULL, "/PDM/CritSects/%s/ContentionRZUnlock", pCritSect->pszName);
175 STAMR3RegisterF(pVM, &pCritSect->StatContentionR3, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, NULL, "/PDM/CritSects/%s/ContentionR3", pCritSect->pszName);
176#ifdef VBOX_WITH_STATISTICS
177 STAMR3RegisterF(pVM, &pCritSect->StatLocked, STAMTYPE_PROFILE_ADV, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_OCCURENCE, NULL, "/PDM/CritSects/%s/Locked", pCritSect->pszName);
178#endif
179 return VINF_SUCCESS;
180 }
181
182 RTStrFree(pszName);
183 }
184 else
185 rc = VERR_NO_STR_MEMORY;
186 SUPSemEventClose(pVM->pSession, (SUPSEMEVENT)pCritSect->Core.EventSem);
187 }
188 return rc;
189}
190
191
192/**
193 * Initializes a PDM critical section for internal use.
194 *
195 * The PDM critical sections are derived from the IPRT critical sections, but
196 * works in GC as well.
197 *
198 * @returns VBox status code.
199 * @param pVM The VM handle.
200 * @param pDevIns Device instance.
201 * @param pCritSect Pointer to the critical section.
202 * @param RT_SRC_POS_DECL Use RT_SRC_POS.
203 * @param pszNameFmt Format string for naming the critical section. For
204 * statistics and lock validation.
205 * @param ... Arguments for the format string.
206 * @thread EMT(0)
207 */
208VMMR3DECL(int) PDMR3CritSectInit(PVM pVM, PPDMCRITSECT pCritSect, RT_SRC_POS_DECL, const char *pszNameFmt, ...)
209{
210#if HC_ARCH_BITS == 64 && GC_ARCH_BITS == 32
211 AssertCompile(sizeof(pCritSect->padding) >= sizeof(pCritSect->s));
212#endif
213 Assert(RT_ALIGN_P(pCritSect, sizeof(uintptr_t)) == pCritSect);
214 va_list va;
215 va_start(va, pszNameFmt);
216 int rc = pdmR3CritSectInitOne(pVM, &pCritSect->s, pCritSect, RT_SRC_POS_ARGS, pszNameFmt, va);
217 va_end(va);
218 return rc;
219}
220
221
222/**
223 * Initializes a PDM critical section for a device.
224 *
225 * The PDM critical sections are derived from the IPRT critical sections, but
226 * works in GC as well.
227 *
228 * @returns VBox status code.
229 * @param pVM The VM handle.
230 * @param pDevIns Device instance.
231 * @param pCritSect Pointer to the critical section.
232 * @param pszNameFmt Format string for naming the critical section. For
233 * statistics and lock validation.
234 * @param va Arguments for the format string.
235 */
236int pdmR3CritSectInitDevice(PVM pVM, PPDMDEVINS pDevIns, PPDMCRITSECT pCritSect, RT_SRC_POS_DECL,
237 const char *pszNameFmt, va_list va)
238{
239 return pdmR3CritSectInitOne(pVM, &pCritSect->s, pDevIns, RT_SRC_POS_ARGS, pszNameFmt, va);
240}
241
242
243/**
244 * Initializes the automatic default PDM critical section for a device.
245 *
246 * @returns VBox status code.
247 * @param pVM The VM handle.
248 * @param pDevIns Device instance.
249 * @param pCritSect Pointer to the critical section.
250 */
251int pdmR3CritSectInitDeviceAuto(PVM pVM, PPDMDEVINS pDevIns, PPDMCRITSECT pCritSect, RT_SRC_POS_DECL,
252 const char *pszNameFmt, ...)
253{
254 va_list va;
255 va_start(va, pszNameFmt);
256 int rc = pdmR3CritSectInitOne(pVM, &pCritSect->s, pDevIns, RT_SRC_POS_ARGS, pszNameFmt, va);
257 if (RT_SUCCESS(rc))
258 pCritSect->s.fAutomaticDefaultCritsect = true;
259 va_end(va);
260 return rc;
261}
262
263
264/**
265 * Initializes a PDM critical section for a driver.
266 *
267 * @returns VBox status code.
268 * @param pVM The VM handle.
269 * @param pDrvIns Driver instance.
270 * @param pCritSect Pointer to the critical section.
271 * @param pszNameFmt Format string for naming the critical section. For
272 * statistics and lock validation.
273 * @param ... Arguments for the format string.
274 */
275int pdmR3CritSectInitDriver(PVM pVM, PPDMDRVINS pDrvIns, PPDMCRITSECT pCritSect, RT_SRC_POS_DECL,
276 const char *pszNameFmt, ...)
277{
278 va_list va;
279 va_start(va, pszNameFmt);
280 int rc = pdmR3CritSectInitOne(pVM, &pCritSect->s, pDrvIns, RT_SRC_POS_ARGS, pszNameFmt, va);
281 va_end(va);
282 return rc;
283}
284
285
286/**
287 * Deletes one critical section.
288 *
289 * @returns Return code from RTCritSectDelete.
290 *
291 * @param pVM The VM handle.
292 * @param pCritSect The critical section.
293 * @param pPrev The previous critical section in the list.
294 * @param fFinal Set if this is the final call and statistics shouldn't be deregistered.
295 *
296 * @remarks Caller must have entered the ListCritSect.
297 */
298static int pdmR3CritSectDeleteOne(PVM pVM, PUVM pUVM, PPDMCRITSECTINT pCritSect, PPDMCRITSECTINT pPrev, bool fFinal)
299{
300 /*
301 * Assert free waiters and so on (c&p from RTCritSectDelete).
302 */
303 Assert(pCritSect->Core.u32Magic == RTCRITSECT_MAGIC);
304 Assert(pCritSect->Core.cNestings == 0);
305 Assert(pCritSect->Core.cLockers == -1);
306 Assert(pCritSect->Core.NativeThreadOwner == NIL_RTNATIVETHREAD);
307 Assert(RTCritSectIsOwner(&pUVM->pdm.s.ListCritSect));
308
309 /*
310 * Unlink it.
311 */
312 if (pPrev)
313 pPrev->pNext = pCritSect->pNext;
314 else
315 pUVM->pdm.s.pCritSects = pCritSect->pNext;
316
317 /*
318 * Delete it (parts taken from RTCritSectDelete).
319 * In case someone is waiting we'll signal the semaphore cLockers + 1 times.
320 */
321 ASMAtomicWriteU32(&pCritSect->Core.u32Magic, 0);
322 SUPSEMEVENT hEvent = (SUPSEMEVENT)pCritSect->Core.EventSem;
323 pCritSect->Core.EventSem = NIL_RTSEMEVENT;
324 while (pCritSect->Core.cLockers-- >= 0)
325 SUPSemEventSignal(pVM->pSession, hEvent);
326 ASMAtomicWriteS32(&pCritSect->Core.cLockers, -1);
327 int rc = SUPSemEventClose(pVM->pSession, hEvent);
328 AssertRC(rc);
329 RTLockValidatorRecExclDestroy(&pCritSect->Core.pValidatorRec);
330 pCritSect->pNext = NULL;
331 pCritSect->pvKey = NULL;
332 pCritSect->pVMR3 = NULL;
333 pCritSect->pVMR0 = NIL_RTR0PTR;
334 pCritSect->pVMRC = NIL_RTRCPTR;
335 RTStrFree((char *)pCritSect->pszName);
336 pCritSect->pszName = NULL;
337 if (!fFinal)
338 {
339 STAMR3Deregister(pVM, &pCritSect->StatContentionRZLock);
340 STAMR3Deregister(pVM, &pCritSect->StatContentionRZUnlock);
341 STAMR3Deregister(pVM, &pCritSect->StatContentionR3);
342#ifdef VBOX_WITH_STATISTICS
343 STAMR3Deregister(pVM, &pCritSect->StatLocked);
344#endif
345 }
346 return rc;
347}
348
349
350/**
351 * Deletes all critical sections with a give initializer key.
352 *
353 * @returns VBox status code.
354 * The entire list is processed on failure, so we'll only
355 * return the first error code. This shouldn't be a problem
356 * since errors really shouldn't happen here.
357 * @param pVM The VM handle.
358 * @param pvKey The initializer key.
359 */
360static int pdmR3CritSectDeleteByKey(PVM pVM, void *pvKey)
361{
362 /*
363 * Iterate the list and match key.
364 */
365 PUVM pUVM = pVM->pUVM;
366 int rc = VINF_SUCCESS;
367 PPDMCRITSECTINT pPrev = NULL;
368 RTCritSectEnter(&pUVM->pdm.s.ListCritSect);
369 PPDMCRITSECTINT pCur = pUVM->pdm.s.pCritSects;
370 while (pCur)
371 {
372 if (pCur->pvKey == pvKey)
373 {
374 int rc2 = pdmR3CritSectDeleteOne(pVM, pUVM, pCur, pPrev, false /* not final */);
375 AssertRC(rc2);
376 if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
377 rc = rc2;
378 }
379
380 /* next */
381 pPrev = pCur;
382 pCur = pCur->pNext;
383 }
384 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
385 return rc;
386}
387
388
389/**
390 * Deletes all undeleted critical sections initialized by a given device.
391 *
392 * @returns VBox status code.
393 * @param pVM The VM handle.
394 * @param pDevIns The device handle.
395 */
396int pdmR3CritSectDeleteDevice(PVM pVM, PPDMDEVINS pDevIns)
397{
398 return pdmR3CritSectDeleteByKey(pVM, pDevIns);
399}
400
401
402/**
403 * Deletes all undeleted critical sections initialized by a given driver.
404 *
405 * @returns VBox status code.
406 * @param pVM The VM handle.
407 * @param pDrvIns The driver handle.
408 */
409int pdmR3CritSectDeleteDriver(PVM pVM, PPDMDRVINS pDrvIns)
410{
411 return pdmR3CritSectDeleteByKey(pVM, pDrvIns);
412}
413
414
415/**
416 * Deletes the critical section.
417 *
418 * @returns VBox status code.
419 * @param pCritSect The PDM critical section to destroy.
420 */
421VMMR3DECL(int) PDMR3CritSectDelete(PPDMCRITSECT pCritSect)
422{
423 if (!RTCritSectIsInitialized(&pCritSect->s.Core))
424 return VINF_SUCCESS;
425
426 /*
427 * Find and unlink it.
428 */
429 PVM pVM = pCritSect->s.pVMR3;
430 PUVM pUVM = pVM->pUVM;
431 AssertReleaseReturn(pVM, VERR_INTERNAL_ERROR);
432 PPDMCRITSECTINT pPrev = NULL;
433 RTCritSectEnter(&pUVM->pdm.s.ListCritSect);
434 PPDMCRITSECTINT pCur = pUVM->pdm.s.pCritSects;
435 while (pCur)
436 {
437 if (pCur == &pCritSect->s)
438 {
439 int rc = pdmR3CritSectDeleteOne(pVM, pUVM, pCur, pPrev, false /* not final */);
440 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
441 return rc;
442 }
443
444 /* next */
445 pPrev = pCur;
446 pCur = pCur->pNext;
447 }
448 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
449 AssertReleaseMsgFailed(("pCritSect=%p wasn't found!\n", pCritSect));
450 return VERR_INTERNAL_ERROR;
451}
452
453
454/**
455 * Gets the name of the critical section.
456 *
457 *
458 * @returns Pointer to the critical section name (read only) on success,
459 * NULL on failure (invalid critical section).
460 * @param pCritSect The critical section.
461 */
462VMMR3DECL(const char *) PDMR3CritSectName(PCPDMCRITSECT pCritSect)
463{
464 AssertPtrReturn(pCritSect, NULL);
465 AssertReturn(pCritSect->s.Core.u32Magic == RTCRITSECT_MAGIC, NULL);
466 return pCritSect->s.pszName;
467}
468
469
470/**
471 * Yield the critical section if someone is waiting on it.
472 *
473 * When yielding, we'll leave the critical section and try to make sure the
474 * other waiting threads get a chance of entering before we reclaim it.
475 *
476 * @retval true if yielded.
477 * @retval false if not yielded.
478 * @param pCritSect The critical section.
479 */
480VMMR3DECL(bool) PDMR3CritSectYield(PPDMCRITSECT pCritSect)
481{
482 AssertPtrReturn(pCritSect, false);
483 AssertReturn(pCritSect->s.Core.u32Magic == RTCRITSECT_MAGIC, false);
484 Assert(pCritSect->s.Core.NativeThreadOwner == RTThreadNativeSelf());
485 Assert(!(pCritSect->s.Core.fFlags & RTCRITSECT_FLAGS_NOP));
486
487 /* No recursion allowed here. */
488 int32_t const cNestings = pCritSect->s.Core.cNestings;
489 AssertReturn(cNestings == 1, false);
490
491 int32_t const cLockers = ASMAtomicReadS32(&pCritSect->s.Core.cLockers);
492 if (cLockers < cNestings)
493 return false;
494
495#ifdef PDMCRITSECT_STRICT
496 RTLOCKVALSRCPOS const SrcPos = pCritSect->s.Core.pValidatorRec->SrcPos;
497#endif
498 PDMCritSectLeave(pCritSect);
499
500 /*
501 * If we're lucky, then one of the waiters has entered the lock already.
502 * We spin a little bit in hope for this to happen so we can avoid the
503 * yield detour.
504 */
505 if (ASMAtomicUoReadS32(&pCritSect->s.Core.cNestings) == 0)
506 {
507 int cLoops = 20;
508 while ( cLoops > 0
509 && ASMAtomicUoReadS32(&pCritSect->s.Core.cNestings) == 0
510 && ASMAtomicUoReadS32(&pCritSect->s.Core.cLockers) >= 0)
511 {
512 ASMNopPause();
513 cLoops--;
514 }
515 if (cLoops == 0)
516 RTThreadYield();
517 }
518
519#ifdef PDMCRITSECT_STRICT
520 int rc = PDMCritSectEnterDebug(pCritSect, VERR_INTERNAL_ERROR,
521 SrcPos.uId, SrcPos.pszFile, SrcPos.uLine, SrcPos.pszFunction);
522#else
523 int rc = PDMCritSectEnter(pCritSect, VERR_INTERNAL_ERROR);
524#endif
525 AssertLogRelRC(rc);
526 return true;
527}
528
529
530/**
531 * Schedule a event semaphore for signalling upon critsect exit.
532 *
533 * @returns VINF_SUCCESS on success.
534 * @returns VERR_TOO_MANY_SEMAPHORES if an event was already scheduled.
535 * @returns VERR_NOT_OWNER if we're not the critsect owner.
536 * @returns VERR_SEM_DESTROYED if RTCritSectDelete was called while waiting.
537 *
538 * @param pCritSect The critical section.
539 * @param EventToSignal The semaphore that should be signalled.
540 */
541VMMR3DECL(int) PDMR3CritSectScheduleExitEvent(PPDMCRITSECT pCritSect, RTSEMEVENT EventToSignal)
542{
543 AssertPtr(pCritSect);
544 Assert(!(pCritSect->s.Core.fFlags & RTCRITSECT_FLAGS_NOP));
545 Assert(EventToSignal != NIL_RTSEMEVENT);
546 if (RT_UNLIKELY(!RTCritSectIsOwner(&pCritSect->s.Core)))
547 return VERR_NOT_OWNER;
548 if (RT_LIKELY( pCritSect->s.EventToSignal == NIL_RTSEMEVENT
549 || pCritSect->s.EventToSignal == EventToSignal))
550 {
551 pCritSect->s.EventToSignal = EventToSignal;
552 return VINF_SUCCESS;
553 }
554 return VERR_TOO_MANY_SEMAPHORES;
555}
556
557
558/**
559 * Counts the critical sections owned by the calling thread, optionally
560 * returning a comma separated list naming them.
561 *
562 * This is for diagnostic purposes only.
563 *
564 * @returns Lock count.
565 *
566 * @param pVM The VM handle.
567 * @param pszNames Where to return the critical section names.
568 * @param cbNames The size of the buffer.
569 */
570VMMR3DECL(uint32_t) PDMR3CritSectCountOwned(PVM pVM, char *pszNames, size_t cbNames)
571{
572 /*
573 * Init the name buffer.
574 */
575 size_t cchLeft = cbNames;
576 if (cchLeft)
577 {
578 cchLeft--;
579 pszNames[0] = pszNames[cchLeft] = '\0';
580 }
581
582 /*
583 * Iterate the critical sections.
584 */
585 /* This is unsafe, but wtf. */
586 RTNATIVETHREAD const hNativeThread = RTThreadNativeSelf();
587 uint32_t cCritSects = 0;
588 for (PPDMCRITSECTINT pCur = pVM->pUVM->pdm.s.pCritSects;
589 pCur;
590 pCur = pCur->pNext)
591 {
592 /* Same as RTCritSectIsOwner(). */
593 if (pCur->Core.NativeThreadOwner == hNativeThread)
594 {
595 cCritSects++;
596
597 /*
598 * Copy the name if there is space. Fun stuff.
599 */
600 if (cchLeft)
601 {
602 /* try add comma. */
603 if (cCritSects != 1)
604 {
605 *pszNames++ = ',';
606 if (--cchLeft)
607 {
608 *pszNames++ = ' ';
609 cchLeft--;
610 }
611 }
612
613 /* try copy the name. */
614 if (cchLeft)
615 {
616 size_t const cchName = strlen(pCur->pszName);
617 if (cchName < cchLeft)
618 {
619 memcpy(pszNames, pCur->pszName, cchName);
620 pszNames += cchName;
621 cchLeft -= cchName;
622 }
623 else
624 {
625 if (cchLeft > 2)
626 {
627 memcpy(pszNames, pCur->pszName, cchLeft - 2);
628 pszNames += cchLeft - 2;
629 cchLeft = 2;
630 }
631 while (cchLeft-- > 0)
632 *pszNames++ = '+';
633 }
634 }
635 *pszNames = '\0';
636 }
637 }
638 }
639
640 return cCritSects;
641}
642
643
644/**
645 * Leave all critical sections the calling thread owns.
646 *
647 * This is only used when entering guru meditation in order to prevent other
648 * EMTs and I/O threads from deadlocking.
649 *
650 * @param pVM The VM handle.
651 */
652VMMR3DECL(void) PDMR3CritSectLeaveAll(PVM pVM)
653{
654 RTNATIVETHREAD const hNativeSelf = RTThreadNativeSelf();
655 PUVM pUVM = pVM->pUVM;
656
657 RTCritSectEnter(&pUVM->pdm.s.ListCritSect);
658 for (PPDMCRITSECTINT pCur = pUVM->pdm.s.pCritSects;
659 pCur;
660 pCur = pCur->pNext)
661 {
662 while ( pCur->Core.NativeThreadOwner == hNativeSelf
663 && pCur->Core.cNestings > 0)
664 PDMCritSectLeave((PPDMCRITSECT)pCur);
665 }
666 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
667}
668
669
670/**
671 * Gets the address of the NOP critical section.
672 *
673 * The NOP critical section will not perform any thread serialization but let
674 * all enter immediately and concurrently.
675 *
676 * @returns The address of the NOP critical section.
677 * @param pVM The VM handle.
678 */
679VMMR3DECL(PPDMCRITSECT) PDMR3CritSectGetNop(PVM pVM)
680{
681 VM_ASSERT_VALID_EXT_RETURN(pVM, NULL);
682 return &pVM->pdm.s.NopCritSect;
683}
684
685
686/**
687 * Gets the ring-0 address of the NOP critical section.
688 *
689 * @returns The ring-0 address of the NOP critical section.
690 * @param pVM The VM handle.
691 */
692VMMR3DECL(R0PTRTYPE(PPDMCRITSECT)) PDMR3CritSectGetNopR0(PVM pVM)
693{
694 VM_ASSERT_VALID_EXT_RETURN(pVM, NIL_RTR0PTR);
695 return MMHyperR3ToR0(pVM, &pVM->pdm.s.NopCritSect);
696}
697
698
699/**
700 * Gets the raw-mode context address of the NOP critical section.
701 *
702 * @returns The raw-mode context address of the NOP critical section.
703 * @param pVM The VM handle.
704 */
705VMMR3DECL(RCPTRTYPE(PPDMCRITSECT)) PDMR3CritSectGetNopRC(PVM pVM)
706{
707 VM_ASSERT_VALID_EXT_RETURN(pVM, NIL_RTRCPTR);
708 return MMHyperR3ToRC(pVM, &pVM->pdm.s.NopCritSect);
709}
710
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