diff options
| author | Felix Geyer <fgeyer@debian.org> | 2014-04-05 22:17:15 +0200 |
|---|---|---|
| committer | Felix Geyer <fgeyer@debian.org> | 2014-04-05 22:17:15 +0200 |
| commit | 1700c7d32f7d9d101cbba9f1fcb8bb57ed16a727 (patch) | |
| tree | 727251ad65172262944f82bb0f28601c3fb6f6b3 /src/VBox/Main | |
| parent | 1e85aed889b772c2f2daa7a6d9e8bd967aa213d8 (diff) | |
| download | virtualbox-upstream.tar.gz | |
Imported Upstream version 4.3.10-dfsgupstream/4.3.10-dfsgupstream
Diffstat (limited to 'src/VBox/Main')
23 files changed, 661 insertions, 722 deletions
diff --git a/src/VBox/Main/include/ApplianceImpl.h b/src/VBox/Main/include/ApplianceImpl.h index 7080d14c2..937ebbfd1 100644 --- a/src/VBox/Main/include/ApplianceImpl.h +++ b/src/VBox/Main/include/ApplianceImpl.h @@ -264,6 +264,7 @@ struct VirtualSystemDescriptionEntry Utf8Str strExtraConfigCurrent; // extra configuration key=value strings (type-dependent); current value, either from interpret() or setFinalValue() uint32_t ulSizeMB; // hard disk images only: a copy of ovf::DiskImage::ulSuggestedSizeMB + bool skipIt; ///< used during export to skip some parts if it's needed }; class ATL_NO_VTABLE VirtualSystemDescription : diff --git a/src/VBox/Main/include/ConsoleImpl.h b/src/VBox/Main/include/ConsoleImpl.h index 220ff7bc3..5e5cb6965 100644 --- a/src/VBox/Main/include/ConsoleImpl.h +++ b/src/VBox/Main/include/ConsoleImpl.h @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2005-2013 Oracle Corporation + * Copyright (C) 2005-2014 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -540,6 +540,9 @@ private: HRESULT createSharedFolder(const Utf8Str &strName, const SharedFolderData &aData); HRESULT removeSharedFolder(const Utf8Str &strName); + HRESULT suspendBeforeConfigChange(PUVM pUVM, AutoWriteLock *pAlock, bool *pfResume); + void resumeAfterConfigChange(PUVM pUVM); + static DECLCALLBACK(int) configConstructor(PUVM pUVM, PVM pVM, void *pvConsole); int configConstructorInner(PUVM pUVM, PVM pVM, AutoWriteLock *pAlock); int configCfgmOverlay(PCFGMNODE pRoot, IVirtualBox *pVirtualBox, IMachine *pMachine); @@ -567,7 +570,8 @@ private: bool fForceUnmount, bool fHotplug, PUVM pUVM, - DeviceType_T *paLedDevType); + DeviceType_T *paLedDevType, + PCFGMNODE *ppLunL0); int configMedium(PCFGMNODE pLunL0, bool fPassthrough, DeviceType_T enmType, @@ -581,7 +585,7 @@ private: IMedium *pMedium, MachineState_T aMachineState, HRESULT *phrc); - static DECLCALLBACK(int) reconfigureMediumAttachment(Console *pConsole, + static DECLCALLBACK(int) reconfigureMediumAttachment(Console *pThis, PUVM pUVM, const char *pcszDevice, unsigned uInstance, diff --git a/src/VBox/Main/include/DisplayImpl.h b/src/VBox/Main/include/DisplayImpl.h index b1239ca43..4bc1415a4 100644 --- a/src/VBox/Main/include/DisplayImpl.h +++ b/src/VBox/Main/include/DisplayImpl.h @@ -166,14 +166,15 @@ public: int handleVHWACommandProcess(PVBOXVHWACMD pCommand); #endif #ifdef VBOX_WITH_CRHGSMI - int handleCrCmdNotifyCmds(); void handleCrHgsmiCommandProcess(PVBOXVDMACMD_CHROMIUM_CMD pCmd, uint32_t cbCmd); void handleCrHgsmiControlProcess(PVBOXVDMACMD_CHROMIUM_CTL pCtl, uint32_t cbCtl); void handleCrHgsmiCommandCompletion(int32_t result, uint32_t u32Function, PVBOXHGCMSVCPARM pParam); void handleCrHgsmiControlCompletion(int32_t result, uint32_t u32Function, PVBOXHGCMSVCPARM pParam); #endif - + int handleCrHgcmCtlSubmit(struct VBOXCRCMDCTL* pCmd, uint32_t cbCmd, + PFNCRCTLCOMPLETION pfnCompletion, + void *pvCompletion); #if defined(VBOX_WITH_HGCM) && defined(VBOX_WITH_CROGL) void handleCrAsyncCmdCompletion(int32_t result, uint32_t u32Function, PVBOXHGCMSVCPARM pParam); void handleCrVRecScreenshotPerform(uint32_t uScreen, @@ -264,14 +265,17 @@ private: #endif #ifdef VBOX_WITH_CRHGSMI - static DECLCALLBACK(int) displayCrCmdNotifyCmds(PPDMIDISPLAYCONNECTOR pInterface); static DECLCALLBACK(void) displayCrHgsmiCommandProcess(PPDMIDISPLAYCONNECTOR pInterface, PVBOXVDMACMD_CHROMIUM_CMD pCmd, uint32_t cbCmd); static DECLCALLBACK(void) displayCrHgsmiControlProcess(PPDMIDISPLAYCONNECTOR pInterface, PVBOXVDMACMD_CHROMIUM_CTL pCtl, uint32_t cbCtl); static DECLCALLBACK(void) displayCrHgsmiCommandCompletion(int32_t result, uint32_t u32Function, PVBOXHGCMSVCPARM pParam, void *pvContext); static DECLCALLBACK(void) displayCrHgsmiControlCompletion(int32_t result, uint32_t u32Function, PVBOXHGCMSVCPARM pParam, void *pvContext); #endif - + static DECLCALLBACK(int) displayCrHgcmCtlSubmit(PPDMIDISPLAYCONNECTOR pInterface, + struct VBOXCRCMDCTL* pCmd, uint32_t cbCmd, + PFNCRCTLCOMPLETION pfnCompletion, + void *pvCompletion); + static DECLCALLBACK(void) displayCrHgcmCtlSubmitCompletion(int32_t result, uint32_t u32Function, PVBOXHGCMSVCPARM pParam, void *pvContext); #ifdef VBOX_WITH_HGSMI static DECLCALLBACK(int) displayVBVAEnable(PPDMIDISPLAYCONNECTOR pInterface, unsigned uScreenId, PVBVAHOSTFLAGS pHostFlags); static DECLCALLBACK(void) displayVBVADisable(PPDMIDISPLAYCONNECTOR pInterface, unsigned uScreenId); diff --git a/src/VBox/Main/include/EventImpl.h b/src/VBox/Main/include/EventImpl.h index e2979ce64..414ce013a 100644 --- a/src/VBox/Main/include/EventImpl.h +++ b/src/VBox/Main/include/EventImpl.h @@ -144,7 +144,7 @@ public: void FinalRelease(); // public initializer/uninitializer for internal purposes only - HRESULT init(IUnknown *aParent); + HRESULT init(); void uninit(); // IEventSource methods diff --git a/src/VBox/Main/include/MachineImpl.h b/src/VBox/Main/include/MachineImpl.h index cea78f32a..0ad426594 100644 --- a/src/VBox/Main/include/MachineImpl.h +++ b/src/VBox/Main/include/MachineImpl.h @@ -1219,6 +1219,8 @@ private: /** client token for this machine */ ClientToken *mClientToken; + int miNATNetworksStarted; + static DECLCALLBACK(int) taskHandler(RTTHREAD thread, void *pvUser); }; diff --git a/src/VBox/Main/src-all/EventImpl.cpp b/src/VBox/Main/src-all/EventImpl.cpp index 0d19c3bdb..820f84b93 100644 --- a/src/VBox/Main/src-all/EventImpl.cpp +++ b/src/VBox/Main/src-all/EventImpl.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2010-2012 Oracle Corporation + * Copyright (C) 2010-2014 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -120,7 +120,7 @@ HRESULT VBoxEvent::init(IEventSource *aSource, VBoxEventType_T aType, BOOL aWait if (RT_FAILURE(vrc)) { - AssertFailed (); + AssertFailed(); return setError(E_FAIL, tr("Internal error (%Rrc)"), vrc); } @@ -155,19 +155,21 @@ STDMETHODIMP VBoxEvent::COMGETTER(Type)(VBoxEventType_T *aType) CheckComArgNotNull(aType); AutoCaller autoCaller(this); - if (FAILED(autoCaller.rc())) return autoCaller.rc(); + if (FAILED(autoCaller.rc())) + return autoCaller.rc(); - // never changes till event alive, no locking? + // never changes while event alive, no locking *aType = m->mType; return S_OK; } -STDMETHODIMP VBoxEvent::COMGETTER(Source)(IEventSource* *aSource) +STDMETHODIMP VBoxEvent::COMGETTER(Source)(IEventSource **aSource) { CheckComArgOutPointerValid(aSource); AutoCaller autoCaller(this); - if (FAILED(autoCaller.rc())) return autoCaller.rc(); + if (FAILED(autoCaller.rc())) + return autoCaller.rc(); m->mSource.queryInterfaceTo(aSource); return S_OK; @@ -178,9 +180,10 @@ STDMETHODIMP VBoxEvent::COMGETTER(Waitable)(BOOL *aWaitable) CheckComArgNotNull(aWaitable); AutoCaller autoCaller(this); - if (FAILED(autoCaller.rc())) return autoCaller.rc(); + if (FAILED(autoCaller.rc())) + return autoCaller.rc(); - // never changes till event alive, no locking? + // never changes while event alive, no locking *aWaitable = m->mWaitable; return S_OK; } @@ -189,7 +192,8 @@ STDMETHODIMP VBoxEvent::COMGETTER(Waitable)(BOOL *aWaitable) STDMETHODIMP VBoxEvent::SetProcessed() { AutoCaller autoCaller(this); - if (FAILED(autoCaller.rc())) return autoCaller.rc(); + if (FAILED(autoCaller.rc())) + return autoCaller.rc(); AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); @@ -209,7 +213,8 @@ STDMETHODIMP VBoxEvent::WaitProcessed(LONG aTimeout, BOOL *aResult) CheckComArgNotNull(aResult); AutoCaller autoCaller(this); - if (FAILED(autoCaller.rc())) return autoCaller.rc(); + if (FAILED(autoCaller.rc())) + return autoCaller.rc(); { AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); @@ -249,8 +254,7 @@ STDMETHODIMP VBoxEvent::WaitProcessed(LONG aTimeout, BOOL *aResult) typedef std::list<Bstr> VetoList; struct VBoxVetoEvent::Data { - Data() - : + Data() : mVetoed(FALSE) {} BOOL mVetoed; @@ -281,7 +285,8 @@ HRESULT VBoxVetoEvent::init(IEventSource *aSource, VBoxEventType_T aType) HRESULT rc = S_OK; // all veto events are waitable rc = VBoxEvent::init(aSource, aType, TRUE); - if (FAILED(rc)) return rc; + if (FAILED(rc)) + return rc; m->mVetoed = FALSE; m->mVetoList.clear(); @@ -300,7 +305,8 @@ void VBoxVetoEvent::uninit() STDMETHODIMP VBoxVetoEvent::AddVeto(IN_BSTR aVeto) { AutoCaller autoCaller(this); - if (FAILED(autoCaller.rc())) return autoCaller.rc(); + if (FAILED(autoCaller.rc())) + return autoCaller.rc(); AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); @@ -312,12 +318,13 @@ STDMETHODIMP VBoxVetoEvent::AddVeto(IN_BSTR aVeto) return S_OK; } -STDMETHODIMP VBoxVetoEvent::IsVetoed(BOOL * aResult) +STDMETHODIMP VBoxVetoEvent::IsVetoed(BOOL *aResult) { CheckComArgOutPointerValid(aResult); AutoCaller autoCaller(this); - if (FAILED(autoCaller.rc())) return autoCaller.rc(); + if (FAILED(autoCaller.rc())) + return autoCaller.rc(); AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); @@ -326,13 +333,14 @@ STDMETHODIMP VBoxVetoEvent::IsVetoed(BOOL * aResult) return S_OK; } -STDMETHODIMP VBoxVetoEvent::GetVetos(ComSafeArrayOut(BSTR, aVetos)) +STDMETHODIMP VBoxVetoEvent::GetVetos(ComSafeArrayOut(BSTR, aVetos)) { if (ComSafeArrayOutIsNull(aVetos)) return E_POINTER; AutoCaller autoCaller(this); - if (FAILED(autoCaller.rc())) return autoCaller.rc(); + if (FAILED(autoCaller.rc())) + return autoCaller.rc(); AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); com::SafeArray<BSTR> vetos(m->mVetoList.size()); @@ -351,8 +359,8 @@ STDMETHODIMP VBoxVetoEvent::GetVetos(ComSafeArrayOut(BSTR, aVetos)) } static const int FirstEvent = (int)VBoxEventType_LastWildcard + 1; -static const int LastEvent = (int)VBoxEventType_Last; -static const int NumEvents = LastEvent - FirstEvent; +static const int LastEvent = (int)VBoxEventType_Last; +static const int NumEvents = LastEvent - FirstEvent; /** * Class replacing std::list and able to provide required stability @@ -367,24 +375,19 @@ public: * We have to be double linked, as structural modifications in list are delayed * till element removed, so we have to know our previous one to update its next */ - EventMapRecord* mNext; + EventMapRecord *mNext; bool mAlive; private: - EventMapRecord* mPrev; - ListenerRecord* mRef; /* must be weak reference */ + EventMapRecord *mPrev; + ListenerRecord *mRef; /* must be weak reference */ int32_t mRefCnt; public: - EventMapRecord(ListenerRecord* aRef) - : - mNext(0), - mAlive(true), - mPrev(0), - mRef(aRef), - mRefCnt(1) + EventMapRecord(ListenerRecord *aRef) : + mNext(0), mAlive(true), mPrev(0), mRef(aRef), mRefCnt(1) {} - EventMapRecord(EventMapRecord& aOther) + EventMapRecord(EventMapRecord &aOther) { mNext = aOther.mNext; mPrev = aOther.mPrev; @@ -408,7 +411,8 @@ public: void release() { - if (ASMAtomicDecS32(&mRefCnt) <= 0) delete this; + if (ASMAtomicDecS32(&mRefCnt) <= 0) + delete this; } // Called when an element is no longer needed @@ -418,7 +422,7 @@ public: release(); } - ListenerRecord* ref() + ListenerRecord *ref() { return mAlive ? mRef : 0; } @@ -473,7 +477,7 @@ public: EventMapRecord *pCur = mHead; while (pCur) { - EventMapRecord* aNext = pCur->mNext; + EventMapRecord *aNext = pCur->mNext; if (pCur->ref() == aRec) { if (pCur == mHead) @@ -495,13 +499,13 @@ public: { EventMapRecord *mCur; - iterator() - : mCur(0) + iterator() : + mCur(0) {} explicit - iterator(EventMapRecord *aCur) - : mCur(aCur) + iterator(EventMapRecord *aCur) : + mCur(aCur) { // Prevent element removal, till we're at it if (mCur) @@ -539,13 +543,13 @@ public: } bool - operator==(const EventMapList::iterator& aOther) const + operator==(const EventMapList::iterator &aOther) const { return mCur == aOther.mCur; } bool - operator!=(const EventMapList::iterator& aOther) const + operator!=(const EventMapList::iterator &aOther) const { return mCur != aOther.mCur; } @@ -563,7 +567,7 @@ public: }; typedef EventMapList EventMap[NumEvents]; -typedef std::map<IEvent*, int32_t> PendingEventsMap; +typedef std::map<IEvent *, int32_t> PendingEventsMap; typedef std::deque<ComPtr<IEvent> > PassiveQueue; class ListenerRecord @@ -571,7 +575,7 @@ class ListenerRecord private: ComPtr<IEventListener> mListener; BOOL mActive; - EventSource* mOwner; + EventSource *mOwner; RTSEMEVENT mQEvent; RTCRITSECT mcsQLock; @@ -580,24 +584,29 @@ private: uint64_t mLastRead; public: - ListenerRecord(IEventListener* aListener, - com::SafeArray<VBoxEventType_T>& aInterested, - BOOL aActive, - EventSource* aOwner); + ListenerRecord(IEventListener *aListener, + com::SafeArray<VBoxEventType_T> &aInterested, + BOOL aActive, + EventSource *aOwner); ~ListenerRecord(); - HRESULT process(IEvent* aEvent, BOOL aWaitable, PendingEventsMap::iterator& pit, AutoLockBase& alock); - HRESULT enqueue(IEvent* aEvent); - HRESULT dequeue(IEvent* *aEvent, LONG aTimeout, AutoLockBase& aAlock); - HRESULT eventProcessed(IEvent * aEvent, PendingEventsMap::iterator& pit); + HRESULT process(IEvent *aEvent, BOOL aWaitable, PendingEventsMap::iterator &pit, AutoLockBase &alock); + HRESULT enqueue(IEvent *aEvent); + HRESULT dequeue(IEvent **aEvent, LONG aTimeout, AutoLockBase &aAlock); + HRESULT eventProcessed(IEvent *aEvent, PendingEventsMap::iterator &pit); + void shutdown(); + void addRef() { ASMAtomicIncS32(&mRefCnt); } + void release() { - if (ASMAtomicDecS32(&mRefCnt) <= 0) delete this; + if (ASMAtomicDecS32(&mRefCnt) <= 0) + delete this; } + BOOL isActive() { return mActive; @@ -611,15 +620,13 @@ template<typename Held> class RecordHolder { public: - RecordHolder(Held* lr) - : - held(lr) + RecordHolder(Held *lr) : + held(lr) { addref(); } - RecordHolder(const RecordHolder& that) - : - held(that.held) + RecordHolder(const RecordHolder &that) : + held(that.held) { addref(); } @@ -633,7 +640,7 @@ public: release(); } - Held* obj() + Held *obj() { return held; } @@ -644,7 +651,7 @@ public: return *this; } private: - Held* held; + Held *held; void addref() { @@ -656,7 +663,7 @@ private: if (held) held->release(); } - void safe_assign (Held *that_p) + void safe_assign(Held *that_p) { if (that_p) that_p->addRef(); @@ -665,14 +672,17 @@ private: } }; -typedef std::map<IEventListener*, RecordHolder<ListenerRecord> > Listeners; +typedef std::map<IEventListener *, RecordHolder<ListenerRecord> > Listeners; struct EventSource::Data { - Data() {} + Data() : fShutdown(false) + {} + Listeners mListeners; EventMap mEvMap; PendingEventsMap mPendingMap; + bool fShutdown; }; /** @@ -685,24 +695,22 @@ static BOOL implies(VBoxEventType_T who, VBoxEventType_T what) case VBoxEventType_Any: return TRUE; case VBoxEventType_Vetoable: - return (what == VBoxEventType_OnExtraDataCanChange) - || (what == VBoxEventType_OnCanShowWindow); + return (what == VBoxEventType_OnExtraDataCanChange) + || (what == VBoxEventType_OnCanShowWindow); case VBoxEventType_MachineEvent: - return (what == VBoxEventType_OnMachineStateChanged) - || (what == VBoxEventType_OnMachineDataChanged) - || (what == VBoxEventType_OnMachineRegistered) - || (what == VBoxEventType_OnSessionStateChanged) - || (what == VBoxEventType_OnGuestPropertyChanged); + return (what == VBoxEventType_OnMachineStateChanged) + || (what == VBoxEventType_OnMachineDataChanged) + || (what == VBoxEventType_OnMachineRegistered) + || (what == VBoxEventType_OnSessionStateChanged) + || (what == VBoxEventType_OnGuestPropertyChanged); case VBoxEventType_SnapshotEvent: - return (what == VBoxEventType_OnSnapshotTaken) - || (what == VBoxEventType_OnSnapshotDeleted) - || (what == VBoxEventType_OnSnapshotChanged) - ; + return (what == VBoxEventType_OnSnapshotTaken) + || (what == VBoxEventType_OnSnapshotDeleted) + || (what == VBoxEventType_OnSnapshotChanged) ; case VBoxEventType_InputEvent: - return (what == VBoxEventType_OnKeyboardLedsChanged) - || (what == VBoxEventType_OnMousePointerShapeChanged) - || (what == VBoxEventType_OnMouseCapabilityChanged) - ; + return (what == VBoxEventType_OnKeyboardLedsChanged) + || (what == VBoxEventType_OnMousePointerShapeChanged) + || (what == VBoxEventType_OnMouseCapabilityChanged); case VBoxEventType_Invalid: return FALSE; default: @@ -712,17 +720,14 @@ static BOOL implies(VBoxEventType_T who, VBoxEventType_T what) return who == what; } -ListenerRecord::ListenerRecord(IEventListener* aListener, - com::SafeArray<VBoxEventType_T>& aInterested, - BOOL aActive, - EventSource* aOwner) - : - mActive(aActive), - mOwner(aOwner), - mRefCnt(0) +ListenerRecord::ListenerRecord(IEventListener *aListener, + com::SafeArray<VBoxEventType_T> &aInterested, + BOOL aActive, + EventSource *aOwner) : + mActive(aActive), mOwner(aOwner), mRefCnt(0) { mListener = aListener; - EventMap* aEvMap = &aOwner->m->mEvMap; + EventMap *aEvMap = &aOwner->m->mEvMap; for (size_t i = 0; i < aInterested.size(); ++i) { @@ -740,12 +745,12 @@ ListenerRecord::ListenerRecord(IEventListener* aListener, if (!mActive) { ::RTCritSectInit(&mcsQLock); - ::RTSemEventCreate (&mQEvent); + ::RTSemEventCreate(&mQEvent); mLastRead = RTTimeMilliTS(); } else { - mQEvent =NIL_RTSEMEVENT; + mQEvent = NIL_RTSEMEVENT; RT_ZERO(mcsQLock); mLastRead = 0; } @@ -754,7 +759,7 @@ ListenerRecord::ListenerRecord(IEventListener* aListener, ListenerRecord::~ListenerRecord() { /* Remove references to us from the event map */ - EventMap* aEvMap = &mOwner->m->mEvMap; + EventMap *aEvMap = &mOwner->m->mEvMap; for (int j = FirstEvent; j < LastEvent; j++) { (*aEvMap)[j - FirstEvent].remove(this); @@ -764,7 +769,7 @@ ListenerRecord::~ListenerRecord() { // at this moment nobody could add elements to our queue, so we can safely // clean it up, otherwise there will be pending events map elements - PendingEventsMap* aPem = &mOwner->m->mPendingMap; + PendingEventsMap *aPem = &mOwner->m->mPendingMap; while (true) { ComPtr<IEvent> aEvent; @@ -786,21 +791,21 @@ ListenerRecord::~ListenerRecord() } ::RTCritSectDelete(&mcsQLock); - ::RTSemEventDestroy(mQEvent); } + shutdown(); } -HRESULT ListenerRecord::process(IEvent* aEvent, - BOOL aWaitable, - PendingEventsMap::iterator& pit, - AutoLockBase& aAlock) +HRESULT ListenerRecord::process(IEvent *aEvent, + BOOL aWaitable, + PendingEventsMap::iterator &pit, + AutoLockBase &aAlock) { if (mActive) { /* * We release lock here to allow modifying ops on EventSource inside callback. */ - HRESULT rc = S_OK; + HRESULT rc = S_OK; if (mListener) { aAlock.release(); @@ -818,7 +823,7 @@ HRESULT ListenerRecord::process(IEvent* aEvent, } -HRESULT ListenerRecord::enqueue (IEvent* aEvent) +HRESULT ListenerRecord::enqueue(IEvent *aEvent) { AssertMsg(!mActive, ("must be passive\n")); @@ -829,7 +834,7 @@ HRESULT ListenerRecord::enqueue (IEvent* aEvent) // and events keep coming, or queue is oversized we shall unregister this listener. uint64_t sinceRead = RTTimeMilliTS() - mLastRead; size_t queueSize = mQueue.size(); - if ( (queueSize > 1000) || ((queueSize > 500) && (sinceRead > 60 * 1000))) + if ((queueSize > 1000) || ((queueSize > 500) && (sinceRead > 60 * 1000))) { ::RTCritSectLeave(&mcsQLock); return E_ABORT; @@ -845,15 +850,15 @@ HRESULT ListenerRecord::enqueue (IEvent* aEvent) ::RTCritSectLeave(&mcsQLock); - // notify waiters + // notify waiters ::RTSemEventSignal(mQEvent); return S_OK; } -HRESULT ListenerRecord::dequeue (IEvent* *aEvent, - LONG aTimeout, - AutoLockBase& aAlock) +HRESULT ListenerRecord::dequeue(IEvent **aEvent, + LONG aTimeout, + AutoLockBase &aAlock) { if (mActive) return VBOX_E_INVALID_OBJECT_STATE; @@ -865,7 +870,8 @@ HRESULT ListenerRecord::dequeue (IEvent* *aEvent, mLastRead = RTTimeMilliTS(); - if (mQueue.empty()) { + if (mQueue.empty()) + { ::RTCritSectLeave(&mcsQLock); // Speed up common case if (aTimeout == 0) @@ -893,7 +899,7 @@ HRESULT ListenerRecord::dequeue (IEvent* *aEvent, return S_OK; } -HRESULT ListenerRecord::eventProcessed (IEvent* aEvent, PendingEventsMap::iterator& pit) +HRESULT ListenerRecord::eventProcessed(IEvent *aEvent, PendingEventsMap::iterator &pit) { if (--pit->second == 0) { @@ -905,6 +911,16 @@ HRESULT ListenerRecord::eventProcessed (IEvent* aEvent, PendingEventsMap::iterat return S_OK; } +void ListenerRecord::shutdown() +{ + if (mQEvent != NIL_RTSEMEVENT) + { + RTSEMEVENT tmp = mQEvent; + mQEvent = NIL_RTSEMEVENT; + ::RTSemEventDestroy(tmp); + } +} + EventSource::EventSource() {} @@ -924,7 +940,7 @@ void EventSource::FinalRelease() BaseFinalRelease(); } -HRESULT EventSource::init(IUnknown *) +HRESULT EventSource::init() { HRESULT rc = S_OK; @@ -938,32 +954,58 @@ HRESULT EventSource::init(IUnknown *) void EventSource::uninit() { + { + // First of all (before even thinking about entering the uninit span): + // make sure that all listeners are are shut down (no pending events or + // wait calls), because they cannot be alive without the associated + // event source. Otherwise API clients which use long-term (or + // indefinite) waits will block VBoxSVC termination (just one example) + // for a long time or even infinitely long. + AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); + if (!m->fShutdown) + { + m->fShutdown = true; + for (Listeners::iterator it = m->mListeners.begin(); + it != m->mListeners.end(); + ++it) + { + it->second.obj()->shutdown(); + } + } + } + AutoUninitSpan autoUninitSpan(this); if (autoUninitSpan.uninitDone()) return; + m->mListeners.clear(); // m->mEvMap shall be cleared at this point too by destructors, assert? } -STDMETHODIMP EventSource::RegisterListener(IEventListener * aListener, +STDMETHODIMP EventSource::RegisterListener(IEventListener *aListener, ComSafeArrayIn(VBoxEventType_T, aInterested), - BOOL aActive) + BOOL aActive) { CheckComArgNotNull(aListener); CheckComArgSafeArrayNotNull(aInterested); AutoCaller autoCaller(this); - if (FAILED(autoCaller.rc())) return autoCaller.rc(); + if (FAILED(autoCaller.rc())) + return autoCaller.rc(); { AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); + if (m->fShutdown) + return setError(VBOX_E_INVALID_OBJECT_STATE, + tr("This event source is already shut down")); + Listeners::const_iterator it = m->mListeners.find(aListener); if (it != m->mListeners.end()) return setError(E_INVALIDARG, tr("This listener already registered")); - com::SafeArray<VBoxEventType_T> interested(ComSafeArrayInArg (aInterested)); + com::SafeArray<VBoxEventType_T> interested(ComSafeArrayInArg(aInterested)); RecordHolder<ListenerRecord> lrh(new ListenerRecord(aListener, interested, aActive, this)); m->mListeners.insert(Listeners::value_type(aListener, lrh)); } @@ -975,12 +1017,13 @@ STDMETHODIMP EventSource::RegisterListener(IEventListener * aListener, return S_OK; } -STDMETHODIMP EventSource::UnregisterListener(IEventListener * aListener) +STDMETHODIMP EventSource::UnregisterListener(IEventListener *aListener) { CheckComArgNotNull(aListener); AutoCaller autoCaller(this); - if (FAILED(autoCaller.rc())) return autoCaller.rc(); + if (FAILED(autoCaller.rc())) + return autoCaller.rc(); HRESULT rc; { @@ -990,6 +1033,7 @@ STDMETHODIMP EventSource::UnregisterListener(IEventListener * aListener) if (it != m->mListeners.end()) { + it->second.obj()->shutdown(); m->mListeners.erase(it); // destructor removes refs from the event map rc = S_OK; @@ -1011,15 +1055,16 @@ STDMETHODIMP EventSource::UnregisterListener(IEventListener * aListener) return rc; } -STDMETHODIMP EventSource::FireEvent(IEvent * aEvent, - LONG aTimeout, - BOOL *aProcessed) +STDMETHODIMP EventSource::FireEvent(IEvent *aEvent, + LONG aTimeout, + BOOL *aProcessed) { CheckComArgNotNull(aEvent); CheckComArgOutPointerValid(aProcessed); AutoCaller autoCaller(this); - if (FAILED(autoCaller.rc())) return autoCaller.rc(); + if (FAILED(autoCaller.rc())) + return autoCaller.rc(); HRESULT hrc; BOOL aWaitable = FALSE; @@ -1028,6 +1073,10 @@ STDMETHODIMP EventSource::FireEvent(IEvent * aEvent, do { AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); + if (m->fShutdown) + return setError(VBOX_E_INVALID_OBJECT_STATE, + tr("This event source is already shut down")); + VBoxEventType_T evType; hrc = aEvent->COMGETTER(Type)(&evType); AssertComRCReturn(hrc, hrc); @@ -1074,7 +1123,10 @@ STDMETHODIMP EventSource::FireEvent(IEvent * aEvent, { Listeners::iterator lit = m->mListeners.find(record.obj()->mListener); if (lit != m->mListeners.end()) + { + lit->second.obj()->shutdown(); m->mListeners.erase(lit); + } } // anything else to do with cbRc? } @@ -1090,18 +1142,23 @@ STDMETHODIMP EventSource::FireEvent(IEvent * aEvent, } -STDMETHODIMP EventSource::GetEvent(IEventListener * aListener, - LONG aTimeout, - IEvent ** aEvent) +STDMETHODIMP EventSource::GetEvent(IEventListener *aListener, + LONG aTimeout, + IEvent **aEvent) { CheckComArgNotNull(aListener); AutoCaller autoCaller(this); - if (FAILED(autoCaller.rc())) return autoCaller.rc(); + if (FAILED(autoCaller.rc())) + return autoCaller.rc(); AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); + if (m->fShutdown) + return setError(VBOX_E_INVALID_OBJECT_STATE, + tr("This event source is already shut down")); + Listeners::iterator it = m->mListeners.find(aListener); HRESULT rc; @@ -1117,17 +1174,22 @@ STDMETHODIMP EventSource::GetEvent(IEventListener * aListener, return rc; } -STDMETHODIMP EventSource::EventProcessed(IEventListener * aListener, - IEvent * aEvent) +STDMETHODIMP EventSource::EventProcessed(IEventListener *aListener, + IEvent *aEvent) { CheckComArgNotNull(aListener); CheckComArgNotNull(aEvent); AutoCaller autoCaller(this); - if (FAILED(autoCaller.rc())) return autoCaller.rc(); + if (FAILED(autoCaller.rc())) + return autoCaller.rc(); AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); + if (m->fShutdown) + return setError(VBOX_E_INVALID_OBJECT_STATE, + tr("This event source is already shut down")); + Listeners::iterator it = m->mListeners.find(aListener); HRESULT rc; @@ -1136,11 +1198,11 @@ STDMETHODIMP EventSource::EventProcessed(IEventListener * aListener, if (it != m->mListeners.end()) { - ListenerRecord* aRecord = it->second.obj(); + ListenerRecord *aRecord = it->second.obj(); if (aRecord->isActive()) return setError(E_INVALIDARG, - tr("Only applicable to passive listeners")); + tr("Only applicable to passive listeners")); if (aWaitable) { @@ -1246,14 +1308,14 @@ public: BaseFinalRelease(); } - HRESULT init(IEventSource* aSource) + HRESULT init(IEventSource *aSource) { mSource = aSource; return S_OK; } // IEventListener methods - STDMETHOD(HandleEvent)(IEvent * aEvent) + STDMETHOD(HandleEvent)(IEvent *aEvent) { BOOL fProcessed = FALSE; if (mSource) @@ -1269,7 +1331,7 @@ class ATL_NO_VTABLE EventSourceAggregator : { typedef std::list <ComPtr<IEventSource> > EventSourceList; /* key is weak reference */ - typedef std::map<IEventListener*, ComPtr<IEventListener> > ProxyListenerMap; + typedef std::map<IEventListener *, ComPtr<IEventListener> > ProxyListenerMap; EventSourceList mEventSources; ProxyListenerMap mListenerProxies; @@ -1308,28 +1370,28 @@ public: HRESULT init(ComSafeArrayIn(IEventSource *, aSources)); // IEventSource methods - STDMETHOD(CreateListener)(IEventListener ** aListener); - STDMETHOD(CreateAggregator)(ComSafeArrayIn(IEventSource*, aSubordinates), - IEventSource ** aAggregator); - STDMETHOD(RegisterListener)(IEventListener * aListener, + STDMETHOD(CreateListener)(IEventListener **aListener); + STDMETHOD(CreateAggregator)(ComSafeArrayIn(IEventSource *, aSubordinates), + IEventSource **aAggregator); + STDMETHOD(RegisterListener)(IEventListener *aListener, ComSafeArrayIn(VBoxEventType_T, aInterested), - BOOL aActive); - STDMETHOD(UnregisterListener)(IEventListener * aListener); - STDMETHOD(FireEvent)(IEvent * aEvent, - LONG aTimeout, - BOOL *aProcessed); - STDMETHOD(GetEvent)(IEventListener * aListener, - LONG aTimeout, - IEvent * *aEvent); - STDMETHOD(EventProcessed)(IEventListener * aListener, - IEvent * aEvent); + BOOL aActive); + STDMETHOD(UnregisterListener)(IEventListener *aListener); + STDMETHOD(FireEvent)(IEvent *aEvent, + LONG aTimeout, + BOOL *aProcessed); + STDMETHOD(GetEvent)(IEventListener *aListener, + LONG aTimeout, + IEvent **aEvent); + STDMETHOD(EventProcessed)(IEventListener *aListener, + IEvent *aEvent); protected: - HRESULT createProxyListener(IEventListener * aListener, - IEventListener * *aProxy); - HRESULT getProxyListener (IEventListener * aListener, - IEventListener * *aProxy); - HRESULT removeProxyListener(IEventListener * aListener); + HRESULT createProxyListener(IEventListener *aListener, + IEventListener **aProxy); + HRESULT getProxyListener(IEventListener *aListener, + IEventListener **aProxy); + HRESULT removeProxyListener(IEventListener *aListener); }; #ifdef VBOX_WITH_XPCOM @@ -1348,12 +1410,13 @@ NS_IMPL_THREADSAFE_ISUPPORTS1_CI(EventSourceAggregator, IEventSource) #endif -STDMETHODIMP EventSource::CreateListener(IEventListener ** aListener) +STDMETHODIMP EventSource::CreateListener(IEventListener **aListener) { CheckComArgOutPointerValid(aListener); AutoCaller autoCaller(this); - if (FAILED(autoCaller.rc())) return autoCaller.rc(); + if (FAILED(autoCaller.rc())) + return autoCaller.rc(); ComObjPtr<PassiveEventListener> listener; @@ -1365,13 +1428,14 @@ STDMETHODIMP EventSource::CreateListener(IEventListener ** aListener) } -STDMETHODIMP EventSource::CreateAggregator(ComSafeArrayIn(IEventSource*, aSubordinates), - IEventSource ** aResult) +STDMETHODIMP EventSource::CreateAggregator(ComSafeArrayIn(IEventSource *, aSubordinates), + IEventSource **aResult) { CheckComArgOutPointerValid(aResult); AutoCaller autoCaller(this); - if (FAILED(autoCaller.rc())) return autoCaller.rc(); + if (FAILED(autoCaller.rc())) + return autoCaller.rc(); ComObjPtr<EventSourceAggregator> agg; @@ -1383,12 +1447,11 @@ STDMETHODIMP EventSource::CreateAggregator(ComSafeArrayIn(IEventSource*, aSubord if (FAILED(rc)) return rc; - agg.queryInterfaceTo(aResult); return S_OK; } -HRESULT EventSourceAggregator::init(ComSafeArrayIn(IEventSource*, aSourcesIn)) +HRESULT EventSourceAggregator::init(ComSafeArrayIn(IEventSource *, aSourcesIn)) { HRESULT rc; @@ -1398,7 +1461,7 @@ HRESULT EventSourceAggregator::init(ComSafeArrayIn(IEventSource*, aSourcesIn)) rc = mSource.createObject(); ComAssertMsgRet(SUCCEEDED(rc), ("Could not create source (%Rhrc)", rc), E_FAIL); - rc = mSource->init((IEventSource*)this); + rc = mSource->init(); ComAssertMsgRet(SUCCEEDED(rc), ("Could not init source (%Rhrc)", rc), E_FAIL); @@ -1418,26 +1481,27 @@ HRESULT EventSourceAggregator::init(ComSafeArrayIn(IEventSource*, aSourcesIn)) return rc; } -STDMETHODIMP EventSourceAggregator::CreateListener(IEventListener ** aListener) +STDMETHODIMP EventSourceAggregator::CreateListener(IEventListener **aListener) { return mSource->CreateListener(aListener); } -STDMETHODIMP EventSourceAggregator::CreateAggregator(ComSafeArrayIn(IEventSource*, aSubordinates), - IEventSource ** aResult) +STDMETHODIMP EventSourceAggregator::CreateAggregator(ComSafeArrayIn(IEventSource *, aSubordinates), + IEventSource **aResult) { return mSource->CreateAggregator(ComSafeArrayInArg(aSubordinates), aResult); } -STDMETHODIMP EventSourceAggregator::RegisterListener(IEventListener * aListener, +STDMETHODIMP EventSourceAggregator::RegisterListener(IEventListener *aListener, ComSafeArrayIn(VBoxEventType_T, aInterested), - BOOL aActive) + BOOL aActive) { CheckComArgNotNull(aListener); CheckComArgSafeArrayNotNull(aInterested); AutoCaller autoCaller(this); - if (FAILED(autoCaller.rc())) return autoCaller.rc(); + if (FAILED(autoCaller.rc())) + return autoCaller.rc(); HRESULT rc; @@ -1462,12 +1526,13 @@ STDMETHODIMP EventSourceAggregator::RegisterListener(IEventListener * aListener, return rc; } -STDMETHODIMP EventSourceAggregator::UnregisterListener(IEventListener * aListener) +STDMETHODIMP EventSourceAggregator::UnregisterListener(IEventListener *aListener) { CheckComArgNotNull(aListener); AutoCaller autoCaller(this); - if (FAILED(autoCaller.rc())) return autoCaller.rc(); + if (FAILED(autoCaller.rc())) + return autoCaller.rc(); HRESULT rc = S_OK; @@ -1490,19 +1555,20 @@ STDMETHODIMP EventSourceAggregator::UnregisterListener(IEventListener * aListene } -STDMETHODIMP EventSourceAggregator::FireEvent(IEvent * aEvent, - LONG aTimeout, - BOOL *aProcessed) +STDMETHODIMP EventSourceAggregator::FireEvent(IEvent *aEvent, + LONG aTimeout, + BOOL *aProcessed) { CheckComArgNotNull(aEvent); CheckComArgOutPointerValid(aProcessed); AutoCaller autoCaller(this); - if (FAILED(autoCaller.rc())) return autoCaller.rc(); + if (FAILED(autoCaller.rc())) + return autoCaller.rc(); HRESULT rc = S_OK; AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); - /* Aggresgator event source shalln't have direct event firing, but we may + /* Aggregator event source shall not have direct event firing, but we may wish to support aggregation chains */ for (EventSourceList::const_iterator it = mEventSources.begin(); it != mEventSources.end(); ++it) @@ -1517,21 +1583,21 @@ STDMETHODIMP EventSourceAggregator::FireEvent(IEvent * aEvent, return S_OK; } -STDMETHODIMP EventSourceAggregator::GetEvent(IEventListener * aListener, - LONG aTimeout, - IEvent ** aEvent) +STDMETHODIMP EventSourceAggregator::GetEvent(IEventListener *aListener, + LONG aTimeout, + IEvent **aEvent) { return mSource->GetEvent(aListener, aTimeout, aEvent); } -STDMETHODIMP EventSourceAggregator::EventProcessed(IEventListener * aListener, - IEvent * aEvent) +STDMETHODIMP EventSourceAggregator::EventProcessed(IEventListener *aListener, + IEvent *aEvent) { return mSource->EventProcessed(aListener, aEvent); } -HRESULT EventSourceAggregator::createProxyListener(IEventListener * aListener, - IEventListener * *aProxy) +HRESULT EventSourceAggregator::createProxyListener(IEventListener *aListener, + IEventListener **aProxy) { ComObjPtr<ProxyEventListener> proxy; @@ -1554,8 +1620,8 @@ HRESULT EventSourceAggregator::createProxyListener(IEventListener * aListener, return S_OK; } -HRESULT EventSourceAggregator::getProxyListener(IEventListener * aListener, - IEventListener * *aProxy) +HRESULT EventSourceAggregator::getProxyListener(IEventListener *aListener, + IEventListener **aProxy) { ProxyListenerMap::const_iterator it = mListenerProxies.find(aListener); if (it == mListenerProxies.end()) @@ -1566,7 +1632,7 @@ HRESULT EventSourceAggregator::getProxyListener(IEventListener * aListener, return S_OK; } -HRESULT EventSourceAggregator::removeProxyListener(IEventListener * aListener) +HRESULT EventSourceAggregator::removeProxyListener(IEventListener *aListener) { ProxyListenerMap::iterator it = mListenerProxies.find(aListener); if (it == mListenerProxies.end()) diff --git a/src/VBox/Main/src-client/ConsoleImpl.cpp b/src/VBox/Main/src-client/ConsoleImpl.cpp index 78d97f7eb..d0c74c245 100644 --- a/src/VBox/Main/src-client/ConsoleImpl.cpp +++ b/src/VBox/Main/src-client/ConsoleImpl.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2005-2013 Oracle Corporation + * Copyright (C) 2005-2014 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -489,7 +489,7 @@ HRESULT Console::init(IMachine *aMachine, IInternalMachineControl *aControl, Loc // Event source may be needed by other children unconst(mEventSource).createObject(); - rc = mEventSource->init(static_cast<IConsole*>(this)); + rc = mEventSource->init(); AssertComRCReturnRC(rc); mcAudioRefs = 0; @@ -2394,7 +2394,7 @@ HRESULT Console::doCPURemove(ULONG aCpu, PUVM pUVM) */ PVMREQ pReq; vrc = VMR3ReqCallU(pUVM, 0, &pReq, 0 /* no wait! */, VMREQFLAGS_VBOX_STATUS, - (PFNRT)Console::unplugCpu, 3, + (PFNRT)unplugCpu, 3, this, pUVM, (VMCPUID)aCpu); if (vrc == VERR_TIMEOUT || RT_SUCCESS(vrc)) { @@ -2500,7 +2500,7 @@ HRESULT Console::doCPUAdd(ULONG aCpu, PUVM pUVM) */ PVMREQ pReq; int vrc = VMR3ReqCallU(pUVM, 0, &pReq, 0 /* no wait! */, VMREQFLAGS_VBOX_STATUS, - (PFNRT)Console::plugCpu, 3, + (PFNRT)plugCpu, 3, this, pUVM, aCpu); /* release the lock before a VMR3* call (EMT will call us back)! */ @@ -3505,6 +3505,83 @@ HRESULT Console::convertBusPortDeviceToLun(StorageBus_T enmBus, LONG port, LONG // private methods ///////////////////////////////////////////////////////////////////////////// + +/** + * Suspend the VM before we do any medium or network attachment change. + * + * @param pUVM Safe VM handle. + * @param pAlock The automatic lock instance. This is for when we have + * to leave it in order to avoid deadlocks. + * @param pfSuspend where to store the information if we need to resume + * afterwards. + */ +HRESULT Console::suspendBeforeConfigChange(PUVM pUVM, AutoWriteLock *pAlock, bool *pfResume) +{ + *pfResume = false; + VMSTATE enmVMState = VMR3GetStateU(pUVM); + switch (enmVMState) + { + case VMSTATE_RESETTING: + case VMSTATE_RUNNING: + { + LogFlowFunc(("Suspending the VM...\n")); + /* disable the callback to prevent Console-level state change */ + mVMStateChangeCallbackDisabled = true; + if (pAlock) + pAlock->release(); + int rc = VMR3Suspend(pUVM, VMSUSPENDREASON_RECONFIG); + if (pAlock) + pAlock->acquire(); + mVMStateChangeCallbackDisabled = false; + if (RT_FAILURE(rc)) + return setErrorInternal(VBOX_E_INVALID_VM_STATE, + COM_IIDOF(IConsole), + getStaticComponentName(), + Utf8StrFmt("Couldn't suspend VM for medium change (%Rrc)", rc), + false /*aWarning*/, + true /*aLogIt*/); + *pfResume = true; + break; + } + case VMSTATE_SUSPENDED: + break; + default: + return setErrorInternal(VBOX_E_INVALID_VM_STATE, + COM_IIDOF(IConsole), + getStaticComponentName(), + Utf8StrFmt("Invalid VM state '%s' for changing medium", + VMR3GetStateName(enmVMState)), + false /*aWarning*/, + true /*aLogIt*/); + } + + return S_OK; +} + +/** + * Resume the VM after we did any medium or network attachment change. + * This is the counterpart to Console::suspendBeforeConfigChange(). + * + * @param pUVM Safe VM handle. + */ +void Console::resumeAfterConfigChange(PUVM pUVM) +{ + LogFlowFunc(("Resuming the VM...\n")); + /* disable the callback to prevent Console-level state change */ + mVMStateChangeCallbackDisabled = true; + int rc = VMR3Resume(pUVM, VMRESUMEREASON_RECONFIG); + mVMStateChangeCallbackDisabled = false; + AssertRC(rc); + if (RT_FAILURE(rc)) + { + VMSTATE enmVMState = VMR3GetStateU(pUVM); + if (enmVMState == VMSTATE_SUSPENDED) + { + /* too bad, we failed. try to sync the console state with the VMM state */ + vmstateChangeCallback(pUVM, VMSTATE_SUSPENDED, enmVMState, this); + } + } +} /** * Process a medium change. @@ -3574,26 +3651,23 @@ HRESULT Console::doMediumChange(IMediumAttachment *aMediumAttachment, bool fForc AssertComRC(rc); /* + * Suspend the VM first. The VM must not be running since it might have + * pending I/O to the drive which is being changed. + */ + bool fResume = false; + rc = suspendBeforeConfigChange(pUVM, &alock, &fResume); + if (FAILED(rc)) + return rc; + + /* * Call worker in EMT, that's faster and safer than doing everything * using VMR3ReqCall. Note that we separate VMR3ReqCall from VMR3ReqWait * here to make requests from under the lock in order to serialize them. */ PVMREQ pReq; - int vrc = VMR3ReqCallU(pUVM, - VMCPUID_ANY, - &pReq, - 0 /* no wait! */, - VMREQFLAGS_VBOX_STATUS, - (PFNRT)Console::changeRemovableMedium, - 8, - this, - pUVM, - pszDevice, - uInstance, - enmBus, - fUseHostIOCache, - aMediumAttachment, - fForce); + int vrc = VMR3ReqCallU(pUVM, VMCPUID_ANY, &pReq, 0 /* no wait! */, VMREQFLAGS_VBOX_STATUS, + (PFNRT)changeRemovableMedium, 8, + this, pUVM, pszDevice, uInstance, enmBus, fUseHostIOCache, aMediumAttachment, fForce); /* release the lock before waiting for a result (EMT will call us back!) */ alock.release(); @@ -3607,6 +3681,9 @@ HRESULT Console::doMediumChange(IMediumAttachment *aMediumAttachment, bool fForc } VMR3ReqFree(pReq); + if (fResume) + resumeAfterConfigChange(pUVM); + if (RT_SUCCESS(vrc)) { LogFlowThisFunc(("Returns S_OK\n")); @@ -3642,8 +3719,9 @@ HRESULT Console::doMediumChange(IMediumAttachment *aMediumAttachment, bool fForc * @param fPassthrough Enables using passthrough mode of the host DVD drive if applicable. * * @thread EMT + * @note The VM must not be running since it might have pending I/O to the drive which is being changed. */ -DECLCALLBACK(int) Console::changeRemovableMedium(Console *pConsole, +DECLCALLBACK(int) Console::changeRemovableMedium(Console *pThis, PUVM pUVM, const char *pcszDevice, unsigned uInstance, @@ -3652,112 +3730,49 @@ DECLCALLBACK(int) Console::changeRemovableMedium(Console *pConsole, IMediumAttachment *aMediumAtt, bool fForce) { - LogFlowFunc(("pConsole=%p uInstance=%u pszDevice=%p:{%s} enmBus=%u, aMediumAtt=%p, fForce=%d\n", - pConsole, uInstance, pcszDevice, pcszDevice, enmBus, aMediumAtt, fForce)); + LogFlowFunc(("pThis=%p uInstance=%u pszDevice=%p:{%s} enmBus=%u, aMediumAtt=%p, fForce=%d\n", + pThis, uInstance, pcszDevice, pcszDevice, enmBus, aMediumAtt, fForce)); - AssertReturn(pConsole, VERR_INVALID_PARAMETER); + AssertReturn(pThis, VERR_INVALID_PARAMETER); - AutoCaller autoCaller(pConsole); + AutoCaller autoCaller(pThis); AssertComRCReturn(autoCaller.rc(), VERR_ACCESS_DENIED); /* - * Suspend the VM first. - * - * The VM must not be running since it might have pending I/O to - * the drive which is being changed. + * Check the VM for correct state. */ - bool fResume; VMSTATE enmVMState = VMR3GetStateU(pUVM); - switch (enmVMState) - { - case VMSTATE_RESETTING: - case VMSTATE_RUNNING: - { - LogFlowFunc(("Suspending the VM...\n")); - /* disable the callback to prevent Console-level state change */ - pConsole->mVMStateChangeCallbackDisabled = true; - int rc = VMR3Suspend(pUVM, VMSUSPENDREASON_RECONFIG); - pConsole->mVMStateChangeCallbackDisabled = false; - AssertRCReturn(rc, rc); - fResume = true; - break; - } - - case VMSTATE_SUSPENDED: - case VMSTATE_CREATED: - case VMSTATE_OFF: - fResume = false; - break; - - case VMSTATE_RUNNING_LS: - case VMSTATE_RUNNING_FT: - return setErrorInternal(VBOX_E_INVALID_VM_STATE, - COM_IIDOF(IConsole), - getStaticComponentName(), - (enmVMState == VMSTATE_RUNNING_LS) ? Utf8Str(tr("Cannot change drive during live migration")) : Utf8Str(tr("Cannot change drive during fault tolerant syncing")), - false /*aWarning*/, - true /*aLogIt*/); - - default: - AssertMsgFailedReturn(("enmVMState=%d\n", enmVMState), VERR_ACCESS_DENIED); - } + AssertReturn(enmVMState == VMSTATE_SUSPENDED, VERR_INVALID_STATE); /* Determine the base path for the device instance. */ PCFGMNODE pCtlInst; pCtlInst = CFGMR3GetChildF(CFGMR3GetRootU(pUVM), "Devices/%s/%u/", pcszDevice, uInstance); AssertReturn(pCtlInst, VERR_INTERNAL_ERROR); - int rc = VINF_SUCCESS; - int rcRet = VINF_SUCCESS; - - rcRet = pConsole->configMediumAttachment(pCtlInst, - pcszDevice, - uInstance, - enmBus, - fUseHostIOCache, - false /* fSetupMerge */, - false /* fBuiltinIOCache */, - 0 /* uMergeSource */, - 0 /* uMergeTarget */, - aMediumAtt, - pConsole->mMachineState, - NULL /* phrc */, - true /* fAttachDetach */, - fForce /* fForceUnmount */, - false /* fHotplug */, - pUVM, - NULL /* paLedDevType */); - /** @todo this dumps everything attached to this device instance, which - * is more than necessary. Dumping the changed LUN would be enough. */ - CFGMR3Dump(pCtlInst); - - /* - * Resume the VM if necessary. - */ - if (fResume) - { - LogFlowFunc(("Resuming the VM...\n")); - /* disable the callback to prevent Console-level state change */ - pConsole->mVMStateChangeCallbackDisabled = true; - rc = VMR3Resume(pUVM, VMRESUMEREASON_RECONFIG); - pConsole->mVMStateChangeCallbackDisabled = false; - AssertRC(rc); - if (RT_FAILURE(rc)) - { - /* too bad, we failed. try to sync the console state with the VMM state */ - vmstateChangeCallback(pUVM, VMSTATE_SUSPENDED, enmVMState, pConsole); - } - /// @todo (r=dmik) if we failed with drive mount, then the VMR3Resume - // error (if any) will be hidden from the caller. For proper reporting - // of such multiple errors to the caller we need to enhance the - // IVirtualBoxError interface. For now, give the first error the higher - // priority. - if (RT_SUCCESS(rcRet)) - rcRet = rc; - } - - LogFlowFunc(("Returning %Rrc\n", rcRet)); - return rcRet; + PCFGMNODE pLunL0 = NULL; + int rc = pThis->configMediumAttachment(pCtlInst, + pcszDevice, + uInstance, + enmBus, + fUseHostIOCache, + false /* fSetupMerge */, + false /* fBuiltinIOCache */, + 0 /* uMergeSource */, + 0 /* uMergeTarget */, + aMediumAtt, + pThis->mMachineState, + NULL /* phrc */, + true /* fAttachDetach */, + fForce /* fForceUnmount */, + false /* fHotplug */, + pUVM, + NULL /* paLedDevType */, + &pLunL0); + /* Dump the changed LUN if possible, dump the complete device otherwise */ + CFGMR3Dump(pLunL0 ? pLunL0 : pCtlInst); + + LogFlowFunc(("Returning %Rrc\n", rc)); + return rc; } @@ -3829,26 +3844,23 @@ HRESULT Console::doStorageDeviceAttach(IMediumAttachment *aMediumAttachment, PUV AssertComRC(rc); /* + * Suspend the VM first. The VM must not be running since it might have + * pending I/O to the drive which is being changed. + */ + bool fResume = false; + rc = suspendBeforeConfigChange(pUVM, &alock, &fResume); + if (FAILED(rc)) + return rc; + + /* * Call worker in EMT, that's faster and safer than doing everything * using VMR3ReqCall. Note that we separate VMR3ReqCall from VMR3ReqWait * here to make requests from under the lock in order to serialize them. */ PVMREQ pReq; - int vrc = VMR3ReqCallU(pUVM, - VMCPUID_ANY, - &pReq, - 0 /* no wait! */, - VMREQFLAGS_VBOX_STATUS, - (PFNRT)Console::attachStorageDevice, - 8, - this, - pUVM, - pszDevice, - uInstance, - enmBus, - fUseHostIOCache, - aMediumAttachment, - fSilent); + int vrc = VMR3ReqCallU(pUVM, VMCPUID_ANY, &pReq, 0 /* no wait! */, VMREQFLAGS_VBOX_STATUS, + (PFNRT)attachStorageDevice, 8, + this, pUVM, pszDevice, uInstance, enmBus, fUseHostIOCache, aMediumAttachment, fSilent); /* release the lock before waiting for a result (EMT will call us back!) */ alock.release(); @@ -3862,6 +3874,9 @@ HRESULT Console::doStorageDeviceAttach(IMediumAttachment *aMediumAttachment, PUV } VMR3ReqFree(pReq); + if (fResume) + resumeAfterConfigChange(pUVM); + if (RT_SUCCESS(vrc)) { LogFlowThisFunc(("Returns S_OK\n")); @@ -3891,8 +3906,9 @@ HRESULT Console::doStorageDeviceAttach(IMediumAttachment *aMediumAttachment, PUV * @param fSilent Flag whether to inform the guest about the attached device. * * @thread EMT + * @note The VM must not be running since it might have pending I/O to the drive which is being changed. */ -DECLCALLBACK(int) Console::attachStorageDevice(Console *pConsole, +DECLCALLBACK(int) Console::attachStorageDevice(Console *pThis, PUVM pUVM, const char *pcszDevice, unsigned uInstance, @@ -3901,113 +3917,49 @@ DECLCALLBACK(int) Console::attachStorageDevice(Console *pConsole, IMediumAttachment *aMediumAtt, bool fSilent) { - LogFlowFunc(("pConsole=%p uInstance=%u pszDevice=%p:{%s} enmBus=%u, aMediumAtt=%p\n", - pConsole, uInstance, pcszDevice, pcszDevice, enmBus, aMediumAtt)); + LogFlowFunc(("pThis=%p uInstance=%u pszDevice=%p:{%s} enmBus=%u, aMediumAtt=%p\n", + pThis, uInstance, pcszDevice, pcszDevice, enmBus, aMediumAtt)); - AssertReturn(pConsole, VERR_INVALID_PARAMETER); + AssertReturn(pThis, VERR_INVALID_PARAMETER); - AutoCaller autoCaller(pConsole); + AutoCaller autoCaller(pThis); AssertComRCReturn(autoCaller.rc(), VERR_ACCESS_DENIED); /* - * Suspend the VM first. - * - * The VM must not be running since it might have pending I/O to - * the drive which is being changed. + * Check the VM for correct state. */ - bool fResume; VMSTATE enmVMState = VMR3GetStateU(pUVM); - switch (enmVMState) - { - case VMSTATE_RESETTING: - case VMSTATE_RUNNING: - { - LogFlowFunc(("Suspending the VM...\n")); - /* disable the callback to prevent Console-level state change */ - pConsole->mVMStateChangeCallbackDisabled = true; - int rc = VMR3Suspend(pUVM, VMSUSPENDREASON_RECONFIG); - pConsole->mVMStateChangeCallbackDisabled = false; - AssertRCReturn(rc, rc); - fResume = true; - break; - } - - case VMSTATE_SUSPENDED: - case VMSTATE_CREATED: - case VMSTATE_OFF: - fResume = false; - break; - - case VMSTATE_RUNNING_LS: - case VMSTATE_RUNNING_FT: - return setErrorInternal(VBOX_E_INVALID_VM_STATE, - COM_IIDOF(IConsole), - getStaticComponentName(), - (enmVMState == VMSTATE_RUNNING_LS) ? Utf8Str(tr("Cannot change drive during live migration")) : Utf8Str(tr("Cannot change drive during fault tolerant syncing")), - false /*aWarning*/, - true /*aLogIt*/); - - default: - AssertMsgFailedReturn(("enmVMState=%d\n", enmVMState), VERR_ACCESS_DENIED); - } + AssertReturn(enmVMState == VMSTATE_SUSPENDED, VERR_INVALID_STATE); /* Determine the base path for the device instance. */ PCFGMNODE pCtlInst; pCtlInst = CFGMR3GetChildF(CFGMR3GetRootU(pUVM), "Devices/%s/%u/", pcszDevice, uInstance); AssertReturn(pCtlInst, VERR_INTERNAL_ERROR); - int rc = VINF_SUCCESS; - int rcRet = VINF_SUCCESS; - - rcRet = pConsole->configMediumAttachment(pCtlInst, - pcszDevice, - uInstance, - enmBus, - fUseHostIOCache, - false /* fSetupMerge */, - false /* fBuiltinIOCache */, - 0 /* uMergeSource */, - 0 /* uMergeTarget */, - aMediumAtt, - pConsole->mMachineState, - NULL /* phrc */, - true /* fAttachDetach */, - false /* fForceUnmount */, - !fSilent /* fHotplug */, - pUVM, - NULL /* paLedDevType */); - /** @todo this dumps everything attached to this device instance, which - * is more than necessary. Dumping the changed LUN would be enough. */ - CFGMR3Dump(pCtlInst); - - /* - * Resume the VM if necessary. - */ - if (fResume) - { - LogFlowFunc(("Resuming the VM...\n")); - /* disable the callback to prevent Console-level state change */ - pConsole->mVMStateChangeCallbackDisabled = true; - rc = VMR3Resume(pUVM, VMRESUMEREASON_RECONFIG); - pConsole->mVMStateChangeCallbackDisabled = false; - AssertRC(rc); - if (RT_FAILURE(rc)) - { - /* too bad, we failed. try to sync the console state with the VMM state */ - vmstateChangeCallback(pUVM, VMSTATE_SUSPENDED, enmVMState, pConsole); - } - /** @todo if we failed with drive mount, then the VMR3Resume - * error (if any) will be hidden from the caller. For proper reporting - * of such multiple errors to the caller we need to enhance the - * IVirtualBoxError interface. For now, give the first error the higher - * priority. - */ - if (RT_SUCCESS(rcRet)) - rcRet = rc; - } - - LogFlowFunc(("Returning %Rrc\n", rcRet)); - return rcRet; + PCFGMNODE pLunL0 = NULL; + int rc = pThis->configMediumAttachment(pCtlInst, + pcszDevice, + uInstance, + enmBus, + fUseHostIOCache, + false /* fSetupMerge */, + false /* fBuiltinIOCache */, + 0 /* uMergeSource */, + 0 /* uMergeTarget */, + aMediumAtt, + pThis->mMachineState, + NULL /* phrc */, + true /* fAttachDetach */, + false /* fForceUnmount */, + !fSilent /* fHotplug */, + pUVM, + NULL /* paLedDevType */, + &pLunL0); + /* Dump the changed LUN if possible, dump the complete device otherwise */ + CFGMR3Dump(pLunL0 ? pLunL0 : pCtlInst); + + LogFlowFunc(("Returning %Rrc\n", rc)); + return rc; } /** @@ -4075,25 +4027,23 @@ HRESULT Console::doStorageDeviceDetach(IMediumAttachment *aMediumAttachment, PUV AssertComRC(rc); /* + * Suspend the VM first. The VM must not be running since it might have + * pending I/O to the drive which is being changed. + */ + bool fResume = false; + rc = suspendBeforeConfigChange(pUVM, &alock, &fResume); + if (FAILED(rc)) + return rc; + + /* * Call worker in EMT, that's faster and safer than doing everything * using VMR3ReqCall. Note that we separate VMR3ReqCall from VMR3ReqWait * here to make requests from under the lock in order to serialize them. */ PVMREQ pReq; - int vrc = VMR3ReqCallU(pUVM, - VMCPUID_ANY, - &pReq, - 0 /* no wait! */, - VMREQFLAGS_VBOX_STATUS, - (PFNRT)Console::detachStorageDevice, - 7, - this, - pUVM, - pszDevice, - uInstance, - enmBus, - aMediumAttachment, - fSilent); + int vrc = VMR3ReqCallU(pUVM, VMCPUID_ANY, &pReq, 0 /* no wait! */, VMREQFLAGS_VBOX_STATUS, + (PFNRT)detachStorageDevice, 7, + this, pUVM, pszDevice, uInstance, enmBus, aMediumAttachment, fSilent); /* release the lock before waiting for a result (EMT will call us back!) */ alock.release(); @@ -4107,6 +4057,9 @@ HRESULT Console::doStorageDeviceDetach(IMediumAttachment *aMediumAttachment, PUV } VMR3ReqFree(pReq); + if (fResume) + resumeAfterConfigChange(pUVM); + if (RT_SUCCESS(vrc)) { LogFlowThisFunc(("Returns S_OK\n")); @@ -4135,8 +4088,9 @@ HRESULT Console::doStorageDeviceDetach(IMediumAttachment *aMediumAttachment, PUV * @param fSilent Flag whether to notify the guest about the detached device. * * @thread EMT + * @note The VM must not be running since it might have pending I/O to the drive which is being changed. */ -DECLCALLBACK(int) Console::detachStorageDevice(Console *pConsole, +DECLCALLBACK(int) Console::detachStorageDevice(Console *pThis, PUVM pUVM, const char *pcszDevice, unsigned uInstance, @@ -4144,55 +4098,19 @@ DECLCALLBACK(int) Console::detachStorageDevice(Console *pConsole, IMediumAttachment *pMediumAtt, bool fSilent) { - LogFlowFunc(("pConsole=%p uInstance=%u pszDevice=%p:{%s} enmBus=%u, pMediumAtt=%p\n", - pConsole, uInstance, pcszDevice, pcszDevice, enmBus, pMediumAtt)); + LogFlowFunc(("pThis=%p uInstance=%u pszDevice=%p:{%s} enmBus=%u, pMediumAtt=%p\n", + pThis, uInstance, pcszDevice, pcszDevice, enmBus, pMediumAtt)); - AssertReturn(pConsole, VERR_INVALID_PARAMETER); + AssertReturn(pThis, VERR_INVALID_PARAMETER); - AutoCaller autoCaller(pConsole); + AutoCaller autoCaller(pThis); AssertComRCReturn(autoCaller.rc(), VERR_ACCESS_DENIED); /* - * Suspend the VM first. - * - * The VM must not be running since it might have pending I/O to - * the drive which is being changed. + * Check the VM for correct state. */ - bool fResume; VMSTATE enmVMState = VMR3GetStateU(pUVM); - switch (enmVMState) - { - case VMSTATE_RESETTING: - case VMSTATE_RUNNING: - { - LogFlowFunc(("Suspending the VM...\n")); - /* disable the callback to prevent Console-level state change */ - pConsole->mVMStateChangeCallbackDisabled = true; - int rc = VMR3Suspend(pUVM, VMSUSPENDREASON_RECONFIG); - pConsole->mVMStateChangeCallbackDisabled = false; - AssertRCReturn(rc, rc); - fResume = true; - break; - } - - case VMSTATE_SUSPENDED: - case VMSTATE_CREATED: - case VMSTATE_OFF: - fResume = false; - break; - - case VMSTATE_RUNNING_LS: - case VMSTATE_RUNNING_FT: - return setErrorInternal(VBOX_E_INVALID_VM_STATE, - COM_IIDOF(IConsole), - getStaticComponentName(), - (enmVMState == VMSTATE_RUNNING_LS) ? Utf8Str(tr("Cannot change drive during live migration")) : Utf8Str(tr("Cannot change drive during fault tolerant syncing")), - false /*aWarning*/, - true /*aLogIt*/); - - default: - AssertMsgFailedReturn(("enmVMState=%d\n", enmVMState), VERR_ACCESS_DENIED); - } + AssertReturn(enmVMState == VMSTATE_SUSPENDED, VERR_INVALID_STATE); /* Determine the base path for the device instance. */ PCFGMNODE pCtlInst; @@ -4234,7 +4152,7 @@ DECLCALLBACK(int) Console::detachStorageDevice(Console *pConsole, CFGMR3RemoveNode(pLunL0); Utf8Str devicePath = Utf8StrFmt("%s/%u/LUN#%u", pcszDevice, uInstance, uLUN); - pConsole->mapMediumAttachments.erase(devicePath); + pThis->mapMediumAttachments.erase(devicePath); } else @@ -4242,32 +4160,6 @@ DECLCALLBACK(int) Console::detachStorageDevice(Console *pConsole, CFGMR3Dump(pCtlInst); - /* - * Resume the VM if necessary. - */ - if (fResume) - { - LogFlowFunc(("Resuming the VM...\n")); - /* disable the callback to prevent Console-level state change */ - pConsole->mVMStateChangeCallbackDisabled = true; - rc = VMR3Resume(pUVM, VMRESUMEREASON_RECONFIG); - pConsole->mVMStateChangeCallbackDisabled = false; - AssertRC(rc); - if (RT_FAILURE(rc)) - { - /* too bad, we failed. try to sync the console state with the VMM state */ - vmstateChangeCallback(pUVM, VMSTATE_SUSPENDED, enmVMState, pConsole); - } - /** @todo: if we failed with drive mount, then the VMR3Resume - * error (if any) will be hidden from the caller. For proper reporting - * of such multiple errors to the caller we need to enhance the - * IVirtualBoxError interface. For now, give the first error the higher - * priority. - */ - if (RT_SUCCESS(rcRet)) - rcRet = rc; - } - LogFlowFunc(("Returning %Rrc\n", rcRet)); return rcRet; } @@ -4507,13 +4399,21 @@ HRESULT Console::doNetworkAdapterChange(PUVM pUVM, AssertComRCReturnRC(autoCaller.rc()); /* + * Suspend the VM first. + */ + bool fResume = false; + int rc = suspendBeforeConfigChange(pUVM, NULL, &fResume); + if (FAILED(rc)) + return rc; + + /* * Call worker in EMT, that's faster and safer than doing everything * using VM3ReqCall. Note that we separate VMR3ReqCall from VMR3ReqWait * here to make requests from under the lock in order to serialize them. */ PVMREQ pReq; int vrc = VMR3ReqCallU(pUVM, 0 /*idDstCpu*/, &pReq, 0 /* no wait! */, VMREQFLAGS_VBOX_STATUS, - (PFNRT)Console::changeNetworkAttachment, 6, + (PFNRT)changeNetworkAttachment, 6, this, pUVM, pszDevice, uInstance, uLun, aNetworkAdapter); if (vrc == VERR_TIMEOUT || RT_SUCCESS(vrc)) @@ -4525,6 +4425,9 @@ HRESULT Console::doNetworkAdapterChange(PUVM pUVM, } VMR3ReqFree(pReq); + if (fResume) + resumeAfterConfigChange(pUVM); + if (RT_SUCCESS(vrc)) { LogFlowThisFunc(("Returns S_OK\n")); @@ -4551,6 +4454,7 @@ HRESULT Console::doNetworkAdapterChange(PUVM pUVM, * * @thread EMT * @note Locks the Console object for writing. + * @note The VM must not be running. */ DECLCALLBACK(int) Console::changeNetworkAttachment(Console *pThis, PUVM pUVM, @@ -4586,76 +4490,21 @@ DECLCALLBACK(int) Console::changeNetworkAttachment(Console *pThis, Log(("pszDevice=%s uLun=%d uInstance=%d\n", pszDevice, uLun, uInstance)); /* - * Suspend the VM first. - * - * The VM must not be running since it might have pending I/O to - * the drive which is being changed. + * Check the VM for correct state. */ - bool fResume; VMSTATE enmVMState = VMR3GetStateU(pUVM); - switch (enmVMState) - { - case VMSTATE_RESETTING: - case VMSTATE_RUNNING: - { - LogFlowFunc(("Suspending the VM...\n")); - /* disable the callback to prevent Console-level state change */ - pThis->mVMStateChangeCallbackDisabled = true; - int rc = VMR3Suspend(pUVM, VMSUSPENDREASON_RECONFIG); - pThis->mVMStateChangeCallbackDisabled = false; - AssertRCReturn(rc, rc); - fResume = true; - break; - } - - case VMSTATE_SUSPENDED: - case VMSTATE_CREATED: - case VMSTATE_OFF: - fResume = false; - break; - - default: - AssertLogRelMsgFailedReturn(("enmVMState=%d\n", enmVMState), VERR_ACCESS_DENIED); - } - - int rc = VINF_SUCCESS; - int rcRet = VINF_SUCCESS; + AssertReturn(enmVMState == VMSTATE_SUSPENDED, VERR_INVALID_STATE); PCFGMNODE pCfg = NULL; /* /Devices/Dev/.../Config/ */ PCFGMNODE pLunL0 = NULL; /* /Devices/Dev/0/LUN#0/ */ PCFGMNODE pInst = CFGMR3GetChildF(CFGMR3GetRootU(pUVM), "Devices/%s/%d/", pszDevice, uInstance); AssertRelease(pInst); - rcRet = pThis->configNetwork(pszDevice, uInstance, uLun, aNetworkAdapter, pCfg, pLunL0, pInst, - true /*fAttachDetach*/, false /*fIgnoreConnectFailure*/); - - /* - * Resume the VM if necessary. - */ - if (fResume) - { - LogFlowFunc(("Resuming the VM...\n")); - /* disable the callback to prevent Console-level state change */ - pThis->mVMStateChangeCallbackDisabled = true; - rc = VMR3Resume(pUVM, VMRESUMEREASON_RECONFIG); - pThis->mVMStateChangeCallbackDisabled = false; - AssertRC(rc); - if (RT_FAILURE(rc)) - { - /* too bad, we failed. try to sync the console state with the VMM state */ - vmstateChangeCallback(pUVM, VMSTATE_SUSPENDED, enmVMState, pThis); - } - /// @todo (r=dmik) if we failed with drive mount, then the VMR3Resume - // error (if any) will be hidden from the caller. For proper reporting - // of such multiple errors to the caller we need to enhance the - // IVirtualBoxError interface. For now, give the first error the higher - // priority. - if (RT_SUCCESS(rcRet)) - rcRet = rc; - } + int rc = pThis->configNetwork(pszDevice, uInstance, uLun, aNetworkAdapter, pCfg, pLunL0, pInst, + true /*fAttachDetach*/, false /*fIgnoreConnectFailure*/); - LogFlowFunc(("Returning %Rrc\n", rcRet)); - return rcRet; + LogFlowFunc(("Returning %Rrc\n", rc)); + return rc; } @@ -5703,23 +5552,11 @@ HRESULT Console::onlineMergeMedium(IMediumAttachment *aMediumAttachment, AssertRCReturn(vrc2, E_FAIL); } - vrc = VMR3ReqCallWaitU(ptrVM.rawUVM(), - VMCPUID_ANY, - (PFNRT)reconfigureMediumAttachment, - 13, - this, - ptrVM.rawUVM(), - pcszDevice, - uInstance, - enmBus, - fUseHostIOCache, - fBuiltinIOCache, - true /* fSetupMerge */, - aSourceIdx, - aTargetIdx, - aMediumAttachment, - mMachineState, - &rc); + vrc = VMR3ReqCallWaitU(ptrVM.rawUVM(), VMCPUID_ANY, + (PFNRT)reconfigureMediumAttachment, 13, + this, ptrVM.rawUVM(), pcszDevice, uInstance, enmBus, fUseHostIOCache, + fBuiltinIOCache, true /* fSetupMerge */, aSourceIdx, aTargetIdx, + aMediumAttachment, mMachineState, &rc); /* error handling is after resuming the VM */ if (mMachineState == MachineState_DeletingSnapshotOnline) @@ -5777,23 +5614,11 @@ HRESULT Console::onlineMergeMedium(IMediumAttachment *aMediumAttachment, /* Update medium chain and state now, so that the VM can continue. */ rc = mControl->FinishOnlineMergeMedium(); - vrc = VMR3ReqCallWaitU(ptrVM.rawUVM(), - VMCPUID_ANY, - (PFNRT)reconfigureMediumAttachment, - 13, - this, - ptrVM.rawUVM(), - pcszDevice, - uInstance, - enmBus, - fUseHostIOCache, - fBuiltinIOCache, - false /* fSetupMerge */, - 0 /* uMergeSource */, - 0 /* uMergeTarget */, - aMediumAttachment, - mMachineState, - &rc); + vrc = VMR3ReqCallWaitU(ptrVM.rawUVM(), VMCPUID_ANY, + (PFNRT)reconfigureMediumAttachment, 13, + this, ptrVM.rawUVM(), pcszDevice, uInstance, enmBus, fUseHostIOCache, + fBuiltinIOCache, false /* fSetupMerge */, 0 /* uMergeSource */, + 0 /* uMergeTarget */, aMediumAttachment, mMachineState, &rc); /* error handling is after resuming the VM */ if (mMachineState == MachineState_DeletingSnapshotOnline) @@ -8236,7 +8061,6 @@ HRESULT Console::attachUSBDevice(IUSBDevice *aHostDevice, ULONG aMaskedIfs) (PFNRT)usbAttachCallback, 9, this, ptrVM.rawUVM(), aHostDevice, uuid.raw(), fRemote, Address.c_str(), pvRemoteBackend, portVersion, aMaskedIfs); - if (RT_SUCCESS(vrc)) { /* Create a OUSBDevice and add it to the device list */ @@ -9461,7 +9285,7 @@ DECLCALLBACK(int) Console::powerUpThread(RTTHREAD Thread, void *pvUser) /** * Reconfigures a medium attachment (part of taking or deleting an online snapshot). * - * @param pConsole Reference to the console object. + * @param pThis Reference to the console object. * @param pUVM The VM handle. * @param lInstance The instance of the controller. * @param pcszDevice The name of the controller type. @@ -9475,7 +9299,7 @@ DECLCALLBACK(int) Console::powerUpThread(RTTHREAD Thread, void *pvUser) * @return VBox status code. */ /* static */ -DECLCALLBACK(int) Console::reconfigureMediumAttachment(Console *pConsole, +DECLCALLBACK(int) Console::reconfigureMediumAttachment(Console *pThis, PUVM pUVM, const char *pcszDevice, unsigned uInstance, @@ -9491,11 +9315,9 @@ DECLCALLBACK(int) Console::reconfigureMediumAttachment(Console *pConsole, { LogFlowFunc(("pUVM=%p aMediumAtt=%p phrc=%p\n", pUVM, aMediumAtt, phrc)); - int rc; HRESULT hrc; Bstr bstr; *phrc = S_OK; -#define RC_CHECK() do { if (RT_FAILURE(rc)) { AssertMsgFailed(("rc=%Rrc\n", rc)); return rc; } } while (0) #define H() do { if (FAILED(hrc)) { AssertMsgFailed(("hrc=%Rhrc (%#x)\n", hrc, hrc)); *phrc = hrc; return VERR_GENERAL_FAILURE; } } while (0) /* Ignore attachments other than hard disks, since at the moment they are @@ -9511,29 +9333,33 @@ DECLCALLBACK(int) Console::reconfigureMediumAttachment(Console *pConsole, AssertReturn(pCtlInst, VERR_INTERNAL_ERROR); /* Update the device instance configuration. */ - rc = pConsole->configMediumAttachment(pCtlInst, - pcszDevice, - uInstance, - enmBus, - fUseHostIOCache, - fBuiltinIOCache, - fSetupMerge, - uMergeSource, - uMergeTarget, - aMediumAtt, - aMachineState, - phrc, - true /* fAttachDetach */, - false /* fForceUnmount */, - false /* fHotplug */, - pUVM, - NULL /* paLedDevType */); - /** @todo this dumps everything attached to this device instance, which - * is more than necessary. Dumping the changed LUN would be enough. */ - CFGMR3Dump(pCtlInst); - RC_CHECK(); + PCFGMNODE pLunL0 = NULL; + int rc = pThis->configMediumAttachment(pCtlInst, + pcszDevice, + uInstance, + enmBus, + fUseHostIOCache, + fBuiltinIOCache, + fSetupMerge, + uMergeSource, + uMergeTarget, + aMediumAtt, + aMachineState, + phrc, + true /* fAttachDetach */, + false /* fForceUnmount */, + false /* fHotplug */, + pUVM, + NULL /* paLedDevType */, + &pLunL0); + /* Dump the changed LUN if possible, dump the complete device otherwise */ + CFGMR3Dump(pLunL0 ? pLunL0 : pCtlInst); + if (RT_FAILURE(rc)) + { + AssertMsgFailed(("rc=%Rrc\n", rc)); + return rc; + } -#undef RC_CHECK #undef H LogFlowFunc(("Returns success\n")); @@ -9715,23 +9541,11 @@ DECLCALLBACK(int) Console::fntTakeSnapshotWorker(RTTHREAD Thread, void *pvUser) * don't release the lock since reconfigureMediumAttachment * isn't going to need the Console lock. */ - vrc = VMR3ReqCallWaitU(ptrVM.rawUVM(), - VMCPUID_ANY, - (PFNRT)reconfigureMediumAttachment, - 13, - that, - ptrVM.rawUVM(), - pcszDevice, - lInstance, - enmBus, - fUseHostIOCache, - fBuiltinIOCache, - false /* fSetupMerge */, - 0 /* uMergeSource */, - 0 /* uMergeTarget */, - atts[i], - that->mMachineState, - &rc); + vrc = VMR3ReqCallWaitU(ptrVM.rawUVM(), VMCPUID_ANY, + (PFNRT)reconfigureMediumAttachment, 13, + that, ptrVM.rawUVM(), pcszDevice, lInstance, enmBus, fUseHostIOCache, + fBuiltinIOCache, false /* fSetupMerge */, 0 /* uMergeSource */, + 0 /* uMergeTarget */, atts[i], that->mMachineState, &rc); if (RT_FAILURE(vrc)) throw setErrorStatic(E_FAIL, Console::tr("%Rrc"), vrc); if (FAILED(rc)) diff --git a/src/VBox/Main/src-client/ConsoleImpl2.cpp b/src/VBox/Main/src-client/ConsoleImpl2.cpp index b762a06ef..78feac8fd 100644 --- a/src/VBox/Main/src-client/ConsoleImpl2.cpp +++ b/src/VBox/Main/src-client/ConsoleImpl2.cpp @@ -1924,7 +1924,8 @@ int Console::configConstructorInner(PUVM pUVM, PVM pVM, AutoWriteLock *pAlock) false /* fForceUnmount */, false /* fHotplug */, pUVM, - paLedDevType); + paLedDevType, + NULL /* ppLunL0 */); if (RT_FAILURE(rc)) return rc; } @@ -3414,7 +3415,8 @@ int Console::configMediumAttachment(PCFGMNODE pCtlInst, bool fForceUnmount, bool fHotplug, PUVM pUVM, - DeviceType_T *paLedDevType) + DeviceType_T *paLedDevType, + PCFGMNODE *ppLunL0) { // InsertConfig* throws try @@ -3485,6 +3487,8 @@ int Console::configMediumAttachment(PCFGMNODE pCtlInst, } InsertConfigNode(pCtlInst, Utf8StrFmt("LUN#%u", uLUN).c_str(), &pLunL0); + if (ppLunL0) + *ppLunL0 = pLunL0; PCFGMNODE pCfg = CFGMR3GetChild(pCtlInst, "Config"); if (pCfg) diff --git a/src/VBox/Main/src-client/DisplayImpl.cpp b/src/VBox/Main/src-client/DisplayImpl.cpp index b62708579..3477a07c2 100644 --- a/src/VBox/Main/src-client/DisplayImpl.cpp +++ b/src/VBox/Main/src-client/DisplayImpl.cpp @@ -4300,31 +4300,9 @@ void Display::handleCrHgsmiControlCompletion(int32_t result, uint32_t u32Functio mpDrv->pVBVACallbacks->pfnCrHgsmiControlCompleteAsync(mpDrv->pVBVACallbacks, (PVBOXVDMACMD_CHROMIUM_CTL)pParam->u.pointer.addr, result); } -int Display::handleCrCmdNotifyCmds() -{ - int rc = VERR_INVALID_FUNCTION; - - if (mhCrOglSvc) - { - VBOXHGCMSVCPARM dummy; - VMMDev *pVMMDev = mParent->getVMMDev(); - if (pVMMDev) - { - /* no completion callback is specified with this call, - * the CrOgl code will complete the CrHgsmi command once it processes it */ - rc = pVMMDev->hgcmHostFastCallAsync(mhCrOglSvc, SHCRGL_HOST_FN_CRCMD_NOTIFY_CMDS, &dummy, NULL, NULL); - AssertRC(rc); - } - else - rc = VERR_INVALID_STATE; - } - - return rc; -} - void Display::handleCrHgsmiCommandProcess(PVBOXVDMACMD_CHROMIUM_CMD pCmd, uint32_t cbCmd) { - int rc = VERR_INVALID_FUNCTION; + int rc = VERR_NOT_SUPPORTED; VBOXHGCMSVCPARM parm; parm.type = VBOX_HGCM_SVC_PARM_PTR; parm.u.pointer.addr = pCmd; @@ -4352,7 +4330,7 @@ void Display::handleCrHgsmiCommandProcess(PVBOXVDMACMD_CHROMIUM_CMD pCmd, uint32 void Display::handleCrHgsmiControlProcess(PVBOXVDMACMD_CHROMIUM_CTL pCtl, uint32_t cbCtl) { - int rc = VERR_INVALID_FUNCTION; + int rc = VERR_NOT_SUPPORTED; VBOXHGCMSVCPARM parm; parm.type = VBOX_HGCM_SVC_PARM_PTR; parm.u.pointer.addr = pCtl; @@ -4376,13 +4354,6 @@ void Display::handleCrHgsmiControlProcess(PVBOXVDMACMD_CHROMIUM_CTL pCtl, uint32 handleCrHgsmiControlCompletion(rc, SHCRGL_HOST_FN_CRHGSMI_CTL, &parm); } -DECLCALLBACK(int) Display::displayCrCmdNotifyCmds(PPDMIDISPLAYCONNECTOR pInterface) -{ - PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface); - - return pDrv->pDisplay->handleCrCmdNotifyCmds(); -} - DECLCALLBACK(void) Display::displayCrHgsmiCommandProcess(PPDMIDISPLAYCONNECTOR pInterface, PVBOXVDMACMD_CHROMIUM_CMD pCmd, uint32_t cbCmd) { PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface); @@ -4411,6 +4382,48 @@ DECLCALLBACK(void) Display::displayCrHgsmiControlCompletion(int32_t result, uint } #endif +DECLCALLBACK(void) Display::displayCrHgcmCtlSubmitCompletion(int32_t result, uint32_t u32Function, PVBOXHGCMSVCPARM pParam, void *pvContext) +{ + VBOXCRCMDCTL *pCmd = (VBOXCRCMDCTL*)pParam->u.pointer.addr; + if (pCmd->pfnInternal) + ((PFNCRCTLCOMPLETION)pCmd->pfnInternal)(pCmd, pParam->u.pointer.size, result, pvContext); +} + +int Display::handleCrHgcmCtlSubmit(struct VBOXCRCMDCTL* pCmd, uint32_t cbCmd, + PFNCRCTLCOMPLETION pfnCompletion, + void *pvCompletion) +{ + VMMDev *pVMMDev = mParent->getVMMDev(); + if (!pVMMDev) + { + AssertMsgFailed(("no vmmdev\n")); + return VERR_INVALID_STATE; + } + + Assert(mhCrOglSvc); + VBOXHGCMSVCPARM parm; + parm.type = VBOX_HGCM_SVC_PARM_PTR; + parm.u.pointer.addr = pCmd; + parm.u.pointer.size = cbCmd; + + pCmd->pfnInternal = (void(*)())pfnCompletion; + int rc = pVMMDev->hgcmHostFastCallAsync(mhCrOglSvc, SHCRGL_HOST_FN_CTL, &parm, displayCrHgcmCtlSubmitCompletion, pvCompletion); + if (!RT_SUCCESS(rc)) + AssertMsgFailed(("hgcmHostFastCallAsync failed rc %n", rc)); + + return rc; +} + +DECLCALLBACK(int) Display::displayCrHgcmCtlSubmit(PPDMIDISPLAYCONNECTOR pInterface, + struct VBOXCRCMDCTL* pCmd, uint32_t cbCmd, + PFNCRCTLCOMPLETION pfnCompletion, + void *pvCompletion) +{ + PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface); + Display *pThis = pDrv->pDisplay; + return pThis->handleCrHgcmCtlSubmit(pCmd, cbCmd, pfnCompletion, pvCompletion); +} + #if defined(VBOX_WITH_HGCM) && defined(VBOX_WITH_CROGL) DECLCALLBACK(void) Display::displayCrAsyncCmdCompletion(int32_t result, uint32_t u32Function, PVBOXHGCMSVCPARM pParam, void *pvContext) { @@ -5034,10 +5047,10 @@ DECLCALLBACK(int) Display::drvConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint pThis->IConnector.pfnVHWACommandProcess = Display::displayVHWACommandProcess; #endif #ifdef VBOX_WITH_CRHGSMI - pThis->IConnector.pfnCrCmdNotifyCmds = Display::displayCrCmdNotifyCmds; pThis->IConnector.pfnCrHgsmiCommandProcess = Display::displayCrHgsmiCommandProcess; pThis->IConnector.pfnCrHgsmiControlProcess = Display::displayCrHgsmiControlProcess; #endif + pThis->IConnector.pfnCrHgcmCtlSubmit = Display::displayCrHgcmCtlSubmit; #ifdef VBOX_WITH_HGSMI pThis->IConnector.pfnVBVAEnable = Display::displayVBVAEnable; pThis->IConnector.pfnVBVADisable = Display::displayVBVADisable; diff --git a/src/VBox/Main/src-client/GuestFileImpl.cpp b/src/VBox/Main/src-client/GuestFileImpl.cpp index 4bd3c5737..8a0ce53e2 100644 --- a/src/VBox/Main/src-client/GuestFileImpl.cpp +++ b/src/VBox/Main/src-client/GuestFileImpl.cpp @@ -160,7 +160,7 @@ int GuestFile::init(Console *pConsole, GuestSession *pSession, mData.mOpenInfo = openInfo; unconst(mEventSource).createObject(); - HRESULT hr = mEventSource->init(static_cast<IGuestFile*>(this)); + HRESULT hr = mEventSource->init(); if (FAILED(hr)) vrc = VERR_COM_UNEXPECTED; } diff --git a/src/VBox/Main/src-client/GuestImpl.cpp b/src/VBox/Main/src-client/GuestImpl.cpp index e41a6f6f2..41469b0c4 100644 --- a/src/VBox/Main/src-client/GuestImpl.cpp +++ b/src/VBox/Main/src-client/GuestImpl.cpp @@ -111,7 +111,7 @@ HRESULT Guest::init(Console *aParent) #ifdef VBOX_WITH_GUEST_CONTROL hr = unconst(mEventSource).createObject(); if (SUCCEEDED(hr)) - hr = mEventSource->init(static_cast<IGuest*>(this)); + hr = mEventSource->init(); #else hr = S_OK; #endif diff --git a/src/VBox/Main/src-client/GuestProcessImpl.cpp b/src/VBox/Main/src-client/GuestProcessImpl.cpp index cfd2d1dcd..4ccf1e44d 100644 --- a/src/VBox/Main/src-client/GuestProcessImpl.cpp +++ b/src/VBox/Main/src-client/GuestProcessImpl.cpp @@ -188,7 +188,7 @@ int GuestProcess::init(Console *aConsole, GuestSession *aSession, vrc = VERR_NO_MEMORY; else { - hr = mEventSource->init(static_cast<IGuestProcess*>(this)); + hr = mEventSource->init(); if (FAILED(hr)) vrc = VERR_COM_UNEXPECTED; } diff --git a/src/VBox/Main/src-client/GuestSessionImpl.cpp b/src/VBox/Main/src-client/GuestSessionImpl.cpp index 31de6b105..433ac056b 100644 --- a/src/VBox/Main/src-client/GuestSessionImpl.cpp +++ b/src/VBox/Main/src-client/GuestSessionImpl.cpp @@ -211,7 +211,7 @@ int GuestSession::init(Guest *pGuest, const GuestSessionStartupInfo &ssInfo, rc = VERR_NO_MEMORY; else { - hr = mEventSource->init(static_cast<IGuestSession*>(this)); + hr = mEventSource->init(); if (FAILED(hr)) rc = VERR_COM_UNEXPECTED; } diff --git a/src/VBox/Main/src-client/KeyboardImpl.cpp b/src/VBox/Main/src-client/KeyboardImpl.cpp index b8010e7ae..74154daca 100644 --- a/src/VBox/Main/src-client/KeyboardImpl.cpp +++ b/src/VBox/Main/src-client/KeyboardImpl.cpp @@ -112,7 +112,7 @@ HRESULT Keyboard::init(Console *aParent) unconst(mParent) = aParent; unconst(mEventSource).createObject(); - HRESULT rc = mEventSource->init(static_cast<IKeyboard*>(this)); + HRESULT rc = mEventSource->init(); AssertComRCReturnRC(rc); /* Confirm a successful initialization */ diff --git a/src/VBox/Main/src-client/MouseImpl.cpp b/src/VBox/Main/src-client/MouseImpl.cpp index 94a79eb41..652f2df35 100644 --- a/src/VBox/Main/src-client/MouseImpl.cpp +++ b/src/VBox/Main/src-client/MouseImpl.cpp @@ -112,7 +112,7 @@ HRESULT Mouse::init (ConsoleMouseInterface *parent) unconst(mParent) = parent; unconst(mEventSource).createObject(); - HRESULT rc = mEventSource->init(static_cast<IMouse*>(this)); + HRESULT rc = mEventSource->init(); AssertComRCReturnRC(rc); mMouseEvent.init(mEventSource, VBoxEventType_OnGuestMouse, 0, 0, 0, 0, 0, 0); diff --git a/src/VBox/Main/src-client/VirtualBoxClientImpl.cpp b/src/VBox/Main/src-client/VirtualBoxClientImpl.cpp index c421c9304..0e2405af5 100644 --- a/src/VBox/Main/src-client/VirtualBoxClientImpl.cpp +++ b/src/VBox/Main/src-client/VirtualBoxClientImpl.cpp @@ -81,7 +81,7 @@ HRESULT VirtualBoxClient::init() rc = unconst(mData.m_pEventSource).createObject(); AssertComRCReturnRC(rc); - rc = mData.m_pEventSource->init(static_cast<IVirtualBoxClient *>(this)); + rc = mData.m_pEventSource->init(); AssertComRCReturnRC(rc); /* Setting up the VBoxSVC watcher thread. If anything goes wrong here it diff --git a/src/VBox/Main/src-server/ApplianceImpl.cpp b/src/VBox/Main/src-server/ApplianceImpl.cpp index 4c498fd6c..8d1e60141 100644 --- a/src/VBox/Main/src-server/ApplianceImpl.cpp +++ b/src/VBox/Main/src-server/ApplianceImpl.cpp @@ -1530,8 +1530,10 @@ void VirtualSystemDescription::addEntry(VirtualSystemDescriptionType_T aType, = vsde.strExtraConfigCurrent = strExtraConfig; vsde.ulSizeMB = ulSizeMB; + vsde.skipIt = false; m->llDescriptions.push_back(vsde); + } /** diff --git a/src/VBox/Main/src-server/ApplianceImplExport.cpp b/src/VBox/Main/src-server/ApplianceImplExport.cpp index 5980e1c6b..c8c5718f9 100644 --- a/src/VBox/Main/src-server/ApplianceImplExport.cpp +++ b/src/VBox/Main/src-server/ApplianceImplExport.cpp @@ -607,7 +607,13 @@ STDMETHODIMP Appliance::Write(IN_BSTR format, ComSafeArrayIn(ImportOptions_T, op ++it) { ComObjPtr<VirtualSystemDescription> vsdescThis = (*it); - vsdescThis->removeByType(VirtualSystemDescriptionType_CDROM); + std::list<VirtualSystemDescriptionEntry*> skipped = vsdescThis->findByType(VirtualSystemDescriptionType_CDROM); + std::list<VirtualSystemDescriptionEntry*>:: iterator pItSkipped = skipped.begin(); + while (pItSkipped != skipped.end()) + { + (*pItSkipped)->skipIt = true; + ++pItSkipped; + } } } @@ -886,7 +892,8 @@ void Appliance::buildXML(AutoWriteLockBase& writeLock, Bstr bstrSrcFilePath(strSrcFilePath); //skip empty Medium. There are no information to add into section <References> or <DiskSection> - if (strSrcFilePath.isEmpty()) + if (strSrcFilePath.isEmpty() || + pDiskEntry->skipIt == true) continue; // Do NOT check here whether the file exists. FindMedium will figure @@ -1516,7 +1523,8 @@ void Appliance::buildXMLForOneVirtualSystem(AutoWriteLockBase& writeLock, lAutomaticAllocation = 1; //skip empty Medium. There are no information to add into section <References> or <DiskSection> - if (desc.strVBoxCurrent.isNotEmpty()) + if (desc.strVBoxCurrent.isNotEmpty() && + desc.skipIt == false) { // the following references the "<Disks>" XML block strHostResource = Utf8StrFmt("/disk/%s", strDiskID.c_str()); @@ -2091,7 +2099,8 @@ HRESULT Appliance::writeFSImpl(TaskOVF *pTask, AutoWriteLockBase& writeLock, PVD const Utf8Str &strSrcFilePath = pDiskEntry->strVBoxCurrent; //skip empty Medium. In common, It's may be empty CD/DVD - if (strSrcFilePath.isEmpty()) + if (strSrcFilePath.isEmpty() || + pDiskEntry->skipIt == true) continue; // Do NOT check here whether the file exists. findHardDisk will diff --git a/src/VBox/Main/src-server/HostDnsService.cpp b/src/VBox/Main/src-server/HostDnsService.cpp index d4cd3a0f4..011528fba 100644 --- a/src/VBox/Main/src-server/HostDnsService.cpp +++ b/src/VBox/Main/src-server/HostDnsService.cpp @@ -288,7 +288,7 @@ HRESULT HostDnsMonitorProxy::GetDomainName(BSTR *aDomainName) if (m->fModified) updateInfo(); - LogRel(("HostDnsMonitorProxy::GetDomainName:%s\n", m->info->domain.c_str())); + LogRel(("HostDnsMonitorProxy::GetDomainName: %s\n", m->info->domain.c_str())); Utf8Str(m->info->domain.c_str()).cloneTo(aDomainName); @@ -355,7 +355,7 @@ static void dumpHostDnsInformation(const HostDnsInformation& info) static void dumpHostDnsStrVector(const std::string& prefix, const std::vector<std::string>& v) { - int i = 0; + int i = 1; for (std::vector<std::string>::const_iterator it = v.begin(); it != v.end(); ++it, ++i) diff --git a/src/VBox/Main/src-server/MachineImpl.cpp b/src/VBox/Main/src-server/MachineImpl.cpp index b8eea6f14..d79059174 100644 --- a/src/VBox/Main/src-server/MachineImpl.cpp +++ b/src/VBox/Main/src-server/MachineImpl.cpp @@ -12858,28 +12858,6 @@ HRESULT SessionMachine::init(Machine *aMachine) { unconst(mNetworkAdapters[slot]).createObject(); mNetworkAdapters[slot]->init(this, aMachine->mNetworkAdapters[slot]); - - NetworkAttachmentType_T type; - HRESULT hrc; - hrc = mNetworkAdapters[slot]->COMGETTER(AttachmentType)(&type); - if ( SUCCEEDED(hrc) - && type == NetworkAttachmentType_NATNetwork) - { - Bstr name; - hrc = mNetworkAdapters[slot]->COMGETTER(NATNetwork)(name.asOutParam()); - if (SUCCEEDED(hrc)) - { - LogRel(("VM '%s' starts using NAT network '%ls'\n", - mUserData->s.strName.c_str(), name.raw())); - aMachine->lockHandle()->unlockWrite(); - mParent->natNetworkRefInc(name.raw()); -#ifdef RT_LOCK_STRICT - aMachine->lockHandle()->lockWrite(RT_SRC_POS); -#else - aMachine->lockHandle()->lockWrite(); -#endif - } - } } /* create another bandwidth control object that will be mutable */ @@ -12892,6 +12870,8 @@ HRESULT SessionMachine::init(Machine *aMachine) /* Confirm a successful initialization when it's the case */ autoInitSpan.setSucceeded(); + miNATNetworksStarted = 0; + LogFlowThisFuncLeave(); return rc; } @@ -13071,24 +13051,29 @@ void SessionMachine::uninit(Uninit::Reason aReason) mData->mSession.mRemoteControls.clear(); } - for (ULONG slot = 0; slot < mNetworkAdapters.size(); slot++) + /* Remove all references to the NAT network service. The service will stop + * if all references (also from other VMs) are removed. */ + for (; miNATNetworksStarted > 0; miNATNetworksStarted--) { - NetworkAttachmentType_T type; - HRESULT hrc; - - hrc = mNetworkAdapters[slot]->COMGETTER(AttachmentType)(&type); - if ( SUCCEEDED(hrc) - && type == NetworkAttachmentType_NATNetwork) + for (ULONG slot = 0; slot < mNetworkAdapters.size(); slot++) { - Bstr name; - hrc = mNetworkAdapters[slot]->COMGETTER(NATNetwork)(name.asOutParam()); - if (SUCCEEDED(hrc)) + NetworkAttachmentType_T type; + HRESULT hrc; + + hrc = mNetworkAdapters[slot]->COMGETTER(AttachmentType)(&type); + if ( SUCCEEDED(hrc) + && type == NetworkAttachmentType_NATNetwork) { - multilock.release(); - LogRel(("VM '%s' stops using NAT network '%ls'\n", - mUserData->s.strName.c_str(), name.raw())); - mParent->natNetworkRefDec(name.raw()); - multilock.acquire(); + Bstr name; + hrc = mNetworkAdapters[slot]->COMGETTER(NATNetwork)(name.asOutParam()); + if (SUCCEEDED(hrc)) + { + multilock.release(); + LogRel(("VM '%s' stops using NAT network '%ls'\n", + mUserData->s.strName.c_str(), name.raw())); + mParent->natNetworkRefDec(name.raw()); + multilock.acquire(); + } } } } @@ -13261,6 +13246,37 @@ STDMETHODIMP SessionMachine::BeginPowerUp(IProgress *aProgress) if (!mData->mSession.mProgress.isNull()) mData->mSession.mProgress->setOtherProgressObject(aProgress); + /* If we didn't reference the NAT network service yet, add a reference to + * force a start */ + if (miNATNetworksStarted < 1) + { + for (ULONG slot = 0; slot < mNetworkAdapters.size(); slot++) + { + NetworkAttachmentType_T type; + HRESULT hrc; + hrc = mNetworkAdapters[slot]->COMGETTER(AttachmentType)(&type); + if ( SUCCEEDED(hrc) + && type == NetworkAttachmentType_NATNetwork) + { + Bstr name; + hrc = mNetworkAdapters[slot]->COMGETTER(NATNetwork)(name.asOutParam()); + if (SUCCEEDED(hrc)) + { + LogRel(("VM '%s' starts using NAT network '%ls'\n", + mUserData->s.strName.c_str(), name.raw())); + mPeer->lockHandle()->unlockWrite(); + mParent->natNetworkRefInc(name.raw()); +#ifdef RT_LOCK_STRICT + mPeer->lockHandle()->lockWrite(RT_SRC_POS); +#else + mPeer->lockHandle()->lockWrite(); +#endif + } + } + } + miNATNetworksStarted++; + } + LogFlowThisFunc(("returns S_OK.\n")); return S_OK; } diff --git a/src/VBox/Main/src-server/NATNetworkImpl.cpp b/src/VBox/Main/src-server/NATNetworkImpl.cpp index c419420fb..653272503 100644 --- a/src/VBox/Main/src-server/NATNetworkImpl.cpp +++ b/src/VBox/Main/src-server/NATNetworkImpl.cpp @@ -154,7 +154,7 @@ HRESULT NATNetwork::init(VirtualBox *aVirtualBox, IN_BSTR aName) HRESULT hrc = unconst(m->pEventSource).createObject(); if (FAILED(hrc)) throw hrc; - hrc = m->pEventSource->init(static_cast<INATNetwork *>(this)); + hrc = m->pEventSource->init(); if (FAILED(hrc)) throw hrc; /* Confirm a successful initialization */ @@ -209,7 +209,7 @@ HRESULT NATNetwork::init(VirtualBox *aVirtualBox, HRESULT hrc = unconst(m->pEventSource).createObject(); if (FAILED(hrc)) throw hrc; - hrc = m->pEventSource->init(static_cast<INATNetwork *>(this)); + hrc = m->pEventSource->init(); if (FAILED(hrc)) throw hrc; autoInitSpan.setSucceeded(); diff --git a/src/VBox/Main/src-server/VirtualBoxImpl.cpp b/src/VBox/Main/src-server/VirtualBoxImpl.cpp index e19e1f697..7c3192363 100644 --- a/src/VBox/Main/src-server/VirtualBoxImpl.cpp +++ b/src/VBox/Main/src-server/VirtualBoxImpl.cpp @@ -509,7 +509,7 @@ HRESULT VirtualBox::init() /* events */ if (SUCCEEDED(rc = unconst(m->pEventSource).createObject())) - rc = m->pEventSource->init(static_cast<IVirtualBox*>(this)); + rc = m->pEventSource->init(); if (FAILED(rc)) throw rc; #ifdef VBOX_WITH_EXTPACK @@ -807,7 +807,11 @@ void VirtualBox::uninit() LogFlowThisFunc(("Releasing event source...\n")); if (m->pEventSource) { - // we don't perform uninit() as it's possible that some pending event refers to this source + // Must uninit the event source here, because it makes no sense that + // it survives longer than the base object. If someone gets an event + // with such an event source then that's life and it has to be dealt + // with appropriately on the API client side. + m->pEventSource->uninit(); unconst(m->pEventSource).setNull(); } diff --git a/src/VBox/Main/src-server/darwin/iokit.cpp b/src/VBox/Main/src-server/darwin/iokit.cpp index 7a7b1059f..69c572f27 100644 --- a/src/VBox/Main/src-server/darwin/iokit.cpp +++ b/src/VBox/Main/src-server/darwin/iokit.cpp @@ -8,7 +8,7 @@ */ /* - * Copyright (C) 2006-2012 Oracle Corporation + * Copyright (C) 2006-2014 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -1354,7 +1354,7 @@ PDARWINDVD DarwinGetDVDDrives(void) if (*pszVendor && *pszProduct) RTStrPrintf(szName, sizeof(szName), "%s %s (#%u)", pszVendor, pszProduct, i); else - RTStrPrintf(szName, sizeof(szName), "%s %s (#%u)", *pszVendor ? pszVendor : pszProduct, i); + RTStrPrintf(szName, sizeof(szName), "%s (#%u)", *pszVendor ? pszVendor : pszProduct, i); break; } } |
