VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMAll/PDMAllCritSect.cpp@ 28112

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

VMM: more RC/GC warnings - CSAMDoesPageNeedScanning and CSAMMarkPage now takes RTRCUINTPTR instead of RTRCPTR to ease the pain using them in RC.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 22.3 KB
Line 
1/* $Id: PDMAllCritSect.cpp 26277 2010-02-05 04:44:42Z vboxsync $ */
2/** @file
3 * PDM - Critical Sections, All Contexts.
4 */
5
6/*
7 * Copyright (C) 2006-2007 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/vmm.h>
31#include <VBox/vm.h>
32#include <VBox/err.h>
33#include <VBox/hwaccm.h>
34
35#include <VBox/log.h>
36#include <iprt/asm.h>
37#include <iprt/assert.h>
38#ifdef IN_RING3
39# include <iprt/lockvalidator.h>
40# include <iprt/semaphore.h>
41#endif
42
43
44/*******************************************************************************
45* Defined Constants And Macros *
46*******************************************************************************/
47/** The number loops to spin for in ring-3. */
48#define PDMCRITSECT_SPIN_COUNT_R3 20
49/** The number loops to spin for in ring-0. */
50#define PDMCRITSECT_SPIN_COUNT_R0 256
51/** The number loops to spin for in the raw-mode context. */
52#define PDMCRITSECT_SPIN_COUNT_RC 256
53
54
55/* Undefine the automatic VBOX_STRICT API mappings. */
56#undef PDMCritSectEnter
57#undef PDMCritSectTryEnter
58
59
60/**
61 * Gets the ring-3 native thread handle of the calling thread.
62 *
63 * @returns native thread handle (ring-3).
64 * @param pCritSect The critical section. This is used in R0 and RC.
65 */
66DECL_FORCE_INLINE(RTNATIVETHREAD) pdmCritSectGetNativeSelf(PCPDMCRITSECT pCritSect)
67{
68#ifdef IN_RING3
69 NOREF(pCritSect);
70 RTNATIVETHREAD hNativeSelf = RTThreadNativeSelf();
71#else
72 AssertMsgReturn(pCritSect->s.Core.u32Magic == RTCRITSECT_MAGIC, ("%RX32\n", pCritSect->s.Core.u32Magic),
73 NIL_RTNATIVETHREAD);
74 PVM pVM = pCritSect->s.CTX_SUFF(pVM); AssertPtr(pVM);
75 PVMCPU pVCpu = VMMGetCpu(pVM); AssertPtr(pVCpu);
76 RTNATIVETHREAD hNativeSelf = pVCpu->hNativeThread; Assert(hNativeSelf != NIL_RTNATIVETHREAD);
77#endif
78 return hNativeSelf;
79}
80
81
82/**
83 * Tail code called when we've wont the battle for the lock.
84 *
85 * @returns VINF_SUCCESS.
86 *
87 * @param pCritSect The critical section.
88 * @param hNativeSelf The native handle of this thread.
89 */
90DECL_FORCE_INLINE(int) pdmCritSectEnterFirst(PPDMCRITSECT pCritSect, RTNATIVETHREAD hNativeSelf, PCRTLOCKVALSRCPOS pSrcPos)
91{
92 AssertMsg(pCritSect->s.Core.NativeThreadOwner == NIL_RTNATIVETHREAD, ("NativeThreadOwner=%p\n", pCritSect->s.Core.NativeThreadOwner));
93 Assert(!(pCritSect->s.Core.fFlags & PDMCRITSECT_FLAGS_PENDING_UNLOCK));
94
95 ASMAtomicWriteS32(&pCritSect->s.Core.cNestings, 1);
96 ASMAtomicWriteHandle(&pCritSect->s.Core.NativeThreadOwner, hNativeSelf);
97
98# ifdef PDMCRITSECT_STRICT
99 RTLockValidatorRecExclSetOwner(pCritSect->s.Core.pValidatorRec, NIL_RTTHREAD, pSrcPos, true);
100# endif
101
102 STAM_PROFILE_ADV_START(&pCritSect->s.StatLocked, l);
103 return VINF_SUCCESS;
104}
105
106
107#ifdef IN_RING3
108/**
109 * Deals with the contended case in ring-3.
110 *
111 * @returns VINF_SUCCESS or VERR_SEM_DESTROYED.
112 * @param pCritSect The critsect.
113 * @param hNativeSelf The native thread handle.
114 */
115static int pdmR3CritSectEnterContended(PPDMCRITSECT pCritSect, RTNATIVETHREAD hNativeSelf, PCRTLOCKVALSRCPOS pSrcPos)
116{
117 /*
118 * Start waiting.
119 */
120 if (ASMAtomicIncS32(&pCritSect->s.Core.cLockers) == 0)
121 return pdmCritSectEnterFirst(pCritSect, hNativeSelf, pSrcPos);
122 STAM_COUNTER_INC(&pCritSect->s.StatContentionR3);
123
124 /*
125 * The wait loop.
126 */
127 PSUPDRVSESSION pSession = pCritSect->s.CTX_SUFF(pVM)->pSession;
128 SUPSEMEVENT hEvent = (SUPSEMEVENT)pCritSect->s.Core.EventSem;
129# ifdef PDMCRITSECT_STRICT
130 RTTHREAD hThreadSelf = RTThreadSelfAutoAdopt();
131 int rc2 = RTLockValidatorRecExclCheckOrder(pCritSect->s.Core.pValidatorRec, hThreadSelf, pSrcPos, RT_INDEFINITE_WAIT);
132 if (RT_FAILURE(rc2))
133 return rc2;
134# else
135 RTTHREAD hThreadSelf = RTThreadSelf();
136# endif
137 for (;;)
138 {
139# ifdef PDMCRITSECT_STRICT
140 int rc9 = RTLockValidatorRecExclCheckBlocking(pCritSect->s.Core.pValidatorRec, hThreadSelf, pSrcPos,
141 !(pCritSect->s.Core.fFlags & RTCRITSECT_FLAGS_NO_NESTING),
142 RT_INDEFINITE_WAIT, RTTHREADSTATE_CRITSECT, true);
143 if (RT_FAILURE(rc9))
144 return rc9;
145# else
146 RTThreadBlocking(hThreadSelf, RTTHREADSTATE_CRITSECT, true);
147# endif
148 int rc = SUPSemEventWaitNoResume(pSession, hEvent, RT_INDEFINITE_WAIT);
149 RTThreadUnblocked(hThreadSelf, RTTHREADSTATE_CRITSECT);
150
151 if (RT_UNLIKELY(pCritSect->s.Core.u32Magic != RTCRITSECT_MAGIC))
152 return VERR_SEM_DESTROYED;
153 if (rc == VINF_SUCCESS)
154 return pdmCritSectEnterFirst(pCritSect, hNativeSelf, pSrcPos);
155 AssertMsg(rc == VERR_INTERRUPTED, ("rc=%Rrc\n", rc));
156 }
157 /* won't get here */
158}
159#endif /* IN_RING3 */
160
161
162/**
163 * Common worker for the debug and normal APIs.
164 *
165 * @returns VINF_SUCCESS if entered successfully.
166 * @returns rcBusy when encountering a busy critical section in GC/R0.
167 * @returns VERR_SEM_DESTROYED if the critical section is dead.
168 *
169 * @param pCritSect The PDM critical section to enter.
170 * @param rcBusy The status code to return when we're in GC or R0
171 * and the section is busy.
172 */
173DECL_FORCE_INLINE(int) pdmCritSectEnter(PPDMCRITSECT pCritSect, int rcBusy, PCRTLOCKVALSRCPOS pSrcPos)
174{
175 Assert(pCritSect->s.Core.cNestings < 8); /* useful to catch incorrect locking */
176
177 /*
178 * If the critical section has already been destroyed, then inform the caller.
179 */
180 AssertMsgReturn(pCritSect->s.Core.u32Magic == RTCRITSECT_MAGIC,
181 ("%p %RX32\n", pCritSect, pCritSect->s.Core.u32Magic),
182 VERR_SEM_DESTROYED);
183
184 /*
185 * See if we're lucky.
186 */
187 RTNATIVETHREAD hNativeSelf = pdmCritSectGetNativeSelf(pCritSect);
188 /* Not owned ... */
189 if (ASMAtomicCmpXchgS32(&pCritSect->s.Core.cLockers, 0, -1))
190 return pdmCritSectEnterFirst(pCritSect, hNativeSelf, pSrcPos);
191
192 /* ... or nested. */
193 if (pCritSect->s.Core.NativeThreadOwner == hNativeSelf)
194 {
195 ASMAtomicIncS32(&pCritSect->s.Core.cLockers);
196 ASMAtomicIncS32(&pCritSect->s.Core.cNestings);
197 ASMAtomicAndU32(&pCritSect->s.Core.fFlags, ~PDMCRITSECT_FLAGS_PENDING_UNLOCK);
198 return VINF_SUCCESS;
199 }
200
201 /*
202 * Spin for a bit without incrementing the counter.
203 */
204 /** @todo Move this to cfgm variables since it doesn't make sense to spin on UNI
205 * cpu systems. */
206 int32_t cSpinsLeft = CTX_SUFF(PDMCRITSECT_SPIN_COUNT_);
207 while (cSpinsLeft-- > 0)
208 {
209 if (ASMAtomicCmpXchgS32(&pCritSect->s.Core.cLockers, 0, -1))
210 return pdmCritSectEnterFirst(pCritSect, hNativeSelf, pSrcPos);
211 ASMNopPause();
212 /** @todo Should use monitor/mwait on e.g. &cLockers here, possibly with a
213 cli'ed pendingpreemption check up front using sti w/ instruction fusing
214 for avoiding races. Hmm ... This is assuming the other party is actually
215 executing code on another CPU ... which we could keep track of if we
216 wanted. */
217 }
218
219#ifdef IN_RING3
220 /*
221 * Take the slow path.
222 */
223 return pdmR3CritSectEnterContended(pCritSect, hNativeSelf, pSrcPos);
224#else
225 /*
226 * Return busy.
227 */
228 STAM_REL_COUNTER_INC(&pCritSect->s.StatContentionRZLock);
229 LogFlow(("PDMCritSectEnter: locked => R3 (%Rrc)\n", rcBusy));
230 return rcBusy;
231#endif
232}
233
234
235/**
236 * Enters a PDM critical section.
237 *
238 * @returns VINF_SUCCESS if entered successfully.
239 * @returns rcBusy when encountering a busy critical section in GC/R0.
240 * @returns VERR_SEM_DESTROYED if the critical section is dead.
241 *
242 * @param pCritSect The PDM critical section to enter.
243 * @param rcBusy The status code to return when we're in GC or R0
244 * and the section is busy.
245 */
246VMMDECL(int) PDMCritSectEnter(PPDMCRITSECT pCritSect, int rcBusy)
247{
248#ifndef PDMCRITSECT_STRICT
249 return pdmCritSectEnter(pCritSect, rcBusy, NULL);
250#else
251 RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_NORMAL_API();
252 return pdmCritSectEnter(pCritSect, rcBusy, &SrcPos);
253#endif
254}
255
256
257/**
258 * Enters a PDM critical section, with location information for debugging.
259 *
260 * @returns VINF_SUCCESS if entered successfully.
261 * @returns rcBusy when encountering a busy critical section in GC/R0.
262 * @returns VERR_SEM_DESTROYED if the critical section is dead.
263 *
264 * @param pCritSect The PDM critical section to enter.
265 * @param rcBusy The status code to return when we're in GC or R0
266 * and the section is busy.
267 * @param uId Some kind of locking location ID. Typically a
268 * return address up the stack. Optional (0).
269 * @param pszFile The file where the lock is being acquired from.
270 * Optional.
271 * @param iLine The line number in that file. Optional (0).
272 * @param pszFunction The functionn where the lock is being acquired
273 * from. Optional.
274 */
275VMMDECL(int) PDMCritSectEnterDebug(PPDMCRITSECT pCritSect, int rcBusy, RTHCUINTPTR uId, RT_SRC_POS_DECL)
276{
277#ifdef PDMCRITSECT_STRICT
278 RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_DEBUG_API();
279 return pdmCritSectEnter(pCritSect, rcBusy, &SrcPos);
280#else
281 return pdmCritSectEnter(pCritSect, rcBusy, NULL);
282#endif
283}
284
285
286/**
287 * Common worker for the debug and normal APIs.
288 *
289 * @retval VINF_SUCCESS on success.
290 * @retval VERR_SEM_BUSY if the critsect was owned.
291 * @retval VERR_SEM_NESTED if nested enter on a no nesting section. (Asserted.)
292 * @retval VERR_SEM_DESTROYED if RTCritSectDelete was called while waiting.
293 *
294 * @param pCritSect The critical section.
295 */
296static int pdmCritSectTryEnter(PPDMCRITSECT pCritSect, PCRTLOCKVALSRCPOS pSrcPos)
297{
298 /*
299 * If the critical section has already been destroyed, then inform the caller.
300 */
301 AssertMsgReturn(pCritSect->s.Core.u32Magic == RTCRITSECT_MAGIC,
302 ("%p %RX32\n", pCritSect, pCritSect->s.Core.u32Magic),
303 VERR_SEM_DESTROYED);
304
305 /*
306 * See if we're lucky.
307 */
308 RTNATIVETHREAD hNativeSelf = pdmCritSectGetNativeSelf(pCritSect);
309 /* Not owned ... */
310 if (ASMAtomicCmpXchgS32(&pCritSect->s.Core.cLockers, 0, -1))
311 return pdmCritSectEnterFirst(pCritSect, hNativeSelf, pSrcPos);
312
313 /* ... or nested. */
314 if (pCritSect->s.Core.NativeThreadOwner == hNativeSelf)
315 {
316 ASMAtomicIncS32(&pCritSect->s.Core.cLockers);
317 ASMAtomicIncS32(&pCritSect->s.Core.cNestings);
318 ASMAtomicAndU32(&pCritSect->s.Core.fFlags, ~PDMCRITSECT_FLAGS_PENDING_UNLOCK);
319 return VINF_SUCCESS;
320 }
321
322 /* no spinning */
323
324 /*
325 * Return busy.
326 */
327#ifdef IN_RING3
328 STAM_REL_COUNTER_INC(&pCritSect->s.StatContentionR3);
329#else
330 STAM_REL_COUNTER_INC(&pCritSect->s.StatContentionRZLock);
331#endif
332 LogFlow(("PDMCritSectTryEnter: locked\n"));
333 return VERR_SEM_BUSY;
334}
335
336
337/**
338 * Try enter a critical section.
339 *
340 * @retval VINF_SUCCESS on success.
341 * @retval VERR_SEM_BUSY if the critsect was owned.
342 * @retval VERR_SEM_NESTED if nested enter on a no nesting section. (Asserted.)
343 * @retval VERR_SEM_DESTROYED if RTCritSectDelete was called while waiting.
344 *
345 * @param pCritSect The critical section.
346 */
347VMMDECL(int) PDMCritSectTryEnter(PPDMCRITSECT pCritSect)
348{
349#ifndef PDMCRITSECT_STRICT
350 return pdmCritSectTryEnter(pCritSect, NULL);
351#else
352 RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_NORMAL_API();
353 return pdmCritSectTryEnter(pCritSect, &SrcPos);
354#endif
355}
356
357
358/**
359 * Try enter a critical section, with location information for debugging.
360 *
361 * @retval VINF_SUCCESS on success.
362 * @retval VERR_SEM_BUSY if the critsect was owned.
363 * @retval VERR_SEM_NESTED if nested enter on a no nesting section. (Asserted.)
364 * @retval VERR_SEM_DESTROYED if RTCritSectDelete was called while waiting.
365 *
366 * @param pCritSect The critical section.
367 * @param uId Some kind of locking location ID. Typically a
368 * return address up the stack. Optional (0).
369 * @param pszFile The file where the lock is being acquired from.
370 * Optional.
371 * @param iLine The line number in that file. Optional (0).
372 * @param pszFunction The functionn where the lock is being acquired
373 * from. Optional.
374 */
375VMMDECL(int) PDMCritSectTryEnterDebug(PPDMCRITSECT pCritSect, RTHCUINTPTR uId, RT_SRC_POS_DECL)
376{
377#ifdef PDMCRITSECT_STRICT
378 RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_DEBUG_API();
379 return pdmCritSectTryEnter(pCritSect, &SrcPos);
380#else
381 return pdmCritSectTryEnter(pCritSect, NULL);
382#endif
383}
384
385
386#ifdef IN_RING3
387/**
388 * Enters a PDM critical section.
389 *
390 * @returns VINF_SUCCESS if entered successfully.
391 * @returns rcBusy when encountering a busy critical section in GC/R0.
392 * @returns VERR_SEM_DESTROYED if the critical section is dead.
393 *
394 * @param pCritSect The PDM critical section to enter.
395 * @param fCallRing3 Whether this is a VMMRZCallRing3()request.
396 */
397VMMR3DECL(int) PDMR3CritSectEnterEx(PPDMCRITSECT pCritSect, bool fCallRing3)
398{
399 int rc = PDMCritSectEnter(pCritSect, VERR_INTERNAL_ERROR);
400 if ( rc == VINF_SUCCESS
401 && fCallRing3
402 && pCritSect->s.Core.pValidatorRec
403 && pCritSect->s.Core.pValidatorRec->hThread != NIL_RTTHREAD)
404 RTLockValidatorRecExclReleaseOwnerUnchecked(pCritSect->s.Core.pValidatorRec);
405 return rc;
406}
407#endif /* IN_RING3 */
408
409
410/**
411 * Leaves a critical section entered with PDMCritSectEnter().
412 *
413 * @param pCritSect The PDM critical section to leave.
414 */
415VMMDECL(void) PDMCritSectLeave(PPDMCRITSECT pCritSect)
416{
417 AssertMsg(pCritSect->s.Core.u32Magic == RTCRITSECT_MAGIC, ("%p %RX32\n", pCritSect, pCritSect->s.Core.u32Magic));
418 Assert(pCritSect->s.Core.u32Magic == RTCRITSECT_MAGIC);
419 Assert(pCritSect->s.Core.NativeThreadOwner == pdmCritSectGetNativeSelf(pCritSect));
420 Assert(pCritSect->s.Core.cNestings >= 1);
421
422 /*
423 * Nested leave.
424 */
425 if (pCritSect->s.Core.cNestings > 1)
426 {
427 ASMAtomicDecS32(&pCritSect->s.Core.cNestings);
428 ASMAtomicDecS32(&pCritSect->s.Core.cLockers);
429 return;
430 }
431
432#ifdef IN_RING0
433# if 0 /** @todo Make SUPSemEventSignal interrupt safe (handle table++) and enable this for: defined(RT_OS_LINUX) || defined(RT_OS_OS2) */
434 if (1) /* SUPSemEventSignal is safe */
435# else
436 if (ASMIntAreEnabled())
437# endif
438#endif
439#if defined(IN_RING3) || defined(IN_RING0)
440 {
441 /*
442 * Leave for real.
443 */
444 /* update members. */
445# ifdef IN_RING3
446 RTSEMEVENT hEventToSignal = pCritSect->s.EventToSignal;
447 pCritSect->s.EventToSignal = NIL_RTSEMEVENT;
448# if defined(PDMCRITSECT_STRICT)
449 if (pCritSect->s.Core.pValidatorRec->hThread != NIL_RTTHREAD)
450 RTLockValidatorRecExclReleaseOwnerUnchecked(pCritSect->s.Core.pValidatorRec);
451# endif
452 Assert(!pCritSect->s.Core.pValidatorRec || pCritSect->s.Core.pValidatorRec->hThread == NIL_RTTHREAD);
453# endif
454 ASMAtomicAndU32(&pCritSect->s.Core.fFlags, ~PDMCRITSECT_FLAGS_PENDING_UNLOCK);
455 ASMAtomicWriteHandle(&pCritSect->s.Core.NativeThreadOwner, NIL_RTNATIVETHREAD);
456 ASMAtomicDecS32(&pCritSect->s.Core.cNestings);
457
458 /* stop and decrement lockers. */
459 STAM_PROFILE_ADV_STOP(&pCritSect->s.StatLocked, l);
460 ASMCompilerBarrier();
461 if (ASMAtomicDecS32(&pCritSect->s.Core.cLockers) >= 0)
462 {
463 /* Someone is waiting, wake up one of them. */
464 SUPSEMEVENT hEvent = (SUPSEMEVENT)pCritSect->s.Core.EventSem;
465 PSUPDRVSESSION pSession = pCritSect->s.CTX_SUFF(pVM)->pSession;
466 int rc = SUPSemEventSignal(pSession, hEvent);
467 AssertRC(rc);
468 }
469
470# ifdef IN_RING3
471 /* Signal exit event. */
472 if (hEventToSignal != NIL_RTSEMEVENT)
473 {
474 LogBird(("Signalling %#x\n", hEventToSignal));
475 int rc = RTSemEventSignal(hEventToSignal);
476 AssertRC(rc);
477 }
478# endif
479
480# if defined(DEBUG_bird) && defined(IN_RING0)
481 VMMTrashVolatileXMMRegs();
482# endif
483 }
484#endif /* IN_RING3 || IN_RING0 */
485#ifdef IN_RING0
486 else
487#endif
488#if defined(IN_RING0) || defined(IN_RC)
489 {
490 /*
491 * Try leave it.
492 */
493 if (pCritSect->s.Core.cLockers == 0)
494 {
495 ASMAtomicWriteS32(&pCritSect->s.Core.cNestings, 0);
496 RTNATIVETHREAD hNativeThread = pCritSect->s.Core.NativeThreadOwner;
497 ASMAtomicAndU32(&pCritSect->s.Core.fFlags, ~PDMCRITSECT_FLAGS_PENDING_UNLOCK);
498 STAM_PROFILE_ADV_STOP(&pCritSect->s.StatLocked, l);
499
500 ASMAtomicWriteHandle(&pCritSect->s.Core.NativeThreadOwner, NIL_RTNATIVETHREAD);
501 if (ASMAtomicCmpXchgS32(&pCritSect->s.Core.cLockers, -1, 0))
502 return;
503
504 /* darn, someone raced in on us. */
505 ASMAtomicWriteHandle(&pCritSect->s.Core.NativeThreadOwner, hNativeThread);
506 STAM_PROFILE_ADV_START(&pCritSect->s.StatLocked, l);
507 ASMAtomicWriteS32(&pCritSect->s.Core.cNestings, 1);
508 }
509 ASMAtomicOrU32(&pCritSect->s.Core.fFlags, PDMCRITSECT_FLAGS_PENDING_UNLOCK);
510
511 /*
512 * Queue the request.
513 */
514 PVM pVM = pCritSect->s.CTX_SUFF(pVM); AssertPtr(pVM);
515 PVMCPU pVCpu = VMMGetCpu(pVM); AssertPtr(pVCpu);
516 uint32_t i = pVCpu->pdm.s.cQueuedCritSectLeaves++;
517 LogFlow(("PDMCritSectLeave: [%d]=%p => R3\n", i, pCritSect));
518 AssertFatal(i < RT_ELEMENTS(pVCpu->pdm.s.apQueuedCritSectsLeaves));
519 pVCpu->pdm.s.apQueuedCritSectsLeaves[i] = MMHyperCCToR3(pVM, pCritSect);
520 VMCPU_FF_SET(pVCpu, VMCPU_FF_PDM_CRITSECT);
521 VMCPU_FF_SET(pVCpu, VMCPU_FF_TO_R3);
522 STAM_REL_COUNTER_INC(&pVM->pdm.s.StatQueuedCritSectLeaves);
523 STAM_REL_COUNTER_INC(&pCritSect->s.StatContentionRZUnlock);
524 }
525#endif /* IN_RING0 || IN_RC */
526}
527
528
529#if defined(IN_RING3) || defined(IN_RING0)
530/**
531 * Process the critical sections queued for ring-3 'leave'.
532 *
533 * @param pVCpu The VMCPU handle.
534 */
535VMMDECL(void) PDMCritSectFF(PVMCPU pVCpu)
536{
537 Assert(pVCpu->pdm.s.cQueuedCritSectLeaves > 0);
538
539 const RTUINT c = pVCpu->pdm.s.cQueuedCritSectLeaves;
540 for (RTUINT i = 0; i < c; i++)
541 {
542# ifdef IN_RING3
543 PPDMCRITSECT pCritSect = pVCpu->pdm.s.apQueuedCritSectsLeaves[i];
544# else
545 PPDMCRITSECT pCritSect = (PPDMCRITSECT)MMHyperR3ToCC(pVCpu->CTX_SUFF(pVM), pVCpu->pdm.s.apQueuedCritSectsLeaves[i]);
546# endif
547
548 PDMCritSectLeave(pCritSect);
549 LogFlow(("PDMR3CritSectFF: %p\n", pCritSect));
550 }
551
552 pVCpu->pdm.s.cQueuedCritSectLeaves = 0;
553 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_PDM_CRITSECT);
554}
555#endif /* IN_RING3 || IN_RING0 */
556
557
558/**
559 * Checks the caller is the owner of the critical section.
560 *
561 * @returns true if owner.
562 * @returns false if not owner.
563 * @param pCritSect The critical section.
564 */
565VMMDECL(bool) PDMCritSectIsOwner(PCPDMCRITSECT pCritSect)
566{
567#ifdef IN_RING3
568 return RTCritSectIsOwner(&pCritSect->s.Core);
569#else
570 PVM pVM = pCritSect->s.CTX_SUFF(pVM); AssertPtr(pVM);
571 PVMCPU pVCpu = VMMGetCpu(pVM); AssertPtr(pVCpu);
572 if (pCritSect->s.Core.NativeThreadOwner != pVCpu->hNativeThread)
573 return false;
574 return (pCritSect->s.Core.fFlags & PDMCRITSECT_FLAGS_PENDING_UNLOCK) == 0;
575#endif
576}
577
578
579/**
580 * Checks the specified VCPU is the owner of the critical section.
581 *
582 * @returns true if owner.
583 * @returns false if not owner.
584 * @param pCritSect The critical section.
585 * @param idCpu VCPU id
586 */
587VMMDECL(bool) PDMCritSectIsOwnerEx(PCPDMCRITSECT pCritSect, VMCPUID idCpu)
588{
589#ifdef IN_RING3
590 NOREF(idCpu);
591 return RTCritSectIsOwner(&pCritSect->s.Core);
592#else
593 PVM pVM = pCritSect->s.CTX_SUFF(pVM);
594 AssertPtr(pVM);
595 Assert(idCpu < pVM->cCpus);
596 return pCritSect->s.Core.NativeThreadOwner == pVM->aCpus[idCpu].hNativeThread
597 && (pCritSect->s.Core.fFlags & PDMCRITSECT_FLAGS_PENDING_UNLOCK) == 0;
598#endif
599}
600
601
602/**
603 * Checks if somebody currently owns the critical section.
604 *
605 * @returns true if locked.
606 * @returns false if not locked.
607 *
608 * @param pCritSect The critical section.
609 *
610 * @remarks This doesn't prove that no deadlocks will occur later on; it's
611 * just a debugging tool
612 */
613VMMDECL(bool) PDMCritSectIsOwned(PCPDMCRITSECT pCritSect)
614{
615 return pCritSect->s.Core.NativeThreadOwner != NIL_RTNATIVETHREAD
616 && (pCritSect->s.Core.fFlags & PDMCRITSECT_FLAGS_PENDING_UNLOCK) == 0;
617}
618
619
620/**
621 * Checks if anyone is waiting on the critical section we own.
622 *
623 * @returns true if someone is waitings.
624 * @returns false if no one is waiting.
625 * @param pCritSect The critical section.
626 */
627VMMDECL(bool) PDMCritSectHasWaiters(PCPDMCRITSECT pCritSect)
628{
629 AssertReturn(pCritSect->s.Core.u32Magic == RTCRITSECT_MAGIC, false);
630 Assert(pCritSect->s.Core.NativeThreadOwner == pdmCritSectGetNativeSelf(pCritSect));
631 return pCritSect->s.Core.cLockers >= pCritSect->s.Core.cNestings;
632}
633
634
635/**
636 * Checks if a critical section is initialized or not.
637 *
638 * @returns true if initialized.
639 * @returns false if not initialized.
640 * @param pCritSect The critical section.
641 */
642VMMDECL(bool) PDMCritSectIsInitialized(PCPDMCRITSECT pCritSect)
643{
644 return RTCritSectIsInitialized(&pCritSect->s.Core);
645}
646
647
648/**
649 * Gets the recursion depth.
650 *
651 * @returns The recursion depth.
652 * @param pCritSect The critical section.
653 */
654VMMDECL(uint32_t) PDMCritSectGetRecursion(PCPDMCRITSECT pCritSect)
655{
656 return RTCritSectGetRecursion(&pCritSect->s.Core);
657}
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