VirtualBox

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

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

Main: do not include VirtualBoxImpl.h from code ending in VBoxC (causes unnecessary rebuilds), and make sure that the code still builds with VBOX_WITH_RESOURCE_USAGE_API unset

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