VirtualBox

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

Last change on this file since 3840 was 2981, checked in by vboxsync, 17 years ago

InnoTek -> innotek: all the headers and comments.

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