VirtualBox

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

Last change on this file since 2870 was 2565, checked in by vboxsync, 17 years ago

A little experiment trying to get rid of the critsect contention in DevATA.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 11.0 KB
Line 
1/* $Id: PDMCritSect.cpp 2565 2007-05-09 16:28:03Z 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->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 AssertCompile(sizeof(pCritSect->padding) >= sizeof(pCritSect->s));
150 return pdmR3CritSectInitOne(pVM, &pCritSect->s, pCritSect, pszName);
151}
152
153
154/**
155 * Initializes a PDM critical section.
156 *
157 * The PDM critical sections are derived from the IPRT critical sections, but
158 * works in GC as well.
159 *
160 * @returns VBox status code.
161 * @param pVM The VM handle.
162 * @param pDevIns Device instance.
163 * @param pCritSect Pointer to the critical section.
164 * @param pszName The name of the critical section (for statistics).
165 */
166int pdmR3CritSectInitDevice(PVM pVM, PPDMDEVINS pDevIns, PPDMCRITSECT pCritSect, const char *pszName)
167{
168 return pdmR3CritSectInitOne(pVM, &pCritSect->s, pDevIns, pszName);
169}
170
171
172/**
173 * Deletes one critical section.
174 *
175 * @returns Return code from RTCritSectDelete.
176 * @param pVM The VM handle.
177 * @param pCritSect The critical section.
178 * @param pPrev The previous critical section in the list.
179 * @param fFinal Set if this is the final call and statistics shouldn't be deregistered.
180 */
181static int pdmR3CritSectDeleteOne(PVM pVM, PPDMCRITSECTINT pCritSect, PPDMCRITSECTINT pPrev, bool fFinal)
182{
183 /* ulink */
184 if (pPrev)
185 pPrev->pNext = pCritSect->pNext;
186 else
187 pVM->pdm.s.pCritSects = pCritSect->pNext;
188
189 /* delete */
190 pCritSect->pNext = NULL;
191 pCritSect->pVMGC = 0;
192 pCritSect->pVMR3 = NULL;
193 pCritSect->pVMR0 = NIL_RTR0PTR;
194 pCritSect->pvKey = NULL;
195#ifdef VBOX_WITH_STATISTICS
196 if (!fFinal)
197 {
198 STAMR3Deregister(pVM, &pCritSect->StatContentionR0GCLock);
199 STAMR3Deregister(pVM, &pCritSect->StatContentionR0GCUnlock);
200 STAMR3Deregister(pVM, &pCritSect->StatContentionR3);
201 STAMR3Deregister(pVM, &pCritSect->StatLocked);
202 }
203#endif
204 return RTCritSectDelete(&pCritSect->Core);
205}
206
207
208/**
209 * Deletes all critical sections with a give initializer key.
210 *
211 * @returns VBox status code.
212 * The entire list is processed on failure, so we'll only
213 * return the first error code. This shouldn't be a problem
214 * since errors really shouldn't happen here.
215 * @param pVM The VM handle.
216 * @param pvKey The initializer key.
217 */
218static int pdmR3CritSectDeleteByKey(PVM pVM, void *pvKey)
219{
220 /*
221 * Iterate the list and match key.
222 */
223 int rc = VINF_SUCCESS;
224 PPDMCRITSECTINT pPrev = NULL;
225 PPDMCRITSECTINT pCur = pVM->pdm.s.pCritSects;
226 while (pCur)
227 {
228 if (pCur->pvKey == pvKey)
229 {
230 int rc2 = pdmR3CritSectDeleteOne(pVM, pCur, pPrev, false /* not final */);
231 AssertRC(rc2);
232 if (VBOX_FAILURE(rc2) && VBOX_SUCCESS(rc))
233 rc = rc2;
234 }
235
236 /* next */
237 pPrev = pCur;
238 pCur = pCur->pNext;
239 }
240 return rc;
241}
242
243
244/**
245 * Deletes all undeleted critical sections initalized by a given device.
246 *
247 * @returns VBox status code.
248 * @param pVM The VM handle.
249 * @param pDevIns The device handle.
250 */
251int pdmR3CritSectDeleteDevice(PVM pVM, PPDMDEVINS pDevIns)
252{
253 return pdmR3CritSectDeleteByKey(pVM, pDevIns);
254}
255
256
257/**
258 * Deletes the critical section.
259 *
260 * @returns VBox status code.
261 * @param pCritSect The PDM critical section to destroy.
262 */
263PDMR3DECL(int) PDMR3CritSectDelete(PPDMCRITSECT pCritSect)
264{
265 if (!RTCritSectIsInitialized(&pCritSect->s.Core))
266 return VINF_SUCCESS;
267
268 /*
269 * Find and unlink it.
270 */
271 PVM pVM = pCritSect->s.pVMR3;
272 AssertReleaseReturn(pVM, VERR_INTERNAL_ERROR);
273 PPDMCRITSECTINT pPrev = NULL;
274 PPDMCRITSECTINT pCur = pVM->pdm.s.pCritSects;
275 while (pCur)
276 {
277 if (pCur == &pCritSect->s)
278 return pdmR3CritSectDeleteOne(pVM, pCur, pPrev, false /* not final */);
279
280 /* next */
281 pPrev = pCur;
282 pCur = pCur->pNext;
283 }
284 AssertReleaseMsgFailed(("pCritSect=%p wasn't found!\n", pCritSect));
285 return VERR_INTERNAL_ERROR;
286}
287
288
289/**
290 * Process the critical sections queued for ring-3 'leave'.
291 *
292 * @param pVM The VM handle.
293 */
294PDMR3DECL(void) PDMR3CritSectFF(PVM pVM)
295{
296 Assert(pVM->pdm.s.cQueuedCritSectLeaves > 0);
297
298 const RTUINT c = pVM->pdm.s.cQueuedCritSectLeaves;
299 for (RTUINT i = 0; i < c; i++)
300 {
301 PPDMCRITSECT pCritSect = pVM->pdm.s.apQueuedCritSectsLeaves[i];
302 int rc = RTCritSectLeave(&pCritSect->s.Core);
303 LogFlow(("PDMR3CritSectFF: %p - %Vrc\n", pCritSect, rc));
304 AssertRC(rc);
305 }
306
307 pVM->pdm.s.cQueuedCritSectLeaves = 0;
308 VM_FF_CLEAR(pVM, VM_FF_PDM_CRITSECT);
309}
310
311
312/**
313 * Try enter a critical section.
314 *
315 * @returns VINF_SUCCESS on success.
316 * @returns VERR_SEM_BUSY if the critsect was owned.
317 * @returns VERR_SEM_NESTED if nested enter on a no nesting section. (Asserted.)
318 * @returns VERR_SEM_DESTROYED if RTCritSectDelete was called while waiting.
319 * @param pCritSect The critical section.
320 */
321PDMR3DECL(int) PDMR3CritSectTryEnter(PPDMCRITSECT pCritSect)
322{
323 return RTCritSectTryEnter(&pCritSect->s.Core);
324}
325
326
327/**
328 * Schedule a event semaphore for signalling upon critsect exit.
329 *
330 * @returns VINF_SUCCESS on success.
331 * @returns VERR_TOO_MANY_SEMAPHORES if an event was already scheduled.
332 * @returns VERR_NOT_OWNER if we're not the critsect owner.
333 * @returns VERR_SEM_DESTROYED if RTCritSectDelete was called while waiting.
334 * @param pCritSect The critical section.
335 * @param EventToSignal The semapore that should be signalled.
336 */
337PDMR3DECL(int) PDMR3CritSectScheduleExitEvent(PPDMCRITSECT pCritSect, RTSEMEVENT EventToSignal)
338{
339 Assert(EventToSignal != NIL_RTSEMEVENT);
340 if (RT_UNLIKELY(!RTCritSectIsOwner(&pCritSect->s.Core)))
341 return VERR_NOT_OWNER;
342 if (RT_LIKELY( pCritSect->s.EventToSignal == NIL_RTSEMEVENT
343 || pCritSect->s.EventToSignal == EventToSignal))
344 {
345 pCritSect->s.EventToSignal = EventToSignal;
346 return VINF_SUCCESS;
347 }
348 return VERR_TOO_MANY_SEMAPHORES;
349}
350
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