VirtualBox

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

最後變更 在這個檔案從19991是 19991,由 vboxsync 提交於 16 年 前

pdmcritsect: work in progress.

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Id
檔案大小: 15.3 KB
 
1/* $Id: PDMCritSect.cpp 19991 2009-05-25 10:41:07Z vboxsync $ */
2/** @file
3 * PDM - Critical Sections, Ring-3.
4 */
5
6/*
7 * Copyright (C) 2006-2009 Sun Microsystems, Inc.
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.alldomusa.eu.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//#define PDM_WITH_R3R0_CRIT_SECT
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
33#include <VBox/err.h>
34#include <VBox/log.h>
35#ifdef PDM_WITH_R3R0_CRIT_SECT
36# include <VBox/sup.h>
37#endif
38#include <iprt/asm.h>
39#include <iprt/assert.h>
40#include <iprt/string.h>
41#include <iprt/thread.h>
42
43
44/*******************************************************************************
45* Internal Functions *
46*******************************************************************************/
47static int pdmR3CritSectDeleteOne(PVM pVM, PPDMCRITSECTINT pCritSect, PPDMCRITSECTINT pPrev, bool fFinal);
48
49
50
51/**
52 * Initializes the critical section subcomponent.
53 *
54 * @returns VBox status code.
55 * @param pVM The VM handle.
56 * @remark Not to be confused with PDMR3CritSectInit and pdmR3CritSectInitDevice which are
57 * for initializing a critical section.
58 */
59int pdmR3CritSectInit(PVM pVM)
60{
61 STAM_REG(pVM, &pVM->pdm.s.StatQueuedCritSectLeaves, STAMTYPE_COUNTER, "/PDM/QueuedCritSectLeaves", STAMUNIT_OCCURENCES,
62 "Number of times a critical section leave requesed needed to be queued for ring-3 execution.");
63 return VINF_SUCCESS;
64}
65
66
67/**
68 * Relocates all the critical sections.
69 *
70 * @param pVM The VM handle.
71 */
72void pdmR3CritSectRelocate(PVM pVM)
73{
74 for (PPDMCRITSECTINT pCur = pVM->pdm.s.pCritSects;
75 pCur;
76 pCur = pCur->pNext)
77 pCur->pVMRC = pVM->pVMRC;
78}
79
80
81/**
82 * Deletes all remaining critical sections.
83 *
84 * This is called at the end of the termination process.
85 *
86 * @returns VBox status.
87 * First error code, rest is lost.
88 * @param pVM The VM handle.
89 * @remark Don't confuse this with PDMR3CritSectDelete.
90 */
91VMMDECL(int) PDMR3CritSectTerm(PVM pVM)
92{
93 int rc = VINF_SUCCESS;
94 while (pVM->pdm.s.pCritSects)
95 {
96 int rc2 = pdmR3CritSectDeleteOne(pVM, pVM->pdm.s.pCritSects, NULL, true /* final */);
97 AssertRC(rc2);
98 if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
99 rc = rc2;
100 }
101 return rc;
102}
103
104
105
106/**
107 * Initalizes a critical section and inserts it into the list.
108 *
109 * @returns VBox status code.
110 * @param pVM The Vm handle.
111 * @param pCritSect The critical section.
112 * @param pvKey The owner key.
113 * @param pszName The name of the critical section (for statistics).
114 */
115static int pdmR3CritSectInitOne(PVM pVM, PPDMCRITSECTINT pCritSect, void *pvKey, const char *pszName)
116{
117 VM_ASSERT_EMT(pVM);
118
119#ifdef PDM_WITH_R3R0_CRIT_SECT
120 /*
121 * Allocate the semaphore.
122 */
123 AssertCompile(sizeof(SUPSEMEVENT) == sizeof(pCritSect->Core.EventSem));
124 int rc = SUPSemEventCreate(pVM->pSession, (PSUPSEMEVENT)&pCritSect->Core.EventSem);
125#else
126 int rc = RTCritSectInit(&pCritSect->Core);
127#endif
128 if (RT_SUCCESS(rc))
129 {
130#ifdef PDM_WITH_R3R0_CRIT_SECT
131 /*
132 * Initialize the structure (first bit is c&p from RTCritSectInitEx).
133 */
134 pCritSect->Core.u32Magic = RTCRITSECT_MAGIC;
135 pCritSect->Core.fFlags = 0;
136 pCritSect->Core.cNestings = 0;
137 pCritSect->Core.cLockers = -1;
138 pCritSect->Core.NativeThreadOwner = NIL_RTNATIVETHREAD;
139 pCritSect->Core.Strict.ThreadOwner = NIL_RTTHREAD;
140 pCritSect->Core.Strict.pszEnterFile = NULL;
141 pCritSect->Core.Strict.u32EnterLine = 0;
142 pCritSect->Core.Strict.uEnterId = 0;
143#endif
144 pCritSect->pVMR3 = pVM;
145 pCritSect->pVMR0 = pVM->pVMR0;
146 pCritSect->pVMRC = pVM->pVMRC;
147 pCritSect->pvKey = pvKey;
148 pCritSect->EventToSignal = NIL_RTSEMEVENT;
149 pCritSect->pNext = pVM->pdm.s.pCritSects;
150 pCritSect->pszName = RTStrDup(pszName);
151 pVM->pdm.s.pCritSects = pCritSect;
152 STAMR3RegisterF(pVM, &pCritSect->StatContentionRZLock, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, NULL, "/PDM/CritSects/%s/ContentionRZLock", pszName);
153 STAMR3RegisterF(pVM, &pCritSect->StatContentionRZUnlock,STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, NULL, "/PDM/CritSects/%s/ContentionRZUnlock", pszName);
154 STAMR3RegisterF(pVM, &pCritSect->StatContentionR3, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, NULL, "/PDM/CritSects/%s/ContentionR3", pszName);
155#ifdef VBOX_WITH_STATISTICS
156 STAMR3RegisterF(pVM, &pCritSect->StatLocked, STAMTYPE_PROFILE_ADV, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_OCCURENCE, NULL, "/PDM/CritSects/%s/Locked", pszName);
157#endif
158 }
159 return rc;
160}
161
162
163/**
164 * Initializes a PDM critical section for internal use.
165 *
166 * The PDM critical sections are derived from the IPRT critical sections, but
167 * works in GC as well.
168 *
169 * @returns VBox status code.
170 * @param pVM The VM handle.
171 * @param pDevIns Device instance.
172 * @param pCritSect Pointer to the critical section.
173 * @param pszName The name of the critical section (for statistics).
174 */
175VMMR3DECL(int) PDMR3CritSectInit(PVM pVM, PPDMCRITSECT pCritSect, const char *pszName)
176{
177#if HC_ARCH_BITS == 64 && GC_ARCH_BITS == 32
178 AssertCompile(sizeof(pCritSect->padding) >= sizeof(pCritSect->s));
179#endif
180 Assert(RT_ALIGN_P(pCritSect, sizeof(uintptr_t)) == pCritSect);
181 return pdmR3CritSectInitOne(pVM, &pCritSect->s, pCritSect, pszName);
182}
183
184
185/**
186 * Initializes a PDM critical section.
187 *
188 * The PDM critical sections are derived from the IPRT critical sections, but
189 * works in GC as well.
190 *
191 * @returns VBox status code.
192 * @param pVM The VM handle.
193 * @param pDevIns Device instance.
194 * @param pCritSect Pointer to the critical section.
195 * @param pszName The name of the critical section (for statistics).
196 */
197int pdmR3CritSectInitDevice(PVM pVM, PPDMDEVINS pDevIns, PPDMCRITSECT pCritSect, const char *pszName)
198{
199 return pdmR3CritSectInitOne(pVM, &pCritSect->s, pDevIns, pszName);
200}
201
202
203/**
204 * Deletes one critical section.
205 *
206 * @returns Return code from RTCritSectDelete.
207 * @param pVM The VM handle.
208 * @param pCritSect The critical section.
209 * @param pPrev The previous critical section in the list.
210 * @param fFinal Set if this is the final call and statistics shouldn't be deregistered.
211 */
212static int pdmR3CritSectDeleteOne(PVM pVM, PPDMCRITSECTINT pCritSect, PPDMCRITSECTINT pPrev, bool fFinal)
213{
214#ifdef PDM_WITH_R3R0_CRIT_SECT
215 /*
216 * Assert free waiters and so on (c&p from RTCritSectDelete).
217 */
218 Assert(pCritSect->Core.u32Magic == RTCRITSECT_MAGIC);
219 Assert(pCritSect->Core.cNestings == 0);
220 Assert(pCritSect->Core.cLockers == -1);
221 Assert(pCritSect->Core.NativeThreadOwner == NIL_RTNATIVETHREAD);
222#endif
223
224 /*
225 * Unlink it.
226 */
227 if (pPrev)
228 pPrev->pNext = pCritSect->pNext;
229 else
230 pVM->pdm.s.pCritSects = pCritSect->pNext;
231
232 /*
233 * Delete it (parts taken from RTCritSectDelete).
234 * In case someone is waiting we'll signal the semaphore cLockers + 1 times.
235 */
236#ifdef PDM_WITH_R3R0_CRIT_SECT
237 ASMAtomicWriteU32(&pCritSect->Core.u32Magic, 0);
238 SUPSEMEVENT hEvent = (SUPSEMEVENT)pCritSect->Core.EventSem;
239 pCritSect->Core.EventSem = NIL_RTSEMEVENT;
240 while (pCritSect->Core.cLockers-- >= 0)
241 SUPSemEventSignal(pVM->pSession, hEvent);
242 ASMAtomicWriteS32(&pCritSect->Core.cLockers, -1);
243 int rc = SUPSemEventClose(pVM->pSession, hEvent);
244 AssertRC(rc);
245#endif
246 pCritSect->pNext = NULL;
247 pCritSect->pvKey = NULL;
248 pCritSect->pVMR3 = NULL;
249 pCritSect->pVMR0 = NIL_RTR0PTR;
250 pCritSect->pVMRC = NIL_RTRCPTR;
251 RTStrFree((char *)pCritSect->pszName);
252 pCritSect->pszName = NULL;
253 if (!fFinal)
254 {
255 STAMR3Deregister(pVM, &pCritSect->StatContentionRZLock);
256 STAMR3Deregister(pVM, &pCritSect->StatContentionRZUnlock);
257 STAMR3Deregister(pVM, &pCritSect->StatContentionR3);
258#ifdef VBOX_WITH_STATISTICS
259 STAMR3Deregister(pVM, &pCritSect->StatLocked);
260#endif
261 }
262#ifndef PDM_WITH_R3R0_CRIT_SECT
263 int rc = RTCritSectDelete(&pCritSect->Core);
264#endif
265 return rc;
266}
267
268
269/**
270 * Deletes all critical sections with a give initializer key.
271 *
272 * @returns VBox status code.
273 * The entire list is processed on failure, so we'll only
274 * return the first error code. This shouldn't be a problem
275 * since errors really shouldn't happen here.
276 * @param pVM The VM handle.
277 * @param pvKey The initializer key.
278 */
279static int pdmR3CritSectDeleteByKey(PVM pVM, void *pvKey)
280{
281 /*
282 * Iterate the list and match key.
283 */
284 int rc = VINF_SUCCESS;
285 PPDMCRITSECTINT pPrev = NULL;
286 PPDMCRITSECTINT pCur = pVM->pdm.s.pCritSects;
287 while (pCur)
288 {
289 if (pCur->pvKey == pvKey)
290 {
291 int rc2 = pdmR3CritSectDeleteOne(pVM, pCur, pPrev, false /* not final */);
292 AssertRC(rc2);
293 if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
294 rc = rc2;
295 }
296
297 /* next */
298 pPrev = pCur;
299 pCur = pCur->pNext;
300 }
301 return rc;
302}
303
304
305/**
306 * Deletes all undeleted critical sections initalized by a given device.
307 *
308 * @returns VBox status code.
309 * @param pVM The VM handle.
310 * @param pDevIns The device handle.
311 */
312int pdmR3CritSectDeleteDevice(PVM pVM, PPDMDEVINS pDevIns)
313{
314 return pdmR3CritSectDeleteByKey(pVM, pDevIns);
315}
316
317
318/**
319 * Deletes the critical section.
320 *
321 * @returns VBox status code.
322 * @param pCritSect The PDM critical section to destroy.
323 */
324VMMR3DECL(int) PDMR3CritSectDelete(PPDMCRITSECT pCritSect)
325{
326 if (!RTCritSectIsInitialized(&pCritSect->s.Core))
327 return VINF_SUCCESS;
328
329 /*
330 * Find and unlink it.
331 */
332 PVM pVM = pCritSect->s.pVMR3;
333 AssertReleaseReturn(pVM, VERR_INTERNAL_ERROR);
334 PPDMCRITSECTINT pPrev = NULL;
335 PPDMCRITSECTINT pCur = pVM->pdm.s.pCritSects;
336 while (pCur)
337 {
338 if (pCur == &pCritSect->s)
339 return pdmR3CritSectDeleteOne(pVM, pCur, pPrev, false /* not final */);
340
341 /* next */
342 pPrev = pCur;
343 pCur = pCur->pNext;
344 }
345 AssertReleaseMsgFailed(("pCritSect=%p wasn't found!\n", pCritSect));
346 return VERR_INTERNAL_ERROR;
347}
348
349
350/**
351 * Process the critical sections queued for ring-3 'leave'.
352 *
353 * @param pVCpu The VMCPU handle.
354 */
355VMMR3DECL(void) PDMR3CritSectFF(PVMCPU pVCpu)
356{
357 Assert(pVCpu->pdm.s.cQueuedCritSectLeaves > 0);
358
359 const RTUINT c = pVCpu->pdm.s.cQueuedCritSectLeaves;
360 for (RTUINT i = 0; i < c; i++)
361 {
362 PPDMCRITSECT pCritSect = pVCpu->pdm.s.apQueuedCritSectsLeaves[i];
363#ifdef PDM_WITH_R3R0_CRIT_SECT
364 int rc = pdmCritSectLeave(pCritSect);
365#else
366 int rc = RTCritSectLeave(&pCritSect->s.Core);
367#endif
368 LogFlow(("PDMR3CritSectFF: %p - %Rrc\n", pCritSect, rc));
369 AssertRC(rc);
370 }
371
372 pVCpu->pdm.s.cQueuedCritSectLeaves = 0;
373 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_PDM_CRITSECT);
374}
375
376
377/**
378 * Schedule a event semaphore for signalling upon critsect exit.
379 *
380 * @returns VINF_SUCCESS on success.
381 * @returns VERR_TOO_MANY_SEMAPHORES if an event was already scheduled.
382 * @returns VERR_NOT_OWNER if we're not the critsect owner.
383 * @returns VERR_SEM_DESTROYED if RTCritSectDelete was called while waiting.
384 * @param pCritSect The critical section.
385 * @param EventToSignal The semapore that should be signalled.
386 */
387VMMR3DECL(int) PDMR3CritSectScheduleExitEvent(PPDMCRITSECT pCritSect, RTSEMEVENT EventToSignal)
388{
389 Assert(EventToSignal != NIL_RTSEMEVENT);
390 if (RT_UNLIKELY(!RTCritSectIsOwner(&pCritSect->s.Core)))
391 return VERR_NOT_OWNER;
392 if (RT_LIKELY( pCritSect->s.EventToSignal == NIL_RTSEMEVENT
393 || pCritSect->s.EventToSignal == EventToSignal))
394 {
395 pCritSect->s.EventToSignal = EventToSignal;
396 return VINF_SUCCESS;
397 }
398 return VERR_TOO_MANY_SEMAPHORES;
399}
400
401
402/**
403 * Counts the critical sections owned by the calling thread, optionally
404 * returning a comma separated list naming them.
405 *
406 * This is for diagnostic purposes only.
407 *
408 * @returns Lock count.
409 *
410 * @param pVM The VM handle.
411 * @param pszNames Where to return the critical section names.
412 * @param cbNames The size of the buffer.
413 */
414VMMR3DECL(uint32_t) PDMR3CritSectCountOwned(PVM pVM, char *pszNames, size_t cbNames)
415{
416 /*
417 * Init the name buffer.
418 */
419 size_t cchLeft = cbNames;
420 if (cchLeft)
421 {
422 cchLeft--;
423 pszNames[0] = pszNames[cchLeft] = '\0';
424 }
425
426 /*
427 * Iterate the critical sections.
428 */
429 /* This is unsafe, but wtf. */
430 RTNATIVETHREAD const hNativeThread = RTThreadNativeSelf();
431 uint32_t cCritSects = 0;
432 for (PPDMCRITSECTINT pCur = pVM->pdm.s.pCritSects;
433 pCur;
434 pCur = pCur->pNext)
435 {
436 /* Same as RTCritSectIsOwner(). */
437 if (pCur->Core.NativeThreadOwner == hNativeThread)
438 {
439 cCritSects++;
440
441 /*
442 * Copy the name if there is space. Fun stuff.
443 */
444 if (cchLeft)
445 {
446 /* try add comma. */
447 if (cCritSects != 1)
448 {
449 *pszNames++ = ',';
450 if (--cchLeft)
451 {
452 *pszNames++ = ' ';
453 cchLeft--;
454 }
455 }
456
457 /* try copy the name. */
458 if (cchLeft)
459 {
460 size_t const cchName = strlen(pCur->pszName);
461 if (cchName < cchLeft)
462 {
463 memcpy(pszNames, pCur->pszName, cchName);
464 pszNames += cchName;
465 cchLeft -= cchName;
466 }
467 else
468 {
469 if (cchLeft > 2)
470 {
471 memcpy(pszNames, pCur->pszName, cchLeft - 2);
472 pszNames += cchLeft - 2;
473 cchLeft = 2;
474 }
475 while (cchLeft-- > 0)
476 *pszNames++ = '+';
477 }
478 }
479 *pszNames = '\0';
480 }
481 }
482 }
483
484 return cCritSects;
485}
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette