VirtualBox

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

Last change on this file since 9776 was 9154, checked in by vboxsync, 16 years ago

Corrected code that doesn't compile with GC_ARCH_BITS=64.

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