VirtualBox

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

Last change on this file since 93115 was 93115, checked in by vboxsync, 3 years ago

scm --update-copyright-year

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