VirtualBox

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

Last change on this file since 50427 was 50427, checked in by vboxsync, 11 years ago

Main/BandwidthControl: to me it seems we must not uninit the bandwidth groups here

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

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