VirtualBox

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

Last change on this file since 15653 was 14657, checked in by vboxsync, 16 years ago

pgmR3CritSectInitOne: pVMR0 was pointing to pVMR3.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 11.0 KB
Line 
1/* $Id: PDMCritSect.cpp 14657 2008-11-26 18:08:15Z vboxsync $ */
2/** @file
3 * PDM - Critical Sections, Ring-3.
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#include <iprt/thread.h>
37
38
39/*******************************************************************************
40* Internal Functions *
41*******************************************************************************/
42static int pdmR3CritSectDeleteOne(PVM pVM, PPDMCRITSECTINT pCritSect, PPDMCRITSECTINT pPrev, bool fFinal);
43
44
45
46/**
47 * Initializes the critical section subcomponent.
48 *
49 * @returns VBox status code.
50 * @param pVM The VM handle.
51 * @remark Not to be confused with PDMR3CritSectInit and pdmR3CritSectInitDevice which are
52 * for initializing a critical section.
53 */
54int pdmR3CritSectInit(PVM pVM)
55{
56 STAM_REG(pVM, &pVM->pdm.s.StatQueuedCritSectLeaves, STAMTYPE_COUNTER, "/PDM/QueuedCritSectLeaves", STAMUNIT_OCCURENCES,
57 "Number of times a critical section leave requesed needed to be queued for ring-3 execution.");
58 return VINF_SUCCESS;
59}
60
61
62/**
63 * Relocates all the critical sections.
64 *
65 * @param pVM The VM handle.
66 */
67void pdmR3CritSectRelocate(PVM pVM)
68{
69 for (PPDMCRITSECTINT pCur = pVM->pdm.s.pCritSects;
70 pCur;
71 pCur = pCur->pNext)
72 pCur->pVMRC = pVM->pVMRC;
73}
74
75
76/**
77 * Deletes all remaining critical sections.
78 *
79 * This is called at the end of the termination process.
80 *
81 * @returns VBox status.
82 * First error code, rest is lost.
83 * @param pVM The VM handle.
84 * @remark Don't confuse this with PDMR3CritSectDelete.
85 */
86VMMDECL(int) PDMR3CritSectTerm(PVM pVM)
87{
88 int rc = VINF_SUCCESS;
89 while (pVM->pdm.s.pCritSects)
90 {
91 int rc2 = pdmR3CritSectDeleteOne(pVM, pVM->pdm.s.pCritSects, NULL, true /* final */);
92 AssertRC(rc2);
93 if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
94 rc = rc2;
95 }
96 return rc;
97}
98
99
100
101/**
102 * Initalizes a critical section and inserts it into the list.
103 *
104 * @returns VBox status code.
105 * @param pVM The Vm handle.
106 * @param pCritSect The critical section.
107 * @param pvKey The owner key.
108 * @param pszName The name of the critical section (for statistics).
109 */
110static int pdmR3CritSectInitOne(PVM pVM, PPDMCRITSECTINT pCritSect, void *pvKey, const char *pszName)
111{
112 VM_ASSERT_EMT(pVM);
113 int rc = RTCritSectInit(&pCritSect->Core);
114 if (RT_SUCCESS(rc))
115 {
116 pCritSect->pVMR3 = pVM;
117 pCritSect->pVMR0 = pVM->pVMR0;
118 pCritSect->pVMRC = pVM->pVMRC;
119 pCritSect->pvKey = pvKey;
120 pCritSect->EventToSignal = NIL_RTSEMEVENT;
121 pCritSect->pNext = pVM->pdm.s.pCritSects;
122 pVM->pdm.s.pCritSects = pCritSect;
123#ifdef VBOX_WITH_STATISTICS
124 STAMR3RegisterF(pVM, &pCritSect->StatContentionRZLock, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, NULL, "/PDM/CritSects/%s/ContentionRZLock", pszName);
125 STAMR3RegisterF(pVM, &pCritSect->StatContentionRZUnlock,STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, NULL, "/PDM/CritSects/%s/ContentionRZUnlock", pszName);
126 STAMR3RegisterF(pVM, &pCritSect->StatContentionR3, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, NULL, "/PDM/CritSects/%s/ContentionR3", pszName);
127 STAMR3RegisterF(pVM, &pCritSect->StatLocked, STAMTYPE_PROFILE_ADV, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_OCCURENCE, NULL, "/PDM/CritSects/%s/Locked", pszName);
128#endif
129 }
130 return rc;
131}
132
133
134/**
135 * Initializes a PDM critical section for internal use.
136 *
137 * The PDM critical sections are derived from the IPRT critical sections, but
138 * works in GC as well.
139 *
140 * @returns VBox status code.
141 * @param pVM The VM handle.
142 * @param pDevIns Device instance.
143 * @param pCritSect Pointer to the critical section.
144 * @param pszName The name of the critical section (for statistics).
145 */
146VMMR3DECL(int) PDMR3CritSectInit(PVM pVM, PPDMCRITSECT pCritSect, const char *pszName)
147{
148#if HC_ARCH_BITS == 64 && GC_ARCH_BITS == 32
149 AssertCompile(sizeof(pCritSect->padding) >= sizeof(pCritSect->s));
150#endif
151 return pdmR3CritSectInitOne(pVM, &pCritSect->s, pCritSect, pszName);
152}
153
154
155/**
156 * Initializes a PDM critical section.
157 *
158 * The PDM critical sections are derived from the IPRT critical sections, but
159 * works in GC as well.
160 *
161 * @returns VBox status code.
162 * @param pVM The VM handle.
163 * @param pDevIns Device instance.
164 * @param pCritSect Pointer to the critical section.
165 * @param pszName The name of the critical section (for statistics).
166 */
167int pdmR3CritSectInitDevice(PVM pVM, PPDMDEVINS pDevIns, PPDMCRITSECT pCritSect, const char *pszName)
168{
169 return pdmR3CritSectInitOne(pVM, &pCritSect->s, pDevIns, pszName);
170}
171
172
173/**
174 * Deletes one critical section.
175 *
176 * @returns Return code from RTCritSectDelete.
177 * @param pVM The VM handle.
178 * @param pCritSect The critical section.
179 * @param pPrev The previous critical section in the list.
180 * @param fFinal Set if this is the final call and statistics shouldn't be deregistered.
181 */
182static int pdmR3CritSectDeleteOne(PVM pVM, PPDMCRITSECTINT pCritSect, PPDMCRITSECTINT pPrev, bool fFinal)
183{
184 /* ulink */
185 if (pPrev)
186 pPrev->pNext = pCritSect->pNext;
187 else
188 pVM->pdm.s.pCritSects = pCritSect->pNext;
189
190 /* delete */
191 pCritSect->pNext = NULL;
192 pCritSect->pvKey = NULL;
193 pCritSect->pVMR3 = NULL;
194 pCritSect->pVMR0 = NIL_RTR0PTR;
195 pCritSect->pVMRC = NIL_RTRCPTR;
196#ifdef VBOX_WITH_STATISTICS
197 if (!fFinal)
198 {
199 STAMR3Deregister(pVM, &pCritSect->StatContentionRZLock);
200 STAMR3Deregister(pVM, &pCritSect->StatContentionRZUnlock);
201 STAMR3Deregister(pVM, &pCritSect->StatContentionR3);
202 STAMR3Deregister(pVM, &pCritSect->StatLocked);
203 }
204#endif
205 return RTCritSectDelete(&pCritSect->Core);
206}
207
208
209/**
210 * Deletes all critical sections with a give initializer key.
211 *
212 * @returns VBox status code.
213 * The entire list is processed on failure, so we'll only
214 * return the first error code. This shouldn't be a problem
215 * since errors really shouldn't happen here.
216 * @param pVM The VM handle.
217 * @param pvKey The initializer key.
218 */
219static int pdmR3CritSectDeleteByKey(PVM pVM, void *pvKey)
220{
221 /*
222 * Iterate the list and match key.
223 */
224 int rc = VINF_SUCCESS;
225 PPDMCRITSECTINT pPrev = NULL;
226 PPDMCRITSECTINT pCur = pVM->pdm.s.pCritSects;
227 while (pCur)
228 {
229 if (pCur->pvKey == pvKey)
230 {
231 int rc2 = pdmR3CritSectDeleteOne(pVM, pCur, pPrev, false /* not final */);
232 AssertRC(rc2);
233 if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
234 rc = rc2;
235 }
236
237 /* next */
238 pPrev = pCur;
239 pCur = pCur->pNext;
240 }
241 return rc;
242}
243
244
245/**
246 * Deletes all undeleted critical sections initalized by a given device.
247 *
248 * @returns VBox status code.
249 * @param pVM The VM handle.
250 * @param pDevIns The device handle.
251 */
252int pdmR3CritSectDeleteDevice(PVM pVM, PPDMDEVINS pDevIns)
253{
254 return pdmR3CritSectDeleteByKey(pVM, pDevIns);
255}
256
257
258/**
259 * Deletes the critical section.
260 *
261 * @returns VBox status code.
262 * @param pCritSect The PDM critical section to destroy.
263 */
264VMMR3DECL(int) PDMR3CritSectDelete(PPDMCRITSECT pCritSect)
265{
266 if (!RTCritSectIsInitialized(&pCritSect->s.Core))
267 return VINF_SUCCESS;
268
269 /*
270 * Find and unlink it.
271 */
272 PVM pVM = pCritSect->s.pVMR3;
273 AssertReleaseReturn(pVM, VERR_INTERNAL_ERROR);
274 PPDMCRITSECTINT pPrev = NULL;
275 PPDMCRITSECTINT pCur = pVM->pdm.s.pCritSects;
276 while (pCur)
277 {
278 if (pCur == &pCritSect->s)
279 return pdmR3CritSectDeleteOne(pVM, pCur, pPrev, false /* not final */);
280
281 /* next */
282 pPrev = pCur;
283 pCur = pCur->pNext;
284 }
285 AssertReleaseMsgFailed(("pCritSect=%p wasn't found!\n", pCritSect));
286 return VERR_INTERNAL_ERROR;
287}
288
289
290/**
291 * Process the critical sections queued for ring-3 'leave'.
292 *
293 * @param pVM The VM handle.
294 */
295VMMR3DECL(void) PDMR3CritSectFF(PVM pVM)
296{
297 Assert(pVM->pdm.s.cQueuedCritSectLeaves > 0);
298
299 const RTUINT c = pVM->pdm.s.cQueuedCritSectLeaves;
300 for (RTUINT i = 0; i < c; i++)
301 {
302 PPDMCRITSECT pCritSect = pVM->pdm.s.apQueuedCritSectsLeaves[i];
303 int rc = RTCritSectLeave(&pCritSect->s.Core);
304 LogFlow(("PDMR3CritSectFF: %p - %Rrc\n", pCritSect, rc));
305 AssertRC(rc);
306 }
307
308 pVM->pdm.s.cQueuedCritSectLeaves = 0;
309 VM_FF_CLEAR(pVM, VM_FF_PDM_CRITSECT);
310}
311
312
313/**
314 * Try enter a critical section.
315 *
316 * @returns VINF_SUCCESS on success.
317 * @returns VERR_SEM_BUSY if the critsect was owned.
318 * @returns VERR_SEM_NESTED if nested enter on a no nesting section. (Asserted.)
319 * @returns VERR_SEM_DESTROYED if RTCritSectDelete was called while waiting.
320 * @param pCritSect The critical section.
321 */
322VMMR3DECL(int) PDMR3CritSectTryEnter(PPDMCRITSECT pCritSect)
323{
324 return RTCritSectTryEnter(&pCritSect->s.Core);
325}
326
327
328/**
329 * Schedule a event semaphore for signalling upon critsect exit.
330 *
331 * @returns VINF_SUCCESS on success.
332 * @returns VERR_TOO_MANY_SEMAPHORES if an event was already scheduled.
333 * @returns VERR_NOT_OWNER if we're not the critsect owner.
334 * @returns VERR_SEM_DESTROYED if RTCritSectDelete was called while waiting.
335 * @param pCritSect The critical section.
336 * @param EventToSignal The semapore that should be signalled.
337 */
338VMMR3DECL(int) PDMR3CritSectScheduleExitEvent(PPDMCRITSECT pCritSect, RTSEMEVENT EventToSignal)
339{
340 Assert(EventToSignal != NIL_RTSEMEVENT);
341 if (RT_UNLIKELY(!RTCritSectIsOwner(&pCritSect->s.Core)))
342 return VERR_NOT_OWNER;
343 if (RT_LIKELY( pCritSect->s.EventToSignal == NIL_RTSEMEVENT
344 || pCritSect->s.EventToSignal == EventToSignal))
345 {
346 pCritSect->s.EventToSignal = EventToSignal;
347 return VINF_SUCCESS;
348 }
349 return VERR_TOO_MANY_SEMAPHORES;
350}
351
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