VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMAll/PDMAllCritSect.cpp@ 4295

Last change on this file since 4295 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: 5.9 KB
Line 
1/* $Id: PDMAllCritSect.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* Header Files *
21*******************************************************************************/
22#define LOG_GROUP LOG_GROUP_PDM//_CRITSECT
23#include "PDMInternal.h"
24#include <VBox/pdm.h>
25#include <VBox/mm.h>
26#include <VBox/vm.h>
27#include <VBox/err.h>
28
29#include <VBox/log.h>
30#include <iprt/asm.h>
31#include <iprt/assert.h>
32#ifdef IN_RING3
33# include <iprt/semaphore.h>
34#endif
35
36
37/**
38 * Leaves a critical section entered with PDMCritSectEnter().
39 *
40 * @returns VINF_SUCCESS if entered successfully.
41 * @returns rcBusy when encountering a busy critical section in GC/R0.
42 * @returns VERR_SEM_DESTROYED if the critical section is dead.
43 *
44 * @param pCritSect The PDM critical section to enter.
45 * @param rcBusy The status code to return when we're in GC or R0
46 * and the section is busy.
47 */
48PDMDECL(int) PDMCritSectEnter(PPDMCRITSECT pCritSect, int rcBusy)
49{
50 Assert(pCritSect->s.Core.cNestings < 8); /* useful to catch incorrect locking */
51#ifdef IN_RING3
52 NOREF(rcBusy);
53
54 STAM_STATS({ if (pCritSect->s.Core.cLockers >= 0 && !RTCritSectIsOwner(&pCritSect->s.Core)) STAM_COUNTER_INC(&pCritSect->s.StatContentionR3); });
55 int rc = RTCritSectEnter(&pCritSect->s.Core);
56 STAM_STATS({ if (pCritSect->s.Core.cNestings == 1) STAM_PROFILE_ADV_START(&pCritSect->s.StatLocked, l); });
57 return rc;
58
59#else
60 AssertMsgReturn(pCritSect->s.Core.u32Magic == RTCRITSECT_MAGIC, ("%RX32\n", pCritSect->s.Core.u32Magic),
61 VERR_SEM_DESTROYED);
62 PVM pVM = pCritSect->s.CTXALLSUFF(pVM);
63 Assert(pVM);
64
65 /*
66 * Try take the lock.
67 */
68 if (ASMAtomicCmpXchgS32(&pCritSect->s.Core.cLockers, 0, -1))
69 {
70 pCritSect->s.Core.cNestings = 1;
71 ASMAtomicXchgSize(&pCritSect->s.Core.NativeThreadOwner, pVM->NativeThreadEMT);
72 STAM_PROFILE_ADV_START(&pCritSect->s.StatLocked, l);
73 return VINF_SUCCESS;
74 }
75
76 /*
77 * Nested?
78 */
79 if (pCritSect->s.Core.NativeThreadOwner == pVM->NativeThreadEMT)
80 {
81 pCritSect->s.Core.cNestings++;
82 ASMAtomicIncS32(&pCritSect->s.Core.cLockers);
83 return VINF_SUCCESS;
84 }
85
86 /*
87 * Failed.
88 */
89 LogFlow(("pcnetLock: locked => HC (%Vrc)\n", rcBusy));
90 STAM_COUNTER_INC(&pCritSect->s.StatContentionR0GCLock);
91 return rcBusy;
92#endif
93}
94
95
96/**
97 * Leaves a critical section entered with PDMCritSectEnter().
98 *
99 * @param pCritSect The PDM critical section to leave.
100 */
101PDMDECL(void) PDMCritSectLeave(PPDMCRITSECT pCritSect)
102{
103#ifdef IN_RING3
104# ifdef VBOX_WITH_STATISTICS
105 if (pCritSect->s.Core.cNestings == 1)
106 STAM_PROFILE_ADV_STOP(&pCritSect->s.StatLocked, l);
107# endif
108 RTSEMEVENT EventToSignal = pCritSect->s.EventToSignal;
109 if (RT_LIKELY(EventToSignal == NIL_RTSEMEVENT))
110 {
111 int rc = RTCritSectLeave(&pCritSect->s.Core);
112 AssertRC(rc);
113 }
114 else
115 {
116 pCritSect->s.EventToSignal = NIL_RTSEMEVENT;
117 int rc = RTCritSectLeave(&pCritSect->s.Core);
118 AssertRC(rc);
119 LogBird(("signalling %#x\n", EventToSignal));
120 rc = RTSemEventSignal(EventToSignal);
121 AssertRC(rc);
122 }
123
124#else /* !IN_RING3 */
125 Assert(VALID_PTR(pCritSect));
126 Assert(pCritSect->s.Core.u32Magic == RTCRITSECT_MAGIC);
127 Assert(pCritSect->s.Core.cNestings > 0);
128 Assert(pCritSect->s.Core.cLockers >= 0);
129 PVM pVM = pCritSect->s.CTXALLSUFF(pVM);
130 Assert(pVM);
131 Assert(pCritSect->s.Core.NativeThreadOwner == pVM->NativeThreadEMT);
132
133 /*
134 * Deal with nested attempts first.
135 * (We're exploiting nesting to avoid queuing multiple R3 leaves for the same section.)
136 */
137 pCritSect->s.Core.cNestings--;
138 if (pCritSect->s.Core.cNestings > 0)
139 {
140 ASMAtomicDecS32(&pCritSect->s.Core.cLockers);
141 return;
142 }
143
144 /*
145 * Try leave it.
146 */
147 if (pCritSect->s.Core.cLockers == 0)
148 {
149 STAM_PROFILE_ADV_STOP(&pCritSect->s.StatLocked, l);
150 ASMAtomicXchgSize(&pCritSect->s.Core.NativeThreadOwner, NIL_RTNATIVETHREAD);
151 if (ASMAtomicCmpXchgS32(&pCritSect->s.Core.cLockers, -1, 0))
152 return;
153
154 /* darn, someone raced in on us. */
155 ASMAtomicXchgSize(&pCritSect->s.Core.NativeThreadOwner, pVM->NativeThreadEMT);
156 STAM_PROFILE_ADV_START(&pCritSect->s.StatLocked, l);
157 }
158 pCritSect->s.Core.cNestings = 1;
159
160 /*
161 * Queue the request.
162 */
163 RTUINT i = pVM->pdm.s.cQueuedCritSectLeaves++;
164 LogFlow(("PDMCritSectLeave: [%d]=%p => R3\n", i, pCritSect));
165 AssertFatal(i < RT_ELEMENTS(pVM->pdm.s.apQueuedCritSectsLeaves));
166 pVM->pdm.s.apQueuedCritSectsLeaves[i] = MMHyperCCToR3(pVM, pCritSect);
167 VM_FF_SET(pVM, VM_FF_PDM_CRITSECT);
168 VM_FF_SET(pVM, VM_FF_TO_R3);
169 STAM_COUNTER_INC(&pVM->pdm.s.StatQueuedCritSectLeaves);
170 STAM_COUNTER_INC(&pCritSect->s.StatContentionR0GCUnlock);
171#endif
172}
173
174
175/**
176 * Checks the caller is the owner of the critical section.
177 *
178 * @returns true if owner.
179 * @returns false if not owner.
180 * @param pCritSect The critical section.
181 */
182PDMDECL(bool) PDMCritSectIsOwner(PCPDMCRITSECT pCritSect)
183{
184#ifdef IN_RING3
185 return RTCritSectIsOwner(&pCritSect->s.Core);
186#else
187 PVM pVM = pCritSect->s.CTXALLSUFF(pVM);
188 Assert(pVM);
189 return pCritSect->s.Core.NativeThreadOwner == pVM->NativeThreadEMT;
190#endif
191}
192
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