VirtualBox

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

Last change on this file since 42719 was 42551, checked in by vboxsync, 12 years ago

Main: big API naming cleanup, use all caps acronyms everywhere, including SDK docs
Frontends/VBoxManage: implement guestcontrol execute for new API, disabled by default

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 16.6 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 "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, LONG64 aMaxBytesPerSec)
413{
414 if (aMaxBytesPerSec < 0)
415 return setError(E_INVALIDARG,
416 tr("Bandwidth group limit cannot be negative"));
417
418 AutoCaller autoCaller(this);
419 if (FAILED(autoCaller.rc())) return autoCaller.rc();
420
421 /* the machine needs to be mutable */
422 AutoMutableStateDependency adep(m->pParent);
423 if (FAILED(adep.rc())) return adep.rc();
424
425 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
426
427 /* try to find one with the name first. */
428 ComObjPtr<BandwidthGroup> group;
429
430 HRESULT rc = getBandwidthGroupByName(aName, group, false /* aSetError */);
431 if (SUCCEEDED(rc))
432 return setError(VBOX_E_OBJECT_IN_USE,
433 tr("Bandwidth group named '%ls' already exists"),
434 aName);
435
436 group.createObject();
437
438 rc = group->init(this, aName, aType, aMaxBytesPerSec);
439 if (FAILED(rc)) return rc;
440
441 m->pParent->setModified(Machine::IsModified_BandwidthControl);
442 m->llBandwidthGroups.backup();
443 m->llBandwidthGroups->push_back(group);
444
445 return S_OK;
446}
447
448STDMETHODIMP BandwidthControl::DeleteBandwidthGroup(IN_BSTR aName)
449{
450 CheckComArgStrNotEmptyOrNull(aName);
451
452 AutoCaller autoCaller(this);
453 if (FAILED(autoCaller.rc())) return autoCaller.rc();
454
455 /* the machine needs to be mutable */
456 AutoMutableStateDependency adep(m->pParent);
457 if (FAILED(adep.rc())) return adep.rc();
458
459 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
460
461 ComObjPtr<BandwidthGroup> group;
462 HRESULT rc = getBandwidthGroupByName(aName, group, true /* aSetError */);
463 if (FAILED(rc)) return rc;
464
465 if (group->getReferences() != 0)
466 return setError(VBOX_E_OBJECT_IN_USE,
467 tr("The bandwidth group '%ls' is still in use"), aName);
468
469 /* We can remove it now. */
470 m->pParent->setModified(Machine::IsModified_BandwidthControl);
471 m->llBandwidthGroups.backup();
472
473 group->unshare();
474
475 m->llBandwidthGroups->remove(group);
476
477 /* inform the direct session if any */
478 alock.release();
479 //onStorageControllerChange(); @todo
480
481 return S_OK;
482}
483
484STDMETHODIMP BandwidthControl::COMGETTER(NumGroups)(ULONG *aGroups)
485{
486 CheckComArgNotNull(aGroups);
487
488 AutoCaller autoCaller(this);
489 if (FAILED(autoCaller.rc())) return autoCaller.rc();
490
491 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
492
493 *aGroups = m->llBandwidthGroups->size();
494
495 return S_OK;
496}
497
498STDMETHODIMP BandwidthControl::GetBandwidthGroup(IN_BSTR aName, IBandwidthGroup **aBandwidthGroup)
499{
500 CheckComArgStrNotEmptyOrNull(aName);
501
502 AutoCaller autoCaller(this);
503 if (FAILED(autoCaller.rc())) return autoCaller.rc();
504
505 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
506
507 ComObjPtr<BandwidthGroup> group;
508
509 HRESULT rc = getBandwidthGroupByName(aName, group, true /* aSetError */);
510 if (SUCCEEDED(rc))
511 group.queryInterfaceTo(aBandwidthGroup);
512
513 return rc;
514}
515
516STDMETHODIMP BandwidthControl::GetAllBandwidthGroups(ComSafeArrayOut(IBandwidthGroup *, aBandwidthGroups))
517{
518 CheckComArgOutSafeArrayPointerValid(aBandwidthGroups);
519
520 AutoCaller autoCaller(this);
521 if (FAILED(autoCaller.rc())) return autoCaller.rc();
522
523 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
524
525 SafeIfaceArray<IBandwidthGroup> collection (*m->llBandwidthGroups.data());
526 collection.detachTo(ComSafeArrayOutArg(aBandwidthGroups));
527
528 return S_OK;
529}
530
531HRESULT BandwidthControl::loadSettings(const settings::IOSettings &data)
532{
533 HRESULT rc = S_OK;
534
535 AutoCaller autoCaller(this);
536 AssertComRCReturnRC(autoCaller.rc());
537
538 for (settings::BandwidthGroupList::const_iterator it = data.llBandwidthGroups.begin();
539 it != data.llBandwidthGroups.end();
540 ++it)
541 {
542 const settings::BandwidthGroup &gr = *it;
543 rc = CreateBandwidthGroup(Bstr(gr.strName).raw(), gr.enmType, gr.cMaxBytesPerSec);
544 if (FAILED(rc)) break;
545 }
546
547 return rc;
548}
549
550HRESULT BandwidthControl::saveSettings(settings::IOSettings &data)
551{
552 AutoCaller autoCaller(this);
553 if (FAILED(autoCaller.rc())) return autoCaller.rc();
554
555 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
556
557 data.llBandwidthGroups.clear();
558
559 for (BandwidthGroupList::const_iterator it = m->llBandwidthGroups->begin();
560 it != m->llBandwidthGroups->end();
561 ++it)
562 {
563 AutoWriteLock groupLock(*it COMMA_LOCKVAL_SRC_POS);
564 settings::BandwidthGroup group;
565
566 group.strName = (*it)->getName();
567 group.enmType = (*it)->getType();
568 group.cMaxBytesPerSec = (*it)->getMaxBytesPerSec();
569
570 data.llBandwidthGroups.push_back(group);
571 }
572
573 return S_OK;
574}
575
576Machine * BandwidthControl::getMachine() const
577{
578 return m->pParent;
579}
580
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