VirtualBox

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

Last change on this file since 19167 was 18532, checked in by vboxsync, 16 years ago

PDMCritSect: Increased the padding size on 32-bit (+32 bytes) for saving the name. Added PDMR3CritSectCountOwned(). Promoted three of the stats to release stats.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 13.6 KB
Line 
1/* $Id: PDMCritSect.cpp 18532 2009-03-30 12:01:20Z 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#include <iprt/string.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->pVMRC = pVM->pVMRC;
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 */
87VMMDECL(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 (RT_FAILURE(rc2) && RT_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 (RT_SUCCESS(rc))
116 {
117 pCritSect->pVMR3 = pVM;
118 pCritSect->pVMR0 = pVM->pVMR0;
119 pCritSect->pVMRC = pVM->pVMRC;
120 pCritSect->pvKey = pvKey;
121 pCritSect->EventToSignal = NIL_RTSEMEVENT;
122 pCritSect->pNext = pVM->pdm.s.pCritSects;
123 pCritSect->pszName = RTStrDup(pszName);
124 pVM->pdm.s.pCritSects = pCritSect;
125 STAMR3RegisterF(pVM, &pCritSect->StatContentionRZLock, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, NULL, "/PDM/CritSects/%s/ContentionRZLock", pszName);
126 STAMR3RegisterF(pVM, &pCritSect->StatContentionRZUnlock,STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, NULL, "/PDM/CritSects/%s/ContentionRZUnlock", pszName);
127 STAMR3RegisterF(pVM, &pCritSect->StatContentionR3, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, NULL, "/PDM/CritSects/%s/ContentionR3", pszName);
128#ifdef VBOX_WITH_STATISTICS
129 STAMR3RegisterF(pVM, &pCritSect->StatLocked, STAMTYPE_PROFILE_ADV, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_OCCURENCE, NULL, "/PDM/CritSects/%s/Locked", pszName);
130#endif
131 }
132 return rc;
133}
134
135
136/**
137 * Initializes a PDM critical section for internal use.
138 *
139 * The PDM critical sections are derived from the IPRT critical sections, but
140 * works in GC as well.
141 *
142 * @returns VBox status code.
143 * @param pVM The VM handle.
144 * @param pDevIns Device instance.
145 * @param pCritSect Pointer to the critical section.
146 * @param pszName The name of the critical section (for statistics).
147 */
148VMMR3DECL(int) PDMR3CritSectInit(PVM pVM, PPDMCRITSECT pCritSect, const char *pszName)
149{
150#if HC_ARCH_BITS == 64 && GC_ARCH_BITS == 32
151 AssertCompile(sizeof(pCritSect->padding) >= sizeof(pCritSect->s));
152#endif
153 return pdmR3CritSectInitOne(pVM, &pCritSect->s, pCritSect, pszName);
154}
155
156
157/**
158 * Initializes a PDM critical section.
159 *
160 * The PDM critical sections are derived from the IPRT critical sections, but
161 * works in GC as well.
162 *
163 * @returns VBox status code.
164 * @param pVM The VM handle.
165 * @param pDevIns Device instance.
166 * @param pCritSect Pointer to the critical section.
167 * @param pszName The name of the critical section (for statistics).
168 */
169int pdmR3CritSectInitDevice(PVM pVM, PPDMDEVINS pDevIns, PPDMCRITSECT pCritSect, const char *pszName)
170{
171 return pdmR3CritSectInitOne(pVM, &pCritSect->s, pDevIns, pszName);
172}
173
174
175/**
176 * Deletes one critical section.
177 *
178 * @returns Return code from RTCritSectDelete.
179 * @param pVM The VM handle.
180 * @param pCritSect The critical section.
181 * @param pPrev The previous critical section in the list.
182 * @param fFinal Set if this is the final call and statistics shouldn't be deregistered.
183 */
184static int pdmR3CritSectDeleteOne(PVM pVM, PPDMCRITSECTINT pCritSect, PPDMCRITSECTINT pPrev, bool fFinal)
185{
186 /* ulink */
187 if (pPrev)
188 pPrev->pNext = pCritSect->pNext;
189 else
190 pVM->pdm.s.pCritSects = pCritSect->pNext;
191
192 /* delete */
193 pCritSect->pNext = NULL;
194 pCritSect->pvKey = NULL;
195 pCritSect->pVMR3 = NULL;
196 pCritSect->pVMR0 = NIL_RTR0PTR;
197 pCritSect->pVMRC = NIL_RTRCPTR;
198 RTStrFree((char *)pCritSect->pszName);
199 pCritSect->pszName = NULL;
200 if (!fFinal)
201 {
202 STAMR3Deregister(pVM, &pCritSect->StatContentionRZLock);
203 STAMR3Deregister(pVM, &pCritSect->StatContentionRZUnlock);
204 STAMR3Deregister(pVM, &pCritSect->StatContentionR3);
205#ifdef VBOX_WITH_STATISTICS
206 STAMR3Deregister(pVM, &pCritSect->StatLocked);
207#endif
208 }
209 return RTCritSectDelete(&pCritSect->Core);
210}
211
212
213/**
214 * Deletes all critical sections with a give initializer key.
215 *
216 * @returns VBox status code.
217 * The entire list is processed on failure, so we'll only
218 * return the first error code. This shouldn't be a problem
219 * since errors really shouldn't happen here.
220 * @param pVM The VM handle.
221 * @param pvKey The initializer key.
222 */
223static int pdmR3CritSectDeleteByKey(PVM pVM, void *pvKey)
224{
225 /*
226 * Iterate the list and match key.
227 */
228 int rc = VINF_SUCCESS;
229 PPDMCRITSECTINT pPrev = NULL;
230 PPDMCRITSECTINT pCur = pVM->pdm.s.pCritSects;
231 while (pCur)
232 {
233 if (pCur->pvKey == pvKey)
234 {
235 int rc2 = pdmR3CritSectDeleteOne(pVM, pCur, pPrev, false /* not final */);
236 AssertRC(rc2);
237 if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
238 rc = rc2;
239 }
240
241 /* next */
242 pPrev = pCur;
243 pCur = pCur->pNext;
244 }
245 return rc;
246}
247
248
249/**
250 * Deletes all undeleted critical sections initalized by a given device.
251 *
252 * @returns VBox status code.
253 * @param pVM The VM handle.
254 * @param pDevIns The device handle.
255 */
256int pdmR3CritSectDeleteDevice(PVM pVM, PPDMDEVINS pDevIns)
257{
258 return pdmR3CritSectDeleteByKey(pVM, pDevIns);
259}
260
261
262/**
263 * Deletes the critical section.
264 *
265 * @returns VBox status code.
266 * @param pCritSect The PDM critical section to destroy.
267 */
268VMMR3DECL(int) PDMR3CritSectDelete(PPDMCRITSECT pCritSect)
269{
270 if (!RTCritSectIsInitialized(&pCritSect->s.Core))
271 return VINF_SUCCESS;
272
273 /*
274 * Find and unlink it.
275 */
276 PVM pVM = pCritSect->s.pVMR3;
277 AssertReleaseReturn(pVM, VERR_INTERNAL_ERROR);
278 PPDMCRITSECTINT pPrev = NULL;
279 PPDMCRITSECTINT pCur = pVM->pdm.s.pCritSects;
280 while (pCur)
281 {
282 if (pCur == &pCritSect->s)
283 return pdmR3CritSectDeleteOne(pVM, pCur, pPrev, false /* not final */);
284
285 /* next */
286 pPrev = pCur;
287 pCur = pCur->pNext;
288 }
289 AssertReleaseMsgFailed(("pCritSect=%p wasn't found!\n", pCritSect));
290 return VERR_INTERNAL_ERROR;
291}
292
293
294/**
295 * Process the critical sections queued for ring-3 'leave'.
296 *
297 * @param pVM The VM handle.
298 */
299VMMR3DECL(void) PDMR3CritSectFF(PVM pVM)
300{
301 Assert(pVM->pdm.s.cQueuedCritSectLeaves > 0);
302
303 const RTUINT c = pVM->pdm.s.cQueuedCritSectLeaves;
304 for (RTUINT i = 0; i < c; i++)
305 {
306 PPDMCRITSECT pCritSect = pVM->pdm.s.apQueuedCritSectsLeaves[i];
307 int rc = RTCritSectLeave(&pCritSect->s.Core);
308 LogFlow(("PDMR3CritSectFF: %p - %Rrc\n", pCritSect, rc));
309 AssertRC(rc);
310 }
311
312 pVM->pdm.s.cQueuedCritSectLeaves = 0;
313 VM_FF_CLEAR(pVM, VM_FF_PDM_CRITSECT);
314}
315
316
317/**
318 * Try enter a critical section.
319 *
320 * @returns VINF_SUCCESS on success.
321 * @returns VERR_SEM_BUSY if the critsect was owned.
322 * @returns VERR_SEM_NESTED if nested enter on a no nesting section. (Asserted.)
323 * @returns VERR_SEM_DESTROYED if RTCritSectDelete was called while waiting.
324 * @param pCritSect The critical section.
325 */
326VMMR3DECL(int) PDMR3CritSectTryEnter(PPDMCRITSECT pCritSect)
327{
328 return RTCritSectTryEnter(&pCritSect->s.Core);
329}
330
331
332/**
333 * Schedule a event semaphore for signalling upon critsect exit.
334 *
335 * @returns VINF_SUCCESS on success.
336 * @returns VERR_TOO_MANY_SEMAPHORES if an event was already scheduled.
337 * @returns VERR_NOT_OWNER if we're not the critsect owner.
338 * @returns VERR_SEM_DESTROYED if RTCritSectDelete was called while waiting.
339 * @param pCritSect The critical section.
340 * @param EventToSignal The semapore that should be signalled.
341 */
342VMMR3DECL(int) PDMR3CritSectScheduleExitEvent(PPDMCRITSECT pCritSect, RTSEMEVENT EventToSignal)
343{
344 Assert(EventToSignal != NIL_RTSEMEVENT);
345 if (RT_UNLIKELY(!RTCritSectIsOwner(&pCritSect->s.Core)))
346 return VERR_NOT_OWNER;
347 if (RT_LIKELY( pCritSect->s.EventToSignal == NIL_RTSEMEVENT
348 || pCritSect->s.EventToSignal == EventToSignal))
349 {
350 pCritSect->s.EventToSignal = EventToSignal;
351 return VINF_SUCCESS;
352 }
353 return VERR_TOO_MANY_SEMAPHORES;
354}
355
356
357/**
358 * Counts the critical sections owned by the calling thread, optionally
359 * returning a comma separated list naming them.
360 *
361 * This is for diagnostic purposes only.
362 *
363 * @returns Lock count.
364 *
365 * @param pVM The VM handle.
366 * @param pszNames Where to return the critical section names.
367 * @param cbNames The size of the buffer.
368 */
369VMMR3DECL(uint32_t) PDMR3CritSectCountOwned(PVM pVM, char *pszNames, size_t cbNames)
370{
371 /*
372 * Init the name buffer.
373 */
374 size_t cchLeft = cbNames;
375 if (cchLeft)
376 {
377 cchLeft--;
378 pszNames[0] = pszNames[cchLeft] = '\0';
379 }
380
381 /*
382 * Iterate the critical sections.
383 */
384 /* This is unsafe, but wtf. */
385 RTNATIVETHREAD const hNativeThread = RTThreadNativeSelf();
386 uint32_t cCritSects = 0;
387 for (PPDMCRITSECTINT pCur = pVM->pdm.s.pCritSects;
388 pCur;
389 pCur = pCur->pNext)
390 {
391 /* Same as RTCritSectIsOwner(). */
392 if (pCur->Core.NativeThreadOwner == hNativeThread)
393 {
394 cCritSects++;
395
396 /*
397 * Copy the name if there is space. Fun stuff.
398 */
399 if (cchLeft)
400 {
401 /* try add comma. */
402 if (cCritSects != 1)
403 {
404 *pszNames++ = ',';
405 if (--cchLeft)
406 {
407 *pszNames++ = ' ';
408 cchLeft--;
409 }
410 }
411
412 /* try copy the name. */
413 if (cchLeft)
414 {
415 size_t const cchName = strlen(pCur->pszName);
416 if (cchName < cchLeft)
417 {
418 memcpy(pszNames, pCur->pszName, cchName);
419 pszNames += cchName;
420 cchLeft -= cchName;
421 }
422 else
423 {
424 if (cchLeft > 2)
425 {
426 memcpy(pszNames, pCur->pszName, cchLeft - 2);
427 pszNames += cchLeft - 2;
428 cchLeft = 2;
429 }
430 while (cchLeft-- > 0)
431 *pszNames++ = '+';
432 }
433 }
434 *pszNames = '\0';
435 }
436 }
437 }
438
439 return cCritSects;
440}
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