VirtualBox

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

Last change on this file since 9657 was 8677, checked in by vboxsync, 17 years ago

Fixed lock accounting for locks aquired via VMM[GC|R0]CallHost.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 7.2 KB
Line 
1/* $Id: PDMAllCritSect.cpp 8677 2008-05-07 18:13:32Z vboxsync $ */
2/** @file
3 * PDM Critical Sections
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/pdm.h>
29#include <VBox/mm.h>
30#include <VBox/vm.h>
31#include <VBox/err.h>
32
33#include <VBox/log.h>
34#include <iprt/asm.h>
35#include <iprt/assert.h>
36#ifdef IN_RING3
37# include <iprt/semaphore.h>
38#endif
39
40
41/**
42 * Enters a PDM critical section.
43 *
44 * @returns VINF_SUCCESS if entered successfully.
45 * @returns rcBusy when encountering a busy critical section in GC/R0.
46 * @returns VERR_SEM_DESTROYED if the critical section is dead.
47 *
48 * @param pCritSect The PDM critical section to enter.
49 * @param rcBusy The status code to return when we're in GC or R0
50 * and the section is busy.
51 */
52PDMDECL(int) PDMCritSectEnter(PPDMCRITSECT pCritSect, int rcBusy)
53{
54 Assert(pCritSect->s.Core.cNestings < 8); /* useful to catch incorrect locking */
55#ifdef IN_RING3
56 NOREF(rcBusy);
57
58 STAM_STATS({ if (pCritSect->s.Core.cLockers >= 0 && !RTCritSectIsOwner(&pCritSect->s.Core)) STAM_COUNTER_INC(&pCritSect->s.StatContentionR3); });
59 int rc = RTCritSectEnter(&pCritSect->s.Core);
60 STAM_STATS({ if (pCritSect->s.Core.cNestings == 1) STAM_PROFILE_ADV_START(&pCritSect->s.StatLocked, l); });
61 return rc;
62
63#else
64 AssertMsgReturn(pCritSect->s.Core.u32Magic == RTCRITSECT_MAGIC, ("%RX32\n", pCritSect->s.Core.u32Magic),
65 VERR_SEM_DESTROYED);
66 PVM pVM = pCritSect->s.CTXALLSUFF(pVM);
67 Assert(pVM);
68
69 /*
70 * Try take the lock.
71 */
72 if (ASMAtomicCmpXchgS32(&pCritSect->s.Core.cLockers, 0, -1))
73 {
74 pCritSect->s.Core.cNestings = 1;
75 ASMAtomicXchgSize(&pCritSect->s.Core.NativeThreadOwner, pVM->NativeThreadEMT);
76 STAM_PROFILE_ADV_START(&pCritSect->s.StatLocked, l);
77 return VINF_SUCCESS;
78 }
79
80 /*
81 * Nested?
82 */
83 if (pCritSect->s.Core.NativeThreadOwner == pVM->NativeThreadEMT)
84 {
85 pCritSect->s.Core.cNestings++;
86 ASMAtomicIncS32(&pCritSect->s.Core.cLockers);
87 return VINF_SUCCESS;
88 }
89
90 /*
91 * Failed.
92 */
93 LogFlow(("pcnetLock: locked => HC (%Vrc)\n", rcBusy));
94 STAM_COUNTER_INC(&pCritSect->s.StatContentionR0GCLock);
95 return rcBusy;
96#endif
97}
98
99
100#ifdef IN_RING3
101/**
102 * Enters a PDM critical section.
103 *
104 * @returns VINF_SUCCESS if entered successfully.
105 * @returns rcBusy when encountering a busy critical section in GC/R0.
106 * @returns VERR_SEM_DESTROYED if the critical section is dead.
107 *
108 * @param pCritSect The PDM critical section to enter.
109 * @param fCallHost Whether this is a VMMGCCallHost() or VMMR0CallHost() request.
110 */
111PDMR3DECL(int) PDMR3CritSectEnterEx(PPDMCRITSECT pCritSect, bool fCallHost)
112{
113 int rc = PDMCritSectEnter(pCritSect, VERR_INTERNAL_ERROR);
114 if ( rc == VINF_SUCCESS
115 && fCallHost
116 && pCritSect->s.Core.Strict.ThreadOwner != NIL_RTTHREAD)
117 {
118 RTThreadWriteLockDec(pCritSect->s.Core.Strict.ThreadOwner);
119 ASMAtomicUoWriteSize(&pCritSect->s.Core.Strict.ThreadOwner, NIL_RTTHREAD);
120 }
121 return rc;
122}
123#endif /* IN_RING3 */
124
125
126/**
127 * Leaves a critical section entered with PDMCritSectEnter().
128 *
129 * @param pCritSect The PDM critical section to leave.
130 */
131PDMDECL(void) PDMCritSectLeave(PPDMCRITSECT pCritSect)
132{
133#ifdef IN_RING3
134# ifdef VBOX_WITH_STATISTICS
135 if (pCritSect->s.Core.cNestings == 1)
136 STAM_PROFILE_ADV_STOP(&pCritSect->s.StatLocked, l);
137# endif
138 RTSEMEVENT EventToSignal = pCritSect->s.EventToSignal;
139 if (RT_LIKELY(EventToSignal == NIL_RTSEMEVENT))
140 {
141 int rc = RTCritSectLeave(&pCritSect->s.Core);
142 AssertRC(rc);
143 }
144 else
145 {
146 pCritSect->s.EventToSignal = NIL_RTSEMEVENT;
147 int rc = RTCritSectLeave(&pCritSect->s.Core);
148 AssertRC(rc);
149 LogBird(("signalling %#x\n", EventToSignal));
150 rc = RTSemEventSignal(EventToSignal);
151 AssertRC(rc);
152 }
153
154#else /* !IN_RING3 */
155 Assert(VALID_PTR(pCritSect));
156 Assert(pCritSect->s.Core.u32Magic == RTCRITSECT_MAGIC);
157 Assert(pCritSect->s.Core.cNestings > 0);
158 Assert(pCritSect->s.Core.cLockers >= 0);
159 PVM pVM = pCritSect->s.CTXALLSUFF(pVM);
160 Assert(pVM);
161 Assert(pCritSect->s.Core.NativeThreadOwner == pVM->NativeThreadEMT);
162
163 /*
164 * Deal with nested attempts first.
165 * (We're exploiting nesting to avoid queuing multiple R3 leaves for the same section.)
166 */
167 pCritSect->s.Core.cNestings--;
168 if (pCritSect->s.Core.cNestings > 0)
169 {
170 ASMAtomicDecS32(&pCritSect->s.Core.cLockers);
171 return;
172 }
173
174 /*
175 * Try leave it.
176 */
177 if (pCritSect->s.Core.cLockers == 0)
178 {
179 STAM_PROFILE_ADV_STOP(&pCritSect->s.StatLocked, l);
180 ASMAtomicXchgSize(&pCritSect->s.Core.NativeThreadOwner, NIL_RTNATIVETHREAD);
181 if (ASMAtomicCmpXchgS32(&pCritSect->s.Core.cLockers, -1, 0))
182 return;
183
184 /* darn, someone raced in on us. */
185 ASMAtomicXchgSize(&pCritSect->s.Core.NativeThreadOwner, pVM->NativeThreadEMT);
186 STAM_PROFILE_ADV_START(&pCritSect->s.StatLocked, l);
187 }
188 pCritSect->s.Core.cNestings = 1;
189
190 /*
191 * Queue the request.
192 */
193 RTUINT i = pVM->pdm.s.cQueuedCritSectLeaves++;
194 LogFlow(("PDMCritSectLeave: [%d]=%p => R3\n", i, pCritSect));
195 AssertFatal(i < RT_ELEMENTS(pVM->pdm.s.apQueuedCritSectsLeaves));
196 pVM->pdm.s.apQueuedCritSectsLeaves[i] = MMHyperCCToR3(pVM, pCritSect);
197 VM_FF_SET(pVM, VM_FF_PDM_CRITSECT);
198 VM_FF_SET(pVM, VM_FF_TO_R3);
199 STAM_COUNTER_INC(&pVM->pdm.s.StatQueuedCritSectLeaves);
200 STAM_COUNTER_INC(&pCritSect->s.StatContentionR0GCUnlock);
201#endif
202}
203
204
205/**
206 * Checks the caller is the owner of the critical section.
207 *
208 * @returns true if owner.
209 * @returns false if not owner.
210 * @param pCritSect The critical section.
211 */
212PDMDECL(bool) PDMCritSectIsOwner(PCPDMCRITSECT pCritSect)
213{
214#ifdef IN_RING3
215 return RTCritSectIsOwner(&pCritSect->s.Core);
216#else
217 PVM pVM = pCritSect->s.CTXALLSUFF(pVM);
218 Assert(pVM);
219 return pCritSect->s.Core.NativeThreadOwner == pVM->NativeThreadEMT;
220#endif
221}
222
223
224/**
225 * Checks if a critical section is initialized or not.
226 *
227 * @returns true if initialized.
228 * @returns false if not initialized.
229 * @param pCritSect The critical section.
230 */
231PDMDECL(bool) PDMCritSectIsInitialized(PCPDMCRITSECT pCritSect)
232{
233 return pCritSect->s.Core.u32Magic == RTCRITSECT_MAGIC;
234}
235
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