VirtualBox

source: vbox/trunk/src/VBox/Main/src-server/BandwidthControlImpl.cpp@ 37989

Last change on this file since 37989 was 35638, checked in by vboxsync, 14 years ago

Main. QT/FE: fix long standing COM issue

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 16.5 KB
Line 
1/** @file
2 *
3 * VirtualBox COM class implementation
4 */
5
6/*
7 * Copyright (C) 2006-2009 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 "BandwidthControlImpl.h"
19#include "BandwidthGroupImpl.h"
20#include "MachineImpl.h"
21#include "Global.h"
22
23#include "AutoStateDep.h"
24#include "AutoCaller.h"
25#include "Logging.h"
26
27#include <iprt/cpp/utils.h>
28
29// defines
30/////////////////////////////////////////////////////////////////////////////
31
32typedef std::list< ComObjPtr<BandwidthGroup> > BandwidthGroupList;
33
34struct BandwidthControl::Data
35{
36 Data(Machine *pMachine)
37 : pParent(pMachine)
38 { }
39
40 ~Data()
41 {};
42
43 Machine * const pParent;
44
45 // peer machine's bandwidth control
46 const ComObjPtr<BandwidthControl> pPeer;
47
48 // the following fields need special backup/rollback/commit handling,
49 // so they cannot be a part of BackupableData
50 Backupable<BandwidthGroupList> llBandwidthGroups;
51};
52
53// constructor / destructor
54/////////////////////////////////////////////////////////////////////////////
55
56HRESULT BandwidthControl::FinalConstruct()
57{
58 return BaseFinalConstruct();
59}
60
61void BandwidthControl::FinalRelease()
62{
63 uninit();
64 BaseFinalRelease();
65}
66
67// public initializer/uninitializer for internal purposes only
68/////////////////////////////////////////////////////////////////////////////
69
70/**
71 * Initializes the bandwidth group object.
72 *
73 * @returns COM result indicator.
74 * @param aParent Pointer to our parent object.
75 * @param aName Name of the storage controller.
76 * @param aInstance Instance number of the storage controller.
77 */
78HRESULT BandwidthControl::init(Machine *aParent)
79{
80 LogFlowThisFunc(("aParent=%p\n", aParent));
81
82 ComAssertRet(aParent, E_INVALIDARG);
83
84 /* Enclose the state transition NotReady->InInit->Ready */
85 AutoInitSpan autoInitSpan(this);
86 AssertReturn(autoInitSpan.isOk(), E_FAIL);
87
88 m = new Data(aParent);
89
90 /* m->pPeer is left null */
91
92 m->llBandwidthGroups.allocate();
93
94 /* Confirm a successful initialization */
95 autoInitSpan.setSucceeded();
96
97 return S_OK;
98}
99
100/**
101 * Initializes the object given another object
102 * (a kind of copy constructor). This object shares data with
103 * the object passed as an argument.
104 *
105 * @note This object must be destroyed before the original object
106 * it shares data with is destroyed.
107 *
108 * @note Locks @a aThat object for writing if @a aReshare is @c true, or for
109 * reading if @a aReshare is false.
110 */
111HRESULT BandwidthControl::init(Machine *aParent,
112 BandwidthControl *aThat)
113{
114 LogFlowThisFunc(("aParent=%p, aThat=%p\n", aParent, aThat));
115
116 ComAssertRet(aParent && aThat, E_INVALIDARG);
117
118 /* Enclose the state transition NotReady->InInit->Ready */
119 AutoInitSpan autoInitSpan(this);
120 AssertReturn(autoInitSpan.isOk(), E_FAIL);
121
122 m = new Data(aParent);
123
124 /* sanity */
125 AutoCaller thatCaller(aThat);
126 AssertComRCReturnRC(thatCaller.rc());
127
128 unconst(m->pPeer) = aThat;
129 AutoWriteLock thatLock(aThat COMMA_LOCKVAL_SRC_POS);
130
131 /* create copies of all groups */
132 m->llBandwidthGroups.allocate();
133 BandwidthGroupList::const_iterator it = aThat->m->llBandwidthGroups->begin();
134 while (it != aThat->m->llBandwidthGroups->end())
135 {
136 ComObjPtr<BandwidthGroup> group;
137 group.createObject();
138 group->init(this, *it);
139 m->llBandwidthGroups->push_back(group);
140 ++ it;
141 }
142
143 /* Confirm successful initialization */
144 autoInitSpan.setSucceeded();
145
146 return S_OK;
147}
148
149/**
150 * Initializes the storage controller object given another guest object
151 * (a kind of copy constructor). This object makes a private copy of data
152 * of the original object passed as an argument.
153 */
154HRESULT BandwidthControl::initCopy(Machine *aParent, BandwidthControl *aThat)
155{
156 LogFlowThisFunc(("aParent=%p, aThat=%p\n", aParent, aThat));
157
158 ComAssertRet(aParent && aThat, E_INVALIDARG);
159
160 /* Enclose the state transition NotReady->InInit->Ready */
161 AutoInitSpan autoInitSpan(this);
162 AssertReturn(autoInitSpan.isOk(), E_FAIL);
163
164 m = new Data(aParent);
165 /* m->pPeer is left null */
166
167 AutoCaller thatCaller(aThat);
168 AssertComRCReturnRC(thatCaller.rc());
169
170 AutoReadLock thatlock(aThat COMMA_LOCKVAL_SRC_POS);
171
172 /* create copies of all groups */
173 m->llBandwidthGroups.allocate();
174 BandwidthGroupList::const_iterator it = aThat->m->llBandwidthGroups->begin();
175 while (it != aThat->m->llBandwidthGroups->end())
176 {
177 ComObjPtr<BandwidthGroup> group;
178 group.createObject();
179 group->init(this, *it);
180 m->llBandwidthGroups->push_back(group);
181 ++ it;
182 }
183
184 /* Confirm a successful initialization */
185 autoInitSpan.setSucceeded();
186
187 return S_OK;
188}
189
190
191/**
192 * @note Locks this object for writing, together with the peer object
193 * represented by @a aThat (locked for reading).
194 */
195void BandwidthControl::copyFrom (BandwidthControl *aThat)
196{
197 AssertReturnVoid (aThat != NULL);
198
199 /* sanity */
200 AutoCaller autoCaller(this);
201 AssertComRCReturnVoid (autoCaller.rc());
202
203 /* sanity too */
204 AutoCaller thatCaller (aThat);
205 AssertComRCReturnVoid (thatCaller.rc());
206
207 /* even more sanity */
208 AutoAnyStateDependency adep(m->pParent);
209 AssertComRCReturnVoid (adep.rc());
210 /* Machine::copyFrom() may not be called when the VM is running */
211 AssertReturnVoid (!Global::IsOnline (adep.machineState()));
212
213 /* peer is not modified, lock it for reading (aThat is "master" so locked
214 * first) */
215 AutoReadLock rl(aThat COMMA_LOCKVAL_SRC_POS);
216 AutoWriteLock wl(this COMMA_LOCKVAL_SRC_POS);
217
218 /* create private copies of all filters */
219 m->llBandwidthGroups.backup();
220 m->llBandwidthGroups->clear();
221 for (BandwidthGroupList::const_iterator it = aThat->m->llBandwidthGroups->begin();
222 it != aThat->m->llBandwidthGroups->end();
223 ++ it)
224 {
225 ComObjPtr<BandwidthGroup> group;
226 group.createObject();
227 group->initCopy (this, *it);
228 m->llBandwidthGroups->push_back (group);
229 }
230}
231
232/** @note Locks objects for writing! */
233void BandwidthControl::rollback()
234{
235 AutoCaller autoCaller(this);
236 AssertComRCReturnVoid(autoCaller.rc());
237
238 /* we need the machine state */
239 AutoAnyStateDependency adep(m->pParent);
240 AssertComRCReturnVoid(adep.rc());
241
242 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
243
244 if (!m->llBandwidthGroups.isNull())
245 {
246 if (m->llBandwidthGroups.isBackedUp())
247 {
248 /* unitialize all new groups (absent in the backed up list). */
249 BandwidthGroupList::const_iterator it = m->llBandwidthGroups->begin();
250 BandwidthGroupList *backedList = m->llBandwidthGroups.backedUpData();
251 while (it != m->llBandwidthGroups->end())
252 {
253 if ( std::find(backedList->begin(), backedList->end(), *it)
254 == backedList->end()
255 )
256 {
257 (*it)->uninit();
258 }
259 ++it;
260 }
261
262 /* restore the list */
263 m->llBandwidthGroups.rollback();
264 }
265
266 /* rollback any changes to groups after restoring the list */
267 BandwidthGroupList::const_iterator it = m->llBandwidthGroups->begin();
268 while (it != m->llBandwidthGroups->end())
269 {
270 (*it)->rollback();
271 ++it;
272 }
273 }
274}
275
276void BandwidthControl::commit()
277{
278 bool commitBandwidthGroups = false;
279
280 if (m->llBandwidthGroups.isBackedUp())
281 {
282 m->llBandwidthGroups.commit();
283
284 if (m->pPeer)
285 {
286 AutoWriteLock peerlock(m->pPeer COMMA_LOCKVAL_SRC_POS);
287
288 /* Commit all changes to new controllers (this will reshare data with
289 * peers for those who have peers) */
290 BandwidthGroupList *newList = new BandwidthGroupList();
291 BandwidthGroupList::const_iterator it = m->llBandwidthGroups->begin();
292 while (it != m->llBandwidthGroups->end())
293 {
294 (*it)->commit();
295
296 /* look if this group has a peer group */
297 ComObjPtr<BandwidthGroup> peer = (*it)->getPeer();
298 if (!peer)
299 {
300 /* no peer means the device is a newly created one;
301 * create a peer owning data this device share it with */
302 peer.createObject();
303 peer->init(m->pPeer, *it, true /* aReshare */);
304 }
305 else
306 {
307 /* remove peer from the old list */
308 m->pPeer->m->llBandwidthGroups->remove(peer);
309 }
310 /* and add it to the new list */
311 newList->push_back(peer);
312
313 ++it;
314 }
315
316 /* uninit old peer's controllers that are left */
317 it = m->pPeer->m->llBandwidthGroups->begin();
318 while (it != m->pPeer->m->llBandwidthGroups->end())
319 {
320 (*it)->uninit();
321 ++it;
322 }
323
324 /* attach new list of controllers to our peer */
325 m->pPeer->m->llBandwidthGroups.attach(newList);
326 }
327 else
328 {
329 /* we have no peer (our parent is the newly created machine);
330 * just commit changes to devices */
331 commitBandwidthGroups = true;
332 }
333 }
334 else
335 {
336 /* the list of groups itself is not changed,
337 * just commit changes to controllers themselves */
338 commitBandwidthGroups = true;
339 }
340
341 if (commitBandwidthGroups)
342 {
343 BandwidthGroupList::const_iterator it = m->llBandwidthGroups->begin();
344 while (it != m->llBandwidthGroups->end())
345 {
346 (*it)->commit();
347 ++it;
348 }
349 }
350}
351
352/**
353 * Uninitializes the instance and sets the ready flag to FALSE.
354 * Called either from FinalRelease() or by the parent when it gets destroyed.
355 */
356void BandwidthControl::uninit()
357{
358 LogFlowThisFunc(("\n"));
359
360 /* Enclose the state transition Ready->InUninit->NotReady */
361 AutoUninitSpan autoUninitSpan(this);
362 if (autoUninitSpan.uninitDone())
363 return;
364
365 // uninit all groups on the list (it's a standard std::list not an ObjectsList
366 // so we must uninit() manually)
367 for (BandwidthGroupList::iterator it = m->llBandwidthGroups->begin();
368 it != m->llBandwidthGroups->end();
369 ++it)
370 (*it)->uninit();
371
372 m->llBandwidthGroups.free();
373
374 unconst(m->pPeer) = NULL;
375 unconst(m->pParent) = NULL;
376
377 delete m;
378 m = NULL;
379}
380
381/**
382 * Returns a storage controller object with the given name.
383 *
384 * @param aName storage controller name to find
385 * @param aStorageController where to return the found storage controller
386 * @param aSetError true to set extended error info on failure
387 */
388HRESULT BandwidthControl::getBandwidthGroupByName(const Utf8Str &aName,
389 ComObjPtr<BandwidthGroup> &aBandwidthGroup,
390 bool aSetError /* = false */)
391{
392 AssertReturn(!aName.isEmpty(), E_INVALIDARG);
393
394 for (BandwidthGroupList::const_iterator it = m->llBandwidthGroups->begin();
395 it != m->llBandwidthGroups->end();
396 ++it)
397 {
398 if ((*it)->getName() == aName)
399 {
400 aBandwidthGroup = (*it);
401 return S_OK;
402 }
403 }
404
405 if (aSetError)
406 return setError(VBOX_E_OBJECT_NOT_FOUND,
407 tr("Could not find a bandwidth group named '%s'"),
408 aName.c_str());
409 return VBOX_E_OBJECT_NOT_FOUND;
410}
411
412STDMETHODIMP BandwidthControl::CreateBandwidthGroup(IN_BSTR aName, BandwidthGroupType_T aType, ULONG aMaxMbPerSec)
413{
414 AutoCaller autoCaller(this);
415 if (FAILED(autoCaller.rc())) return autoCaller.rc();
416
417 /* the machine needs to be mutable */
418 AutoMutableStateDependency adep(m->pParent);
419 if (FAILED(adep.rc())) return adep.rc();
420
421 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
422
423 /* try to find one with the name first. */
424 ComObjPtr<BandwidthGroup> group;
425
426 HRESULT rc = getBandwidthGroupByName(aName, group, false /* aSetError */);
427 if (SUCCEEDED(rc))
428 return setError(VBOX_E_OBJECT_IN_USE,
429 tr("Bandwidth group named '%ls' already exists"),
430 aName);
431
432 group.createObject();
433
434 rc = group->init(this, aName, aType, aMaxMbPerSec);
435 if (FAILED(rc)) return rc;
436
437 m->pParent->setModified(Machine::IsModified_BandwidthControl);
438 m->llBandwidthGroups.backup();
439 m->llBandwidthGroups->push_back(group);
440
441 return S_OK;
442}
443
444STDMETHODIMP BandwidthControl::DeleteBandwidthGroup(IN_BSTR aName)
445{
446 CheckComArgStrNotEmptyOrNull(aName);
447
448 AutoCaller autoCaller(this);
449 if (FAILED(autoCaller.rc())) return autoCaller.rc();
450
451 /* the machine needs to be mutable */
452 AutoMutableStateDependency adep(m->pParent);
453 if (FAILED(adep.rc())) return adep.rc();
454
455 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
456
457 ComObjPtr<BandwidthGroup> group;
458 HRESULT rc = getBandwidthGroupByName(aName, group, true /* aSetError */);
459 if (FAILED(rc)) return rc;
460
461 if (group->getReferences() != 0)
462 return setError(VBOX_E_OBJECT_IN_USE,
463 tr("The bandwidth group '%ls' is still in use"), aName);
464
465 /* We can remove it now. */
466 m->pParent->setModified(Machine::IsModified_BandwidthControl);
467 m->llBandwidthGroups.backup();
468
469 group->unshare();
470
471 m->llBandwidthGroups->remove(group);
472
473 /* inform the direct session if any */
474 alock.leave();
475 //onStorageControllerChange(); @todo
476
477 return S_OK;
478}
479
480STDMETHODIMP BandwidthControl::COMGETTER(NumGroups)(ULONG *aGroups)
481{
482 CheckComArgNotNull(aGroups);
483
484 AutoCaller autoCaller(this);
485 if (FAILED(autoCaller.rc())) return autoCaller.rc();
486
487 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
488
489 *aGroups = m->llBandwidthGroups->size();
490
491 return S_OK;
492}
493
494STDMETHODIMP BandwidthControl::GetBandwidthGroup(IN_BSTR aName, IBandwidthGroup **aBandwidthGroup)
495{
496 CheckComArgStrNotEmptyOrNull(aName);
497
498 AutoCaller autoCaller(this);
499 if (FAILED(autoCaller.rc())) return autoCaller.rc();
500
501 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
502
503 ComObjPtr<BandwidthGroup> group;
504
505 HRESULT rc = getBandwidthGroupByName(aName, group, true /* aSetError */);
506 if (SUCCEEDED(rc))
507 group.queryInterfaceTo(aBandwidthGroup);
508
509 return rc;
510}
511
512STDMETHODIMP BandwidthControl::GetAllBandwidthGroups(ComSafeArrayOut(IBandwidthGroup *, aBandwidthGroups))
513{
514 CheckComArgOutSafeArrayPointerValid(aBandwidthGroups);
515
516 AutoCaller autoCaller(this);
517 if (FAILED(autoCaller.rc())) return autoCaller.rc();
518
519 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
520
521 SafeIfaceArray<IBandwidthGroup> collection (*m->llBandwidthGroups.data());
522 collection.detachTo(ComSafeArrayOutArg(aBandwidthGroups));
523
524 return S_OK;
525}
526
527HRESULT BandwidthControl::loadSettings(const settings::IoSettings &data)
528{
529 HRESULT rc = S_OK;
530
531 AutoCaller autoCaller(this);
532 AssertComRCReturnRC(autoCaller.rc());
533
534 for (settings::BandwidthGroupList::const_iterator it = data.llBandwidthGroups.begin();
535 it != data.llBandwidthGroups.end();
536 ++it)
537 {
538 const settings::BandwidthGroup &gr = *it;
539 rc = CreateBandwidthGroup(Bstr(gr.strName).raw(), gr.enmType, gr.cMaxMbPerSec);
540 if (FAILED(rc)) break;
541 }
542
543 return rc;
544}
545
546HRESULT BandwidthControl::saveSettings(settings::IoSettings &data)
547{
548 AutoCaller autoCaller(this);
549 if (FAILED(autoCaller.rc())) return autoCaller.rc();
550
551 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
552
553 data.llBandwidthGroups.clear();
554
555 for (BandwidthGroupList::const_iterator it = m->llBandwidthGroups->begin();
556 it != m->llBandwidthGroups->end();
557 ++it)
558 {
559 AutoWriteLock groupLock(*it COMMA_LOCKVAL_SRC_POS);
560 settings::BandwidthGroup group;
561
562 group.strName = (*it)->getName();
563 group.enmType = (*it)->getType();
564 group.cMaxMbPerSec = (*it)->getMaxMbPerSec();
565
566 data.llBandwidthGroups.push_back(group);
567 }
568
569 return S_OK;
570}
571
572Machine * BandwidthControl::getMachine() const
573{
574 return m->pParent;
575}
576
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