VirtualBox

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

Last change on this file since 5474 was 4071, checked in by vboxsync, 17 years ago

Biggest check-in ever. New source code headers for all (C) innotek files.

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