VirtualBox

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

Last change on this file since 1308 was 634, checked in by vboxsync, 18 years ago

nc

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 10.0 KB
Line 
1/* $Id: PDMCritSect.cpp 634 2007-02-05 13:06:04Z vboxsync $ */
2/** @file
3 * PDM Critical Sections
4 */
5
6/*
7 * Copyright (C) 2006 InnoTek Systemberatung GmbH
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 as published by the Free Software Foundation,
13 * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
14 * distribution. VirtualBox OSE is distributed in the hope that it will
15 * be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * If you received this file as part of a commercial VirtualBox
18 * distribution, then only the terms of your commercial VirtualBox
19 * license agreement apply instead of the previous paragraph.
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->pNext = pVM->pdm.s.pCritSects;
122 pVM->pdm.s.pCritSects = pCritSect;
123#ifdef VBOX_WITH_STATISTICS
124 STAMR3RegisterF(pVM, &pCritSect->StatContentionR0GCLock, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, NULL, "/PDM/CritSects/%s/ContentionR0GCLock", pszName);
125 STAMR3RegisterF(pVM, &pCritSect->StatContentionR0GCUnlock, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, NULL, "/PDM/CritSects/%s/ContentionR0GCUnlock", 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 */
146PDMR3DECL(int) PDMR3CritSectInit(PVM pVM, PPDMCRITSECT pCritSect, const char *pszName)
147{
148 AssertCompile(sizeof(pCritSect->padding) >= sizeof(pCritSect->s));
149 return pdmR3CritSectInitOne(pVM, &pCritSect->s, pCritSect, pszName);
150}
151
152
153/**
154 * Initializes a PDM critical section.
155 *
156 * The PDM critical sections are derived from the IPRT critical sections, but
157 * works in GC as well.
158 *
159 * @returns VBox status code.
160 * @param pVM The VM handle.
161 * @param pDevIns Device instance.
162 * @param pCritSect Pointer to the critical section.
163 * @param pszName The name of the critical section (for statistics).
164 */
165int pdmR3CritSectInitDevice(PVM pVM, PPDMDEVINS pDevIns, PPDMCRITSECT pCritSect, const char *pszName)
166{
167 return pdmR3CritSectInitOne(pVM, &pCritSect->s, pDevIns, pszName);
168}
169
170
171/**
172 * Deletes one critical section.
173 *
174 * @returns Return code from RTCritSectDelete.
175 * @param pVM The VM handle.
176 * @param pCritSect The critical section.
177 * @param pPrev The previous critical section in the list.
178 * @param fFinal Set if this is the final call and statistics shouldn't be deregistered.
179 */
180static int pdmR3CritSectDeleteOne(PVM pVM, PPDMCRITSECTINT pCritSect, PPDMCRITSECTINT pPrev, bool fFinal)
181{
182 /* ulink */
183 if (pPrev)
184 pPrev->pNext = pCritSect->pNext;
185 else
186 pVM->pdm.s.pCritSects = pCritSect->pNext;
187
188 /* delete */
189 pCritSect->pNext = NULL;
190 pCritSect->pVMGC = 0;
191 pCritSect->pVMR3 = NULL;
192 pCritSect->pVMR0 = NIL_RTR0PTR;
193 pCritSect->pvKey = NULL;
194#ifdef VBOX_WITH_STATISTICS
195 if (!fFinal)
196 {
197 STAMR3Deregister(pVM, &pCritSect->StatContentionR0GCLock);
198 STAMR3Deregister(pVM, &pCritSect->StatContentionR0GCUnlock);
199 STAMR3Deregister(pVM, &pCritSect->StatContentionR3);
200 STAMR3Deregister(pVM, &pCritSect->StatLocked);
201 }
202#endif
203 return RTCritSectDelete(&pCritSect->Core);
204}
205
206
207/**
208 * Deletes all critical sections with a give initializer key.
209 *
210 * @returns VBox status code.
211 * The entire list is processed on failure, so we'll only
212 * return the first error code. This shouldn't be a problem
213 * since errors really shouldn't happen here.
214 * @param pVM The VM handle.
215 * @param pvKey The initializer key.
216 */
217static int pdmR3CritSectDeleteByKey(PVM pVM, void *pvKey)
218{
219 /*
220 * Iterate the list and match key.
221 */
222 int rc = VINF_SUCCESS;
223 PPDMCRITSECTINT pPrev = NULL;
224 PPDMCRITSECTINT pCur = pVM->pdm.s.pCritSects;
225 while (pCur)
226 {
227 if (pCur->pvKey == pvKey)
228 {
229 int rc2 = pdmR3CritSectDeleteOne(pVM, pCur, pPrev, false /* not final */);
230 AssertRC(rc2);
231 if (VBOX_FAILURE(rc2) && VBOX_SUCCESS(rc))
232 rc = rc2;
233 }
234
235 /* next */
236 pPrev = pCur;
237 pCur = pCur->pNext;
238 }
239 return rc;
240}
241
242
243/**
244 * Deletes all undeleted critical sections initalized by a given device.
245 *
246 * @returns VBox status code.
247 * @param pVM The VM handle.
248 * @param pDevIns The device handle.
249 */
250int pdmR3CritSectDeleteDevice(PVM pVM, PPDMDEVINS pDevIns)
251{
252 return pdmR3CritSectDeleteByKey(pVM, pDevIns);
253}
254
255
256/**
257 * Deletes the critical section.
258 *
259 * @returns VBox status code.
260 * @param pCritSect The PDM critical section to destroy.
261 */
262PDMR3DECL(int) PDMR3CritSectDelete(PPDMCRITSECT pCritSect)
263{
264 if (!RTCritSectIsInitialized(&pCritSect->s.Core))
265 return VINF_SUCCESS;
266
267 /*
268 * Find and unlink it.
269 */
270 PVM pVM = pCritSect->s.pVMR3;
271 AssertReleaseReturn(pVM, VERR_INTERNAL_ERROR);
272 PPDMCRITSECTINT pPrev = NULL;
273 PPDMCRITSECTINT pCur = pVM->pdm.s.pCritSects;
274 while (pCur)
275 {
276 if (pCur == &pCritSect->s)
277 return pdmR3CritSectDeleteOne(pVM, pCur, pPrev, false /* not final */);
278
279 /* next */
280 pPrev = pCur;
281 pCur = pCur->pNext;
282 }
283 AssertReleaseMsgFailed(("pCritSect=%p wasn't found!\n", pCritSect));
284 return VERR_INTERNAL_ERROR;
285}
286
287
288/**
289 * Process the critical sections queued for ring-3 'leave'.
290 *
291 * @param pVM The VM handle.
292 */
293PDMR3DECL(void) PDMR3CritSectFF(PVM pVM)
294{
295 Assert(pVM->pdm.s.cQueuedCritSectLeaves > 0);
296
297 const RTUINT c = pVM->pdm.s.cQueuedCritSectLeaves;
298 for (RTUINT i = 0; i < c; i++)
299 {
300 PPDMCRITSECT pCritSect = pVM->pdm.s.apQueuedCritSectsLeaves[i];
301 int rc = RTCritSectLeave(&pCritSect->s.Core);
302 LogFlow(("PDMR3CritSectFF: %p - %Vrc\n", pCritSect, rc));
303 AssertRC(rc);
304 }
305
306 pVM->pdm.s.cQueuedCritSectLeaves = 0;
307 VM_FF_CLEAR(pVM, VM_FF_PDM_CRITSECT);
308}
309
310
311/**
312 * Try enter a critical section.
313 *
314 * @returns VINF_SUCCESS on success.
315 * @returns VERR_SEM_BUSY if the critsect was owned.
316 * @returns VERR_SEM_NESTED if nested enter on a no nesting section. (Asserted.)
317 * @returns VERR_SEM_DESTROYED if RTCritSectDelete was called while waiting.
318 * @param pCritSect The critical section.
319 */
320PDMR3DECL(int) PDMR3CritSectTryEnter(PPDMCRITSECT pCritSect)
321{
322 return RTCritSectTryEnter(&pCritSect->s.Core);
323}
324
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