VirtualBox

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

Last change on this file since 42640 was 41965, checked in by vboxsync, 13 years ago

VMM: ran scm. Mostly svn:keywords changes (adding Revision).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 23.1 KB
Line 
1/* $Id: PDMCritSect.cpp 41965 2012-06-29 02:52:49Z 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 Pointer to the VM.
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 Pointer to the VM.
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 Pointer to the VM.
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 Pointer to the VM.
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 Pointer to the VM.
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 Pointer to the VM.
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 Pointer to the VM.
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 Pointer to the VM.
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 Pointer to the VM.
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 Pointer to the VM.
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 Pointer to the VM.
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_PDM_CRITSECT_IPE);
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_PDM_CRITSECT_NOT_FOUND;
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_IGNORED,
521 SrcPos.uId, SrcPos.pszFile, SrcPos.uLine, SrcPos.pszFunction);
522#else
523 int rc = PDMCritSectEnter(pCritSect, VERR_IGNORED);
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 Pointer to the VM.
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 Pointer to the VM.
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 Pointer to the VM.
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 Pointer to the VM.
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 Pointer to the VM.
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