VirtualBox

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

Last change on this file since 28258 was 28258, checked in by vboxsync, 15 years ago

PDM critsects for drivers. Fixed critsect cleanup in failure path. Started on new transmit locking scheme (required for intnet buffer serialization).

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

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