VirtualBox

source: vbox/trunk/src/VBox/Main/src-server/BandwidthGroupImpl.cpp@ 40262

Last change on this file since 40262 was 40257, checked in by vboxsync, 13 years ago

Main/Medium: rework locking scheme to solve lock order violations and long GUI start up time caused by too much locking
Main/all: Remove the enter and leave methods from write locks, they cause hard to find locking problems. Better solve them explicitly.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 10.4 KB
Line 
1/** @file
2 *
3 * VirtualBox COM class implementation
4 */
5
6/*
7 * Copyright (C) 2006-2012 Oracle Corporation
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
18#include "BandwidthGroupImpl.h"
19#include "MachineImpl.h"
20#include "Global.h"
21
22#include "AutoCaller.h"
23#include "Logging.h"
24
25#include <iprt/cpp/utils.h>
26
27////////////////////////////////////////////////////////////////////////////////
28//
29// private member data definition
30//
31////////////////////////////////////////////////////////////////////////////////
32
33struct BackupableBandwidthGroupData
34{
35 BackupableBandwidthGroupData()
36 : enmType(BandwidthGroupType_Null),
37 aMaxMbPerSec(0),
38 cReferences(0)
39 { }
40
41 Utf8Str strName;
42 BandwidthGroupType_T enmType;
43 ULONG aMaxMbPerSec;
44 ULONG cReferences;
45};
46
47struct BandwidthGroup::Data
48{
49 Data(BandwidthControl * const aBandwidthControl)
50 : pParent(aBandwidthControl),
51 pPeer(NULL)
52 { }
53
54 BandwidthControl * const pParent;
55 ComObjPtr<BandwidthGroup> pPeer;
56
57 // use the XML settings structure in the members for simplicity
58 Backupable<BackupableBandwidthGroupData> bd;
59};
60
61// constructor / destructor
62/////////////////////////////////////////////////////////////////////////////
63
64HRESULT BandwidthGroup::FinalConstruct()
65{
66 return BaseFinalConstruct();
67}
68
69void BandwidthGroup::FinalRelease()
70{
71 uninit();
72 BaseFinalRelease();
73}
74
75// public initializer/uninitializer for internal purposes only
76/////////////////////////////////////////////////////////////////////////////
77
78/**
79 * Initializes the bandwidth group object.
80 *
81 * @returns COM result indicator.
82 * @param aParent Pointer to our parent object.
83 * @param aName Name of the storage controller.
84 * @param aInstance Instance number of the storage controller.
85 */
86HRESULT BandwidthGroup::init(BandwidthControl *aParent,
87 const Utf8Str &aName,
88 BandwidthGroupType_T aType,
89 ULONG aMaxMbPerSec)
90{
91 LogFlowThisFunc(("aParent=%p aName=\"%s\"\n",
92 aParent, aName.c_str()));
93
94 ComAssertRet(aParent && !aName.isEmpty(), E_INVALIDARG);
95 if ( (aType <= BandwidthGroupType_Null)
96 || (aType > BandwidthGroupType_Network))
97 return setError(E_INVALIDARG,
98 tr("Invalid bandwidth group type type"));
99
100 /* Enclose the state transition NotReady->InInit->Ready */
101 AutoInitSpan autoInitSpan(this);
102 AssertReturn(autoInitSpan.isOk(), E_FAIL);
103
104 m = new Data(aParent);
105
106 /* m->pPeer is left null */
107
108 m->bd.allocate();
109
110 m->bd->strName = aName;
111 m->bd->enmType = aType;
112 m->bd->cReferences = 0;
113 m->bd->aMaxMbPerSec = aMaxMbPerSec;
114
115 /* Confirm a successful initialization */
116 autoInitSpan.setSucceeded();
117
118 return S_OK;
119}
120
121/**
122 * Initializes the object given another object
123 * (a kind of copy constructor). This object shares data with
124 * the object passed as an argument.
125 *
126 * @param aReshare
127 * When false, the original object will remain a data owner.
128 * Otherwise, data ownership will be transferred from the original
129 * object to this one.
130 *
131 * @note This object must be destroyed before the original object
132 * it shares data with is destroyed.
133 *
134 * @note Locks @a aThat object for writing if @a aReshare is @c true, or for
135 * reading if @a aReshare is false.
136 */
137HRESULT BandwidthGroup::init(BandwidthControl *aParent,
138 BandwidthGroup *aThat,
139 bool aReshare /* = false */)
140{
141 LogFlowThisFunc(("aParent=%p, aThat=%p, aReshare=%RTbool\n",
142 aParent, aThat, aReshare));
143
144 ComAssertRet(aParent && aThat, E_INVALIDARG);
145
146 /* Enclose the state transition NotReady->InInit->Ready */
147 AutoInitSpan autoInitSpan(this);
148 AssertReturn(autoInitSpan.isOk(), E_FAIL);
149
150 m = new Data(aParent);
151
152 /* sanity */
153 AutoCaller thatCaller(aThat);
154 AssertComRCReturnRC(thatCaller.rc());
155
156 if (aReshare)
157 {
158 AutoWriteLock thatLock(aThat COMMA_LOCKVAL_SRC_POS);
159
160 unconst(aThat->m->pPeer) = this;
161 m->bd.attach (aThat->m->bd);
162 }
163 else
164 {
165 unconst(m->pPeer) = aThat;
166
167 AutoReadLock thatLock(aThat COMMA_LOCKVAL_SRC_POS);
168 m->bd.share (aThat->m->bd);
169 }
170
171 /* Confirm successful initialization */
172 autoInitSpan.setSucceeded();
173
174 return S_OK;
175}
176
177/**
178 * Initializes the storage controller object given another guest object
179 * (a kind of copy constructor). This object makes a private copy of data
180 * of the original object passed as an argument.
181 */
182HRESULT BandwidthGroup::initCopy(BandwidthControl *aParent, BandwidthGroup *aThat)
183{
184 LogFlowThisFunc(("aParent=%p, aThat=%p\n", aParent, aThat));
185
186 ComAssertRet(aParent && aThat, E_INVALIDARG);
187
188 /* Enclose the state transition NotReady->InInit->Ready */
189 AutoInitSpan autoInitSpan(this);
190 AssertReturn(autoInitSpan.isOk(), E_FAIL);
191
192 m = new Data(aParent);
193 /* m->pPeer is left null */
194
195 AutoCaller thatCaller(aThat);
196 AssertComRCReturnRC(thatCaller.rc());
197
198 AutoReadLock thatlock(aThat COMMA_LOCKVAL_SRC_POS);
199 m->bd.attachCopy(aThat->m->bd);
200
201 /* Confirm a successful initialization */
202 autoInitSpan.setSucceeded();
203
204 return S_OK;
205}
206
207
208/**
209 * Uninitializes the instance and sets the ready flag to FALSE.
210 * Called either from FinalRelease() or by the parent when it gets destroyed.
211 */
212void BandwidthGroup::uninit()
213{
214 LogFlowThisFunc(("\n"));
215
216 /* Enclose the state transition Ready->InUninit->NotReady */
217 AutoUninitSpan autoUninitSpan(this);
218 if (autoUninitSpan.uninitDone())
219 return;
220
221 m->bd.free();
222
223 unconst(m->pPeer) = NULL;
224 unconst(m->pParent) = NULL;
225
226 delete m;
227 m = NULL;
228}
229
230STDMETHODIMP BandwidthGroup::COMGETTER(Name)(BSTR *aName)
231{
232 CheckComArgOutPointerValid(aName);
233
234 AutoCaller autoCaller(this);
235 if (FAILED(autoCaller.rc())) return autoCaller.rc();
236
237 /* mName is constant during life time, no need to lock */
238 m->bd.data()->strName.cloneTo(aName);
239
240 return S_OK;
241}
242
243STDMETHODIMP BandwidthGroup::COMGETTER(Type)(BandwidthGroupType_T *aType)
244{
245 CheckComArgOutPointerValid(aType);
246
247 AutoCaller autoCaller(this);
248 if (FAILED(autoCaller.rc())) return autoCaller.rc();
249
250 /* type is constant during life time, no need to lock */
251 *aType = m->bd->enmType;
252
253 return S_OK;
254}
255
256STDMETHODIMP BandwidthGroup::COMGETTER(Reference)(ULONG *aReferences)
257{
258 CheckComArgOutPointerValid(aReferences);
259
260 AutoCaller autoCaller(this);
261 if (FAILED(autoCaller.rc())) return autoCaller.rc();
262
263 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
264
265 *aReferences = m->bd->cReferences;
266
267 return S_OK;
268}
269
270STDMETHODIMP BandwidthGroup::COMGETTER(MaxMbPerSec)(ULONG *aMaxMbPerSec)
271{
272 CheckComArgOutPointerValid(aMaxMbPerSec);
273
274 AutoCaller autoCaller(this);
275 if (FAILED(autoCaller.rc())) return autoCaller.rc();
276
277 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
278
279 *aMaxMbPerSec = m->bd->aMaxMbPerSec;
280
281 return S_OK;
282}
283
284STDMETHODIMP BandwidthGroup::COMSETTER(MaxMbPerSec)(ULONG aMaxMbPerSec)
285{
286 AutoCaller autoCaller(this);
287 if (FAILED(autoCaller.rc())) return autoCaller.rc();
288
289 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
290
291 m->bd.backup();
292 m->bd->aMaxMbPerSec = aMaxMbPerSec;
293
294 /* inform direct session if any. */
295 ComObjPtr<Machine> pMachine = m->pParent->getMachine();
296 alock.release();
297 pMachine->onBandwidthGroupChange(this);
298
299 return S_OK;
300}
301
302// public methods only for internal purposes
303/////////////////////////////////////////////////////////////////////////////
304
305/** @note Locks objects for writing! */
306void BandwidthGroup::rollback()
307{
308 AutoCaller autoCaller(this);
309 AssertComRCReturnVoid(autoCaller.rc());
310
311 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
312
313 m->bd.rollback();
314}
315
316/**
317 * @note Locks this object for writing, together with the peer object (also
318 * for writing) if there is one.
319 */
320void BandwidthGroup::commit()
321{
322 /* sanity */
323 AutoCaller autoCaller(this);
324 AssertComRCReturnVoid (autoCaller.rc());
325
326 /* sanity too */
327 AutoCaller peerCaller (m->pPeer);
328 AssertComRCReturnVoid (peerCaller.rc());
329
330 /* lock both for writing since we modify both (m->pPeer is "master" so locked
331 * first) */
332 AutoMultiWriteLock2 alock(m->pPeer, this COMMA_LOCKVAL_SRC_POS);
333
334 if (m->bd.isBackedUp())
335 {
336 m->bd.commit();
337 if (m->pPeer)
338 {
339 // attach new data to the peer and reshare it
340 m->pPeer->m->bd.attach (m->bd);
341 }
342 }
343}
344
345
346/**
347 * Cancels sharing (if any) by making an independent copy of data.
348 * This operation also resets this object's peer to NULL.
349 *
350 * @note Locks this object for writing, together with the peer object
351 * represented by @a aThat (locked for reading).
352 */
353void BandwidthGroup::unshare()
354{
355 /* sanity */
356 AutoCaller autoCaller(this);
357 AssertComRCReturnVoid (autoCaller.rc());
358
359 /* sanity too */
360 AutoCaller peerCaller (m->pPeer);
361 AssertComRCReturnVoid (peerCaller.rc());
362
363 /* peer is not modified, lock it for reading (m->pPeer is "master" so locked
364 * first) */
365 AutoReadLock rl(m->pPeer COMMA_LOCKVAL_SRC_POS);
366 AutoWriteLock wl(this COMMA_LOCKVAL_SRC_POS);
367
368 if (m->bd.isShared())
369 {
370 if (!m->bd.isBackedUp())
371 m->bd.backup();
372
373 m->bd.commit();
374 }
375
376 unconst(m->pPeer) = NULL;
377}
378
379ComObjPtr<BandwidthGroup> BandwidthGroup::getPeer()
380{
381 return m->pPeer;
382}
383
384const Utf8Str& BandwidthGroup::getName() const
385{
386 return m->bd->strName;
387}
388
389BandwidthGroupType_T BandwidthGroup::getType() const
390{
391 return m->bd->enmType;
392}
393
394ULONG BandwidthGroup::getMaxMbPerSec() const
395{
396 return m->bd->aMaxMbPerSec;
397}
398
399ULONG BandwidthGroup::getReferences() const
400{
401 return m->bd->cReferences;
402}
403
404void BandwidthGroup::reference()
405{
406 AutoWriteLock wl(this COMMA_LOCKVAL_SRC_POS);
407 m->bd.backup();
408 m->bd->cReferences++;
409}
410
411void BandwidthGroup::release()
412{
413 AutoWriteLock wl(this COMMA_LOCKVAL_SRC_POS);
414 m->bd.backup();
415 m->bd->cReferences--;
416}
417
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