summaryrefslogtreecommitdiff
path: root/src/VBox/Main/src-client/ConsoleImpl.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/VBox/Main/src-client/ConsoleImpl.cpp')
-rw-r--r--src/VBox/Main/src-client/ConsoleImpl.cpp2678
1 files changed, 1402 insertions, 1276 deletions
diff --git a/src/VBox/Main/src-client/ConsoleImpl.cpp b/src/VBox/Main/src-client/ConsoleImpl.cpp
index 6c29a2dd..d0c74c24 100644
--- a/src/VBox/Main/src-client/ConsoleImpl.cpp
+++ b/src/VBox/Main/src-client/ConsoleImpl.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2005-2012 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;
@@ -57,19 +57,17 @@
#include "SharedFolderImpl.h"
#include "AudioSnifferInterface.h"
#include "Nvram.h"
-#ifdef VBOX_WITH_USB_VIDEO
-# include "UsbWebcamInterface.h"
-#endif
#ifdef VBOX_WITH_USB_CARDREADER
# include "UsbCardReader.h"
#endif
-#include "ProgressCombinedImpl.h"
+#include "ProgressImpl.h"
#include "ConsoleVRDPServer.h"
#include "VMMDev.h"
#ifdef VBOX_WITH_EXTPACK
# include "ExtPackManagerImpl.h"
#endif
#include "BusAssignmentManager.h"
+#include "EmulatedUSBImpl.h"
#include "VBoxEvents.h"
#include "AutoCaller.h"
@@ -155,7 +153,7 @@ struct VMTask
mConsoleCaller(aConsole),
mProgress(aProgress),
mServerProgress(aServerProgress),
- mpVM(NULL),
+ mpUVM(NULL),
mRC(E_FAIL),
mpSafeVMPtr(NULL)
{
@@ -167,7 +165,7 @@ struct VMTask
{
mpSafeVMPtr = new Console::SafeVMPtr(aConsole);
if (mpSafeVMPtr->isOk())
- mpVM = mpSafeVMPtr->raw();
+ mpUVM = mpSafeVMPtr->rawUVM();
else
mRC = mpSafeVMPtr->rc();
}
@@ -196,7 +194,7 @@ struct VMTask
const ComObjPtr<Progress> mProgress;
Utf8Str mErrorMsg;
const ComPtr<IProgress> mServerProgress;
- PVM mpVM;
+ PUVM mpUVM;
private:
HRESULT mRC;
@@ -262,16 +260,20 @@ struct VMSaveTask : public VMTask
VMSaveTask(Console *aConsole,
const ComPtr<IProgress> &aServerProgress,
const Utf8Str &aSavedStateFile,
- MachineState_T aMachineStateBefore)
+ MachineState_T aMachineStateBefore,
+ Reason_T aReason)
: VMTask(aConsole, NULL /* aProgress */, aServerProgress,
true /* aUsesVMPtr */),
mSavedStateFile(aSavedStateFile),
- mMachineStateBefore(aMachineStateBefore)
+ mMachineStateBefore(aMachineStateBefore),
+ mReason(aReason)
{}
Utf8Str mSavedStateFile;
/* The local machine state we had before. Required if something fails */
MachineState_T mMachineStateBefore;
+ /* The reason for saving state */
+ Reason_T mReason;
};
// Handler for global events
@@ -344,13 +346,34 @@ public:
break;
}
+ case VBoxEventType_OnExtraDataChanged:
+ {
+ ComPtr<IExtraDataChangedEvent> pEDCEv = aEvent;
+ Bstr strMachineId;
+ Bstr strKey;
+ Bstr strVal;
+ HRESULT hrc = S_OK;
+
+ hrc = pEDCEv->COMGETTER(MachineId)(strMachineId.asOutParam());
+ if (FAILED(hrc)) break;
+
+ hrc = pEDCEv->COMGETTER(Key)(strKey.asOutParam());
+ if (FAILED(hrc)) break;
+
+ hrc = pEDCEv->COMGETTER(Value)(strVal.asOutParam());
+ if (FAILED(hrc)) break;
+
+ mConsole->onExtraDataChange(strMachineId.raw(), strKey.raw(), strVal.raw());
+ break;
+ }
+
default:
AssertFailed();
}
return S_OK;
}
private:
- Console *mConsole;
+ ComObjPtr<Console> mConsole;
};
typedef ListenerImpl<VmEventListener, Console*> VmEventListenerImpl;
@@ -365,6 +388,8 @@ VBOX_LISTENER_DECLARE(VmEventListenerImpl)
Console::Console()
: mSavedStateDataLoaded(false)
, mConsoleVRDPServer(NULL)
+ , mfVRDEChangeInProcess(false)
+ , mfVRDEChangePending(false)
, mpUVM(NULL)
, mVMCallers(0)
, mVMZeroCallersSem(NIL_RTSEMEVENT)
@@ -374,13 +399,12 @@ Console::Console()
, mfSnapshotFolderSizeWarningShown(false)
, mfSnapshotFolderExt4WarningShown(false)
, mfSnapshotFolderDiskTypeShown(false)
+ , mfVMHasUsbController(false)
+ , mfPowerOffCausedByReset(false)
, mpVmm2UserMethods(NULL)
, m_pVMMDev(NULL)
, mAudioSniffer(NULL)
, mNvram(NULL)
-#ifdef VBOX_WITH_USB_VIDEO
- , mUsbWebcamInterface(NULL)
-#endif
#ifdef VBOX_WITH_USB_CARDREADER
, mUsbCardReader(NULL)
#endif
@@ -398,10 +422,10 @@ HRESULT Console::FinalConstruct()
{
LogFlowThisFunc(("\n"));
- memset(mapStorageLeds, 0, sizeof(mapStorageLeds));
- memset(mapNetworkLeds, 0, sizeof(mapNetworkLeds));
- memset(&mapUSBLed, 0, sizeof(mapUSBLed));
- memset(&mapSharedFolderLed, 0, sizeof(mapSharedFolderLed));
+ RT_ZERO(mapStorageLeds);
+ RT_ZERO(mapNetworkLeds);
+ RT_ZERO(mapUSBLed);
+ RT_ZERO(mapSharedFolderLed);
for (unsigned i = 0; i < RT_ELEMENTS(maStorageDevType); ++i)
maStorageDevType[i] = DeviceType_Null;
@@ -416,6 +440,7 @@ HRESULT Console::FinalConstruct()
pVmm2UserMethods->pfnNotifyEmtTerm = Console::vmm2User_NotifyEmtTerm;
pVmm2UserMethods->pfnNotifyPdmtInit = Console::vmm2User_NotifyPdmtInit;
pVmm2UserMethods->pfnNotifyPdmtTerm = Console::vmm2User_NotifyPdmtTerm;
+ pVmm2UserMethods->pfnNotifyResetTurnedIntoPowerOff = Console::vmm2User_NotifyResetTurnedIntoPowerOff;
pVmm2UserMethods->u32EndMagic = VMM2USERMETHODS_MAGIC;
pVmm2UserMethods->pConsole = this;
mpVmm2UserMethods = pVmm2UserMethods;
@@ -464,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;
@@ -498,6 +523,10 @@ HRESULT Console::init(IMachine *aMachine, IInternalMachineControl *aControl, Loc
rc = mVRDEServerInfo->init(this);
AssertComRCReturnRC(rc);
+ unconst(mEmulatedUSB).createObject();
+ rc = mEmulatedUSB->init(this);
+ AssertComRCReturnRC(rc);
+
/* Grab global and machine shared folder lists */
rc = fetchSharedFolders(true /* aGlobal */);
@@ -548,10 +577,6 @@ HRESULT Console::init(IMachine *aMachine, IInternalMachineControl *aControl, Loc
AssertReturn(mNvram, E_FAIL);
}
-#ifdef VBOX_WITH_USB_VIDEO
- unconst(mUsbWebcamInterface) = new UsbWebcamInterface(this);
- AssertReturn(mUsbWebcamInterface, E_FAIL);
-#endif
#ifdef VBOX_WITH_USB_CARDREADER
unconst(mUsbCardReader) = new UsbCardReader(this);
AssertReturn(mUsbCardReader, E_FAIL);
@@ -569,6 +594,7 @@ HRESULT Console::init(IMachine *aMachine, IInternalMachineControl *aControl, Loc
com::SafeArray<VBoxEventType_T> eventTypes;
eventTypes.push_back(VBoxEventType_OnNATRedirect);
eventTypes.push_back(VBoxEventType_OnHostPCIDevicePlug);
+ eventTypes.push_back(VBoxEventType_OnExtraDataChanged);
rc = pES->RegisterListener(aVmListener, ComSafeArrayAsInParam(eventTypes), true);
AssertComRC(rc);
}
@@ -649,14 +675,6 @@ void Console::uninit()
unconst(mNvram) = NULL;
}
-#ifdef VBOX_WITH_USB_VIDEO
- if (mUsbWebcamInterface)
- {
- delete mUsbWebcamInterface;
- unconst(mUsbWebcamInterface) = NULL;
- }
-#endif
-
#ifdef VBOX_WITH_USB_CARDREADER
if (mUsbCardReader)
{
@@ -697,6 +715,12 @@ void Console::uninit()
unconst(mVRDEServerInfo).setNull();
}
+ if (mEmulatedUSB)
+ {
+ mEmulatedUSB->uninit();
+ unconst(mEmulatedUSB).setNull();
+ }
+
if (mDebugger)
{
mDebugger->uninit();
@@ -778,8 +802,7 @@ void Console::guestPropertiesHandleVMReset(void)
/* Delete all properties which have the flag "TRANSRESET". */
if (Utf8Str(arrFlags[i]).contains("TRANSRESET", Utf8Str::CaseInsensitive))
{
- hrc = mMachine->SetGuestProperty(arrNames[i], Bstr("").raw() /* Value */,
- Bstr("").raw() /* Flags */);
+ hrc = mMachine->DeleteGuestProperty(arrNames[i]);
if (FAILED(hrc))
LogRel(("RESET: Could not delete transient property \"%ls\", rc=%Rhrc\n",
arrNames[i], hrc));
@@ -989,6 +1012,17 @@ void Console::guestPropertiesVRDPUpdateDisconnect(uint32_t u32ClientId)
#endif /* VBOX_WITH_GUEST_PROPS */
+bool Console::isResetTurnedIntoPowerOff(void)
+{
+ Bstr value;
+ HRESULT hrc = mMachine->GetExtraData(Bstr("VBoxInternal2/TurnResetIntoPowerOff").raw(),
+ value.asOutParam());
+ if ( hrc == S_OK
+ && value == "1")
+ return true;
+ return false;
+}
+
#ifdef VBOX_WITH_EXTPACK
/**
* Used by VRDEServer and others to talke to the extension pack manager.
@@ -1229,9 +1263,13 @@ int Console::VRDPClientLogon(uint32_t u32ClientId, const char *pszUser, const ch
{
uint32_t u32GuestFlags = VMMDEV_SETCREDENTIALS_GUESTLOGON;
- int rc = m_pVMMDev->getVMMDevPort()->pfnSetCredentials(m_pVMMDev->getVMMDevPort(),
- pszUser, pszPassword, pszDomain, u32GuestFlags);
- AssertRC(rc);
+ PPDMIVMMDEVPORT pDevPort = m_pVMMDev->getVMMDevPort();
+ if (pDevPort)
+ {
+ int rc = pDevPort->pfnSetCredentials(m_pVMMDev->getVMMDevPort(),
+ pszUser, pszPassword, pszDomain, u32GuestFlags);
+ AssertRC(rc);
+ }
}
return VINF_SUCCESS;
@@ -1697,8 +1735,8 @@ DECLCALLBACK(int) Console::doGuestPropNotification(void *pvExtension,
PHOSTCALLBACKDATA pCBData = reinterpret_cast<PHOSTCALLBACKDATA>(pvParms);
AssertReturn(sizeof(HOSTCALLBACKDATA) == cbParms, VERR_INVALID_PARAMETER);
AssertReturn(HOSTCALLBACKMAGIC == pCBData->u32Magic, VERR_INVALID_PARAMETER);
- Log5(("Console::doGuestPropNotification: pCBData={.pcszName=%s, .pcszValue=%s, .pcszFlags=%s}\n",
- pCBData->pcszName, pCBData->pcszValue, pCBData->pcszFlags));
+ LogFlow(("Console::doGuestPropNotification: pCBData={.pcszName=%s, .pcszValue=%s, .pcszFlags=%s}\n",
+ pCBData->pcszName, pCBData->pcszValue, pCBData->pcszFlags));
int rc;
Bstr name(pCBData->pcszName);
@@ -1713,7 +1751,7 @@ DECLCALLBACK(int) Console::doGuestPropNotification(void *pvExtension,
rc = VINF_SUCCESS;
else
{
- LogFunc(("Console::doGuestPropNotification: hrc=%Rhrc pCBData={.pcszName=%s, .pcszValue=%s, .pcszFlags=%s}\n",
+ LogFlow(("Console::doGuestPropNotification: hrc=%Rhrc pCBData={.pcszName=%s, .pcszValue=%s, .pcszFlags=%s}\n",
hrc, pCBData->pcszName, pCBData->pcszValue, pCBData->pcszFlags));
rc = Global::vboxStatusCodeFromCOM(hrc);
}
@@ -1968,12 +2006,25 @@ STDMETHODIMP Console::COMGETTER(VRDEServerInfo)(IVRDEServerInfo **aVRDEServerInf
AutoCaller autoCaller(this);
if (FAILED(autoCaller.rc())) return autoCaller.rc();
- /* mDisplay is constant during life time, no need to lock */
+ /* mVRDEServerInfo is constant during life time, no need to lock */
mVRDEServerInfo.queryInterfaceTo(aVRDEServerInfo);
return S_OK;
}
+STDMETHODIMP Console::COMGETTER(EmulatedUSB)(IEmulatedUSB **aEmulatedUSB)
+{
+ CheckComArgOutPointerValid(aEmulatedUSB);
+
+ AutoCaller autoCaller(this);
+ if (FAILED(autoCaller.rc())) return autoCaller.rc();
+
+ /* mEmulatedUSB is constant during life time, no need to lock */
+ mEmulatedUSB.queryInterfaceTo(aEmulatedUSB);
+
+ return S_OK;
+}
+
STDMETHODIMP
Console::COMGETTER(SharedFolders)(ComSafeArrayOut(ISharedFolder *, aSharedFolders))
{
@@ -2074,7 +2125,6 @@ STDMETHODIMP Console::PowerUpPaused(IProgress **aProgress)
STDMETHODIMP Console::PowerDown(IProgress **aProgress)
{
LogFlowThisFuncEnter();
- LogFlowThisFunc(("mMachineState=%d\n", mMachineState));
CheckComArgOutPointerValid(aProgress);
@@ -2083,6 +2133,7 @@ STDMETHODIMP Console::PowerDown(IProgress **aProgress)
AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+ LogFlowThisFunc(("mMachineState=%d\n", mMachineState));
switch (mMachineState)
{
case MachineState_Running:
@@ -2144,6 +2195,20 @@ STDMETHODIMP Console::PowerDown(IProgress **aProgress)
{
ComPtr<IProgress> pProgress;
+#ifdef VBOX_WITH_GUEST_PROPS
+ alock.release();
+
+ if (isResetTurnedIntoPowerOff())
+ {
+ mMachine->DeleteGuestProperty(Bstr("/VirtualBox/HostInfo/VMPowerOffReason").raw());
+ mMachine->SetGuestProperty(Bstr("/VirtualBox/HostInfo/VMPowerOffReason").raw(),
+ Bstr("PowerOff").raw(), Bstr("RDONLYGUEST").raw());
+ mMachine->SaveSettings();
+ }
+
+ alock.acquire();
+#endif
+
/*
* request a progress object from the server
* (this will set the machine state to Stopping on the server to block
@@ -2206,13 +2271,13 @@ STDMETHODIMP Console::PowerDown(IProgress **aProgress)
STDMETHODIMP Console::Reset()
{
LogFlowThisFuncEnter();
- LogFlowThisFunc(("mMachineState=%d\n", mMachineState));
AutoCaller autoCaller(this);
if (FAILED(autoCaller.rc())) return autoCaller.rc();
AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+ LogFlowThisFunc(("mMachineState=%d\n", mMachineState));
if ( mMachineState != MachineState_Running
&& mMachineState != MachineState_Teleporting
&& mMachineState != MachineState_LiveSnapshotting
@@ -2228,7 +2293,7 @@ STDMETHODIMP Console::Reset()
/* release the lock before a VMR3* call (EMT will call us back)! */
alock.release();
- int vrc = VMR3Reset(ptrVM);
+ int vrc = VMR3Reset(ptrVM.rawUVM());
HRESULT rc = RT_SUCCESS(vrc) ? S_OK :
setError(VBOX_E_VM_ERROR,
@@ -2240,30 +2305,30 @@ STDMETHODIMP Console::Reset()
return rc;
}
-/*static*/ DECLCALLBACK(int) Console::unplugCpu(Console *pThis, PVM pVM, unsigned uCpu)
+/*static*/ DECLCALLBACK(int) Console::unplugCpu(Console *pThis, PUVM pUVM, VMCPUID idCpu)
{
- LogFlowFunc(("pThis=%p pVM=%p uCpu=%u\n", pThis, pVM, uCpu));
+ LogFlowFunc(("pThis=%p pVM=%p idCpu=%u\n", pThis, pUVM, idCpu));
AssertReturn(pThis, VERR_INVALID_PARAMETER);
- int vrc = PDMR3DeviceDetach(pVM, "acpi", 0, uCpu, 0);
+ int vrc = PDMR3DeviceDetach(pUVM, "acpi", 0, idCpu, 0);
Log(("UnplugCpu: rc=%Rrc\n", vrc));
return vrc;
}
-HRESULT Console::doCPURemove(ULONG aCpu, PVM pVM)
+HRESULT Console::doCPURemove(ULONG aCpu, PUVM pUVM)
{
HRESULT rc = S_OK;
LogFlowThisFuncEnter();
- LogFlowThisFunc(("mMachineState=%d\n", mMachineState));
AutoCaller autoCaller(this);
if (FAILED(autoCaller.rc())) return autoCaller.rc();
AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+ LogFlowThisFunc(("mMachineState=%d\n", mMachineState));
AssertReturn(m_pVMMDev, E_FAIL);
PPDMIVMMDEVPORT pVmmDevPort = m_pVMMDev->getVMMDevPort();
AssertReturn(pVmmDevPort, E_FAIL);
@@ -2288,7 +2353,7 @@ HRESULT Console::doCPURemove(ULONG aCpu, PVM pVM)
/* Check if the CPU is unlocked */
PPDMIBASE pBase;
- int vrc = PDMR3QueryDeviceLun(pVM, "acpi", 0, aCpu, &pBase);
+ int vrc = PDMR3QueryDeviceLun(pUVM, "acpi", 0, aCpu, &pBase);
if (RT_SUCCESS(vrc))
{
Assert(pBase);
@@ -2296,7 +2361,7 @@ HRESULT Console::doCPURemove(ULONG aCpu, PVM pVM)
/* Notify the guest if possible. */
uint32_t idCpuCore, idCpuPackage;
- vrc = VMR3GetCpuCoreAndPackageIdFromCpuId(pVM, aCpu, &idCpuCore, &idCpuPackage); AssertRC(vrc);
+ vrc = VMR3GetCpuCoreAndPackageIdFromCpuId(pUVM, aCpu, &idCpuCore, &idCpuPackage); AssertRC(vrc);
if (RT_SUCCESS(vrc))
vrc = pVmmDevPort->pfnCpuHotUnplug(pVmmDevPort, idCpuCore, idCpuPackage);
if (RT_SUCCESS(vrc))
@@ -2328,9 +2393,9 @@ HRESULT Console::doCPURemove(ULONG aCpu, PVM pVM)
* using VMR3ReqCall.
*/
PVMREQ pReq;
- vrc = VMR3ReqCall(pVM, 0, &pReq, 0 /* no wait! */, VMREQFLAGS_VBOX_STATUS,
- (PFNRT)Console::unplugCpu, 3,
- this, pVM, aCpu);
+ vrc = VMR3ReqCallU(pUVM, 0, &pReq, 0 /* no wait! */, VMREQFLAGS_VBOX_STATUS,
+ (PFNRT)unplugCpu, 3,
+ this, pUVM, (VMCPUID)aCpu);
if (vrc == VERR_TIMEOUT || RT_SUCCESS(vrc))
{
vrc = VMR3ReqWait(pReq, RT_INDEFINITE_WAIT);
@@ -2343,7 +2408,7 @@ HRESULT Console::doCPURemove(ULONG aCpu, PVM pVM)
if (RT_SUCCESS(vrc))
{
/* Detach it from the VM */
- vrc = VMR3HotUnplugCpu(pVM, aCpu);
+ vrc = VMR3HotUnplugCpu(pUVM, aCpu);
AssertRC(vrc);
}
else
@@ -2359,25 +2424,25 @@ HRESULT Console::doCPURemove(ULONG aCpu, PVM pVM)
return rc;
}
-/*static*/ DECLCALLBACK(int) Console::plugCpu(Console *pThis, PVM pVM, unsigned uCpu)
+/*static*/ DECLCALLBACK(int) Console::plugCpu(Console *pThis, PUVM pUVM, VMCPUID idCpu)
{
- LogFlowFunc(("pThis=%p uCpu=%u\n", pThis, uCpu));
+ LogFlowFunc(("pThis=%p uCpu=%u\n", pThis, idCpu));
AssertReturn(pThis, VERR_INVALID_PARAMETER);
- int rc = VMR3HotPlugCpu(pVM, uCpu);
+ int rc = VMR3HotPlugCpu(pUVM, idCpu);
AssertRC(rc);
- PCFGMNODE pInst = CFGMR3GetChild(CFGMR3GetRoot(pVM), "Devices/acpi/0/");
+ PCFGMNODE pInst = CFGMR3GetChild(CFGMR3GetRootU(pUVM), "Devices/acpi/0/");
AssertRelease(pInst);
/* nuke anything which might have been left behind. */
- CFGMR3RemoveNode(CFGMR3GetChildF(pInst, "LUN#%d", uCpu));
+ CFGMR3RemoveNode(CFGMR3GetChildF(pInst, "LUN#%u", idCpu));
#define RC_CHECK() do { if (RT_FAILURE(rc)) { AssertReleaseRC(rc); break; } } while (0)
PCFGMNODE pLunL0;
PCFGMNODE pCfg;
- rc = CFGMR3InsertNodeF(pInst, &pLunL0, "LUN#%d", uCpu); RC_CHECK();
+ rc = CFGMR3InsertNodeF(pInst, &pLunL0, "LUN#%u", idCpu); RC_CHECK();
rc = CFGMR3InsertString(pLunL0, "Driver", "ACPICpu"); RC_CHECK();
rc = CFGMR3InsertNode(pLunL0, "Config", &pCfg); RC_CHECK();
@@ -2385,7 +2450,7 @@ HRESULT Console::doCPURemove(ULONG aCpu, PVM pVM)
* Attach the driver.
*/
PPDMIBASE pBase;
- rc = PDMR3DeviceAttach(pVM, "acpi", 0, uCpu, 0, &pBase); RC_CHECK();
+ rc = PDMR3DeviceAttach(pUVM, "acpi", 0, idCpu, 0, &pBase); RC_CHECK();
Log(("PlugCpu: rc=%Rrc\n", rc));
@@ -2396,18 +2461,18 @@ HRESULT Console::doCPURemove(ULONG aCpu, PVM pVM)
return VINF_SUCCESS;
}
-HRESULT Console::doCPUAdd(ULONG aCpu, PVM pVM)
+HRESULT Console::doCPUAdd(ULONG aCpu, PUVM pUVM)
{
HRESULT rc = S_OK;
LogFlowThisFuncEnter();
- LogFlowThisFunc(("mMachineState=%d\n", mMachineState));
AutoCaller autoCaller(this);
if (FAILED(autoCaller.rc())) return autoCaller.rc();
AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+ LogFlowThisFunc(("mMachineState=%d\n", mMachineState));
if ( mMachineState != MachineState_Running
&& mMachineState != MachineState_Teleporting
&& mMachineState != MachineState_LiveSnapshotting
@@ -2434,9 +2499,9 @@ HRESULT Console::doCPUAdd(ULONG aCpu, PVM pVM)
* here to make requests from under the lock in order to serialize them.
*/
PVMREQ pReq;
- int vrc = VMR3ReqCall(pVM, 0, &pReq, 0 /* no wait! */, VMREQFLAGS_VBOX_STATUS,
- (PFNRT)Console::plugCpu, 3,
- this, pVM, aCpu);
+ int vrc = VMR3ReqCallU(pUVM, 0, &pReq, 0 /* no wait! */, VMREQFLAGS_VBOX_STATUS,
+ (PFNRT)plugCpu, 3,
+ this, pUVM, aCpu);
/* release the lock before a VMR3* call (EMT will call us back)! */
alock.release();
@@ -2459,7 +2524,7 @@ HRESULT Console::doCPUAdd(ULONG aCpu, PVM pVM)
{
/* Notify the guest if possible. */
uint32_t idCpuCore, idCpuPackage;
- vrc = VMR3GetCpuCoreAndPackageIdFromCpuId(pVM, aCpu, &idCpuCore, &idCpuPackage); AssertRC(vrc);
+ vrc = VMR3GetCpuCoreAndPackageIdFromCpuId(pUVM, aCpu, &idCpuCore, &idCpuPackage); AssertRC(vrc);
if (RT_SUCCESS(vrc))
vrc = pDevPort->pfnCpuHotPlug(pDevPort, idCpuCore, idCpuPackage);
/** @todo warning if the guest doesn't support it */
@@ -2474,89 +2539,18 @@ STDMETHODIMP Console::Pause()
{
LogFlowThisFuncEnter();
- AutoCaller autoCaller(this);
- if (FAILED(autoCaller.rc())) return autoCaller.rc();
-
- AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
-
- switch (mMachineState)
- {
- case MachineState_Running:
- case MachineState_Teleporting:
- case MachineState_LiveSnapshotting:
- break;
-
- case MachineState_Paused:
- case MachineState_TeleportingPausedVM:
- case MachineState_Saving:
- return setError(VBOX_E_INVALID_VM_STATE, tr("Already paused"));
-
- default:
- return setInvalidMachineStateError();
- }
+ HRESULT rc = pause(Reason_Unspecified);
- /* get the VM handle. */
- SafeVMPtr ptrVM(this);
- if (!ptrVM.isOk())
- return ptrVM.rc();
-
- LogFlowThisFunc(("Sending PAUSE request...\n"));
-
- /* release the lock before a VMR3* call (EMT will call us back)! */
- alock.release();
-
- int vrc = VMR3Suspend(ptrVM);
-
- HRESULT hrc = S_OK;
- if (RT_FAILURE(vrc))
- hrc = setError(VBOX_E_VM_ERROR, tr("Could not suspend the machine execution (%Rrc)"), vrc);
-
- LogFlowThisFunc(("hrc=%Rhrc\n", hrc));
+ LogFlowThisFunc(("rc=%Rhrc\n", rc));
LogFlowThisFuncLeave();
- return hrc;
+ return rc;
}
STDMETHODIMP Console::Resume()
{
LogFlowThisFuncEnter();
- AutoCaller autoCaller(this);
- if (FAILED(autoCaller.rc())) return autoCaller.rc();
-
- AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
-
- if (mMachineState != MachineState_Paused)
- return setError(VBOX_E_INVALID_VM_STATE,
- tr("Cannot resume the machine as it is not paused (machine state: %s)"),
- Global::stringifyMachineState(mMachineState));
-
- /* get the VM handle. */
- SafeVMPtr ptrVM(this);
- if (!ptrVM.isOk())
- return ptrVM.rc();
-
- LogFlowThisFunc(("Sending RESUME request...\n"));
-
- /* release the lock before a VMR3* call (EMT will call us back)! */
- alock.release();
-
-#ifdef VBOX_WITH_EXTPACK
- int vrc = mptrExtPackManager->callAllVmPowerOnHooks(this, ptrVM); /** @todo called a few times too many... */
-#else
- int vrc = VINF_SUCCESS;
-#endif
- if (RT_SUCCESS(vrc))
- {
- if (VMR3GetState(ptrVM) == VMSTATE_CREATED)
- vrc = VMR3PowerOn(ptrVM); /* (PowerUpPaused) */
- else
- vrc = VMR3Resume(ptrVM);
- }
-
- HRESULT rc = RT_SUCCESS(vrc) ? S_OK :
- setError(VBOX_E_VM_ERROR,
- tr("Could not resume the machine execution (%Rrc)"),
- vrc);
+ HRESULT rc = resume(Reason_Unspecified);
LogFlowThisFunc(("rc=%Rhrc\n", rc));
LogFlowThisFuncLeave();
@@ -2587,7 +2581,7 @@ STDMETHODIMP Console::PowerButton()
/* get the acpi device interface and press the button. */
PPDMIBASE pBase;
- int vrc = PDMR3QueryDeviceLun(ptrVM, "acpi", 0, 0, &pBase);
+ int vrc = PDMR3QueryDeviceLun(ptrVM.rawUVM(), "acpi", 0, 0, &pBase);
if (RT_SUCCESS(vrc))
{
Assert(pBase);
@@ -2635,7 +2629,7 @@ STDMETHODIMP Console::GetPowerButtonHandled(BOOL *aHandled)
/* get the acpi device interface and check if the button press was handled. */
PPDMIBASE pBase;
- int vrc = PDMR3QueryDeviceLun(ptrVM, "acpi", 0, 0, &pBase);
+ int vrc = PDMR3QueryDeviceLun(ptrVM.rawUVM(), "acpi", 0, 0, &pBase);
if (RT_SUCCESS(vrc))
{
Assert(pBase);
@@ -2690,7 +2684,7 @@ STDMETHODIMP Console::GetGuestEnteredACPIMode(BOOL *aEntered)
/* get the acpi device interface and query the information. */
PPDMIBASE pBase;
- int vrc = PDMR3QueryDeviceLun(ptrVM, "acpi", 0, 0, &pBase);
+ int vrc = PDMR3QueryDeviceLun(ptrVM.rawUVM(), "acpi", 0, 0, &pBase);
if (RT_SUCCESS(vrc))
{
Assert(pBase);
@@ -2719,7 +2713,9 @@ STDMETHODIMP Console::SleepButton()
AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
- if (mMachineState != MachineState_Running) /** @todo Live Migration: ??? */
+ if ( mMachineState != MachineState_Running
+ && mMachineState != MachineState_Teleporting
+ && mMachineState != MachineState_LiveSnapshotting)
return setInvalidMachineStateError();
/* get the VM handle. */
@@ -2731,7 +2727,7 @@ STDMETHODIMP Console::SleepButton()
/* get the acpi device interface and press the sleep button. */
PPDMIBASE pBase;
- int vrc = PDMR3QueryDeviceLun(ptrVM, "acpi", 0, 0, &pBase);
+ int vrc = PDMR3QueryDeviceLun(ptrVM.rawUVM(), "acpi", 0, 0, &pBase);
if (RT_SUCCESS(vrc))
{
Assert(pBase);
@@ -2755,150 +2751,8 @@ STDMETHODIMP Console::SleepButton()
STDMETHODIMP Console::SaveState(IProgress **aProgress)
{
LogFlowThisFuncEnter();
- LogFlowThisFunc(("mMachineState=%d\n", mMachineState));
-
- CheckComArgOutPointerValid(aProgress);
-
- AutoCaller autoCaller(this);
- if (FAILED(autoCaller.rc())) return autoCaller.rc();
-
- AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
-
- if ( mMachineState != MachineState_Running
- && mMachineState != MachineState_Paused)
- {
- return setError(VBOX_E_INVALID_VM_STATE,
- tr("Cannot save the execution state as the machine is not running or paused (machine state: %s)"),
- Global::stringifyMachineState(mMachineState));
- }
-
- /* memorize the current machine state */
- MachineState_T lastMachineState = mMachineState;
-
- if (mMachineState == MachineState_Running)
- {
- /* get the VM handle. */
- SafeVMPtr ptrVM(this);
- if (!ptrVM.isOk())
- return ptrVM.rc();
-
- /* release the lock before a VMR3* call (EMT will call us back)! */
- alock.release();
- int vrc = VMR3Suspend(ptrVM);
- alock.acquire();
-
- HRESULT hrc = S_OK;
- if (RT_FAILURE(vrc))
- hrc = setError(VBOX_E_VM_ERROR, tr("Could not suspend the machine execution (%Rrc)"), vrc);
- if (FAILED(hrc))
- return hrc;
- }
-
- HRESULT rc = S_OK;
- bool fBeganSavingState = false;
- bool fTaskCreationFailed = false;
-
- do
- {
- ComPtr<IProgress> pProgress;
- Bstr stateFilePath;
-
- /*
- * request a saved state file path from the server
- * (this will set the machine state to Saving on the server to block
- * others from accessing this machine)
- */
- rc = mControl->BeginSavingState(pProgress.asOutParam(),
- stateFilePath.asOutParam());
- if (FAILED(rc))
- break;
-
- fBeganSavingState = true;
-
- /* sync the state with the server */
- setMachineStateLocally(MachineState_Saving);
-
- /* ensure the directory for the saved state file exists */
- {
- Utf8Str dir = stateFilePath;
- dir.stripFilename();
- if (!RTDirExists(dir.c_str()))
- {
- int vrc = RTDirCreateFullPath(dir.c_str(), 0700);
- if (RT_FAILURE(vrc))
- {
- rc = setError(VBOX_E_FILE_ERROR,
- tr("Could not create a directory '%s' to save the state to (%Rrc)"),
- dir.c_str(), vrc);
- break;
- }
- }
- }
-
- /* create a task object early to ensure mpVM protection is successful */
- std::auto_ptr<VMSaveTask> task(new VMSaveTask(this, pProgress,
- stateFilePath,
- lastMachineState));
- rc = task->rc();
- /*
- * If we fail here it means a PowerDown() call happened on another
- * thread while we were doing Pause() (which releases the Console lock).
- * We assign PowerDown() a higher precedence than SaveState(),
- * therefore just return the error to the caller.
- */
- if (FAILED(rc))
- {
- fTaskCreationFailed = true;
- break;
- }
-
- /* create a thread to wait until the VM state is saved */
- int vrc = RTThreadCreate(NULL, Console::saveStateThread, (void *)task.get(),
- 0, RTTHREADTYPE_MAIN_WORKER, 0, "VMSave");
- if (RT_FAILURE(vrc))
- {
- rc = setError(E_FAIL, "Could not create VMSave thread (%Rrc)", vrc);
- break;
- }
- /* task is now owned by saveStateThread(), so release it */
- task.release();
-
- /* return the progress to the caller */
- pProgress.queryInterfaceTo(aProgress);
- } while (0);
-
- if (FAILED(rc) && !fTaskCreationFailed)
- {
- /* preserve existing error info */
- ErrorInfoKeeper eik;
-
- if (fBeganSavingState)
- {
- /*
- * cancel the requested save state procedure.
- * This will reset the machine state to the state it had right
- * before calling mControl->BeginSavingState().
- */
- mControl->EndSavingState(eik.getResultCode(), eik.getText().raw());
- }
-
- if (lastMachineState == MachineState_Running)
- {
- /* restore the paused state if appropriate */
- setMachineStateLocally(MachineState_Paused);
- /* restore the running state if appropriate */
- SafeVMPtr ptrVM(this);
- if (ptrVM.isOk())
- {
- alock.release();
- VMR3Resume(ptrVM);
- alock.acquire();
- }
- }
- else
- setMachineStateLocally(lastMachineState);
- }
+ HRESULT rc = saveState(Reason_Unspecified, aProgress);
LogFlowThisFunc(("rc=%Rhrc\n", rc));
LogFlowThisFuncLeave();
@@ -3049,10 +2903,8 @@ STDMETHODIMP Console::AttachUSBDevice(IN_BSTR aId)
if (!ptrVM.isOk())
return ptrVM.rc();
- /* Don't proceed unless we've found the usb controller. */
- PPDMIBASE pBase = NULL;
- int vrc = PDMR3QueryLun(ptrVM, "usb-ohci", 0, 0, &pBase);
- if (RT_FAILURE(vrc))
+ /* Don't proceed unless we have a USB controller. */
+ if (!mfVMHasUsbController)
return setError(VBOX_E_PDM_ERROR,
tr("The virtual machine does not have a USB controller"));
@@ -3176,7 +3028,7 @@ STDMETHODIMP Console::FindUSBDeviceByAddress(IN_BSTR aAddress, IUSBDevice **aDev
STDMETHODIMP Console::FindUSBDeviceById(IN_BSTR aId, IUSBDevice **aDevice)
{
#ifdef VBOX_WITH_USB
- CheckComArgExpr(aId, Guid(aId).isEmpty() == false);
+ CheckComArgExpr(aId, Guid(aId).isValid());
CheckComArgOutPointerValid(aDevice);
*aDevice = NULL;
@@ -3359,7 +3211,6 @@ STDMETHODIMP Console::TakeSnapshot(IN_BSTR aName,
IProgress **aProgress)
{
LogFlowThisFuncEnter();
- LogFlowThisFunc(("aName='%ls' mMachineState=%d\n", aName, mMachineState));
CheckComArgStrNotEmptyOrNull(aName);
CheckComArgOutPointerValid(aProgress);
@@ -3368,6 +3219,7 @@ STDMETHODIMP Console::TakeSnapshot(IN_BSTR aName,
if (FAILED(autoCaller.rc())) return autoCaller.rc();
AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+ LogFlowThisFunc(("aName='%ls' mMachineState=%d\n", aName, mMachineState));
if (Global::IsTransient(mMachineState))
return setError(VBOX_E_INVALID_VM_STATE,
@@ -3488,7 +3340,7 @@ STDMETHODIMP Console::TakeSnapshot(IN_BSTR aName,
STDMETHODIMP Console::DeleteSnapshot(IN_BSTR aId, IProgress **aProgress)
{
- CheckComArgExpr(aId, Guid(aId).isEmpty() == false);
+ CheckComArgExpr(aId, Guid(aId).isValid());
CheckComArgOutPointerValid(aProgress);
AutoCaller autoCaller(this);
@@ -3511,7 +3363,7 @@ STDMETHODIMP Console::DeleteSnapshot(IN_BSTR aId, IProgress **aProgress)
STDMETHODIMP Console::DeleteSnapshotAndAllChildren(IN_BSTR aId, IProgress **aProgress)
{
- CheckComArgExpr(aId, Guid(aId).isEmpty() == false);
+ CheckComArgExpr(aId, Guid(aId).isValid());
CheckComArgOutPointerValid(aProgress);
AutoCaller autoCaller(this);
@@ -3534,8 +3386,8 @@ STDMETHODIMP Console::DeleteSnapshotAndAllChildren(IN_BSTR aId, IProgress **aPro
STDMETHODIMP Console::DeleteSnapshotRange(IN_BSTR aStartId, IN_BSTR aEndId, IProgress **aProgress)
{
- CheckComArgExpr(aStartId, Guid(aStartId).isEmpty() == false);
- CheckComArgExpr(aEndId, Guid(aEndId).isEmpty() == false);
+ CheckComArgExpr(aStartId, Guid(aStartId).isValid());
+ CheckComArgExpr(aEndId, Guid(aEndId).isValid());
CheckComArgOutPointerValid(aProgress);
AutoCaller autoCaller(this);
@@ -3653,17 +3505,94 @@ 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.
*
* @param aMediumAttachment The medium attachment with the new medium state.
* @param fForce Force medium chance, if it is locked or not.
- * @param pVM Safe VM handle.
+ * @param pUVM Safe VM handle.
*
* @note Locks this object for writing.
*/
-HRESULT Console::doMediumChange(IMediumAttachment *aMediumAttachment, bool fForce, PVM pVM)
+HRESULT Console::doMediumChange(IMediumAttachment *aMediumAttachment, bool fForce, PUVM pUVM)
{
AutoCaller autoCaller(this);
AssertComRCReturnRC(autoCaller.rc());
@@ -3722,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 = VMR3ReqCall(pVM,
- VMCPUID_ANY,
- &pReq,
- 0 /* no wait! */,
- VMREQFLAGS_VBOX_STATUS,
- (PFNRT)Console::changeRemovableMedium,
- 8,
- this,
- pVM,
- 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();
@@ -3755,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"));
@@ -3777,7 +3706,7 @@ HRESULT Console::doMediumChange(IMediumAttachment *aMediumAttachment, bool fForc
* @returns VBox status code.
*
* @param pThis Pointer to the Console object.
- * @param pVM The VM handle.
+ * @param pUVM The VM handle.
* @param pcszDevice The PDM device name.
* @param uInstance The PDM device instance.
* @param uLun The PDM LUN number of the drive.
@@ -3790,9 +3719,10 @@ 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,
- PVM pVM,
+DECLCALLBACK(int) Console::changeRemovableMedium(Console *pThis,
+ PUVM pUVM,
const char *pcszDevice,
unsigned uInstance,
StorageBus_T enmBus,
@@ -3800,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 = VMR3GetState(pVM);
- 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(pVM);
- 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);
- }
+ VMSTATE enmVMState = VMR3GetStateU(pUVM);
+ AssertReturn(enmVMState == VMSTATE_SUSPENDED, VERR_INVALID_STATE);
/* Determine the base path for the device instance. */
PCFGMNODE pCtlInst;
- pCtlInst = CFGMR3GetChildF(CFGMR3GetRoot(pVM), "Devices/%s/%u/", pcszDevice, uInstance);
+ 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 */,
- pVM,
- 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(pVM);
- pConsole->mVMStateChangeCallbackDisabled = false;
- AssertRC(rc);
- if (RT_FAILURE(rc))
- {
- /* too bad, we failed. try to sync the console state with the VMM state */
- vmstateChangeCallback(pVM, 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;
}
@@ -3913,11 +3780,12 @@ DECLCALLBACK(int) Console::changeRemovableMedium(Console *pConsole,
* Attach a new storage device to the VM.
*
* @param aMediumAttachment The medium attachment which is added.
- * @param pVM Safe VM handle.
+ * @param pUVM Safe VM handle.
+ * @param fSilent Flag whether to notify the guest about the attached device.
*
* @note Locks this object for writing.
*/
-HRESULT Console::doStorageDeviceAttach(IMediumAttachment *aMediumAttachment, PVM pVM)
+HRESULT Console::doStorageDeviceAttach(IMediumAttachment *aMediumAttachment, PUVM pUVM, bool fSilent)
{
AutoCaller autoCaller(this);
AssertComRCReturnRC(autoCaller.rc());
@@ -3976,25 +3844,23 @@ HRESULT Console::doStorageDeviceAttach(IMediumAttachment *aMediumAttachment, PVM
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 = VMR3ReqCall(pVM,
- VMCPUID_ANY,
- &pReq,
- 0 /* no wait! */,
- VMREQFLAGS_VBOX_STATUS,
- (PFNRT)Console::attachStorageDevice,
- 7,
- this,
- pVM,
- pszDevice,
- uInstance,
- enmBus,
- fUseHostIOCache,
- aMediumAttachment);
+ 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();
@@ -4008,6 +3874,9 @@ HRESULT Console::doStorageDeviceAttach(IMediumAttachment *aMediumAttachment, PVM
}
VMR3ReqFree(pReq);
+ if (fResume)
+ resumeAfterConfigChange(pUVM);
+
if (RT_SUCCESS(vrc))
{
LogFlowThisFunc(("Returns S_OK\n"));
@@ -4031,138 +3900,78 @@ HRESULT Console::doStorageDeviceAttach(IMediumAttachment *aMediumAttachment, PVM
* @returns VBox status code.
*
* @param pThis Pointer to the Console object.
- * @param pVM The VM handle.
+ * @param pUVM The VM handle.
* @param pcszDevice The PDM device name.
* @param uInstance The PDM device instance.
+ * @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,
- PVM pVM,
+DECLCALLBACK(int) Console::attachStorageDevice(Console *pThis,
+ PUVM pUVM,
const char *pcszDevice,
unsigned uInstance,
StorageBus_T enmBus,
bool fUseHostIOCache,
- IMediumAttachment *aMediumAtt)
+ 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 = VMR3GetState(pVM);
- 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(pVM);
- 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);
- }
+ VMSTATE enmVMState = VMR3GetStateU(pUVM);
+ AssertReturn(enmVMState == VMSTATE_SUSPENDED, VERR_INVALID_STATE);
/* Determine the base path for the device instance. */
PCFGMNODE pCtlInst;
- pCtlInst = CFGMR3GetChildF(CFGMR3GetRoot(pVM), "Devices/%s/%u/", pcszDevice, uInstance);
+ 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 */,
- true /* fHotplug */,
- pVM,
- 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(pVM);
- pConsole->mVMStateChangeCallbackDisabled = false;
- AssertRC(rc);
- if (RT_FAILURE(rc))
- {
- /* too bad, we failed. try to sync the console state with the VMM state */
- vmstateChangeCallback(pVM, 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;
}
/**
* Attach a new storage device to the VM.
*
* @param aMediumAttachment The medium attachment which is added.
- * @param pVM Safe VM handle.
+ * @param pUVM Safe VM handle.
+ * @param fSilent Flag whether to notify the guest about the detached device.
*
* @note Locks this object for writing.
*/
-HRESULT Console::doStorageDeviceDetach(IMediumAttachment *aMediumAttachment, PVM pVM)
+HRESULT Console::doStorageDeviceDetach(IMediumAttachment *aMediumAttachment, PUVM pUVM, bool fSilent)
{
AutoCaller autoCaller(this);
AssertComRCReturnRC(autoCaller.rc());
@@ -4218,24 +4027,23 @@ HRESULT Console::doStorageDeviceDetach(IMediumAttachment *aMediumAttachment, PVM
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 = VMR3ReqCall(pVM,
- VMCPUID_ANY,
- &pReq,
- 0 /* no wait! */,
- VMREQFLAGS_VBOX_STATUS,
- (PFNRT)Console::detachStorageDevice,
- 6,
- this,
- pVM,
- pszDevice,
- uInstance,
- enmBus,
- aMediumAttachment);
+ 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();
@@ -4249,6 +4057,9 @@ HRESULT Console::doStorageDeviceDetach(IMediumAttachment *aMediumAttachment, PVM
}
VMR3ReqFree(pReq);
+ if (fResume)
+ resumeAfterConfigChange(pUVM);
+
if (RT_SUCCESS(vrc))
{
LogFlowThisFunc(("Returns S_OK\n"));
@@ -4271,72 +4082,39 @@ HRESULT Console::doStorageDeviceDetach(IMediumAttachment *aMediumAttachment, PVM
* @returns VBox status code.
*
* @param pThis Pointer to the Console object.
- * @param pVM The VM handle.
+ * @param pUVM The VM handle.
* @param pcszDevice The PDM device name.
* @param uInstance The PDM device instance.
+ * @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,
- PVM pVM,
+DECLCALLBACK(int) Console::detachStorageDevice(Console *pThis,
+ PUVM pUVM,
const char *pcszDevice,
unsigned uInstance,
StorageBus_T enmBus,
- IMediumAttachment *pMediumAtt)
+ 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 = VMR3GetState(pVM);
- 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(pVM);
- 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);
- }
+ VMSTATE enmVMState = VMR3GetStateU(pUVM);
+ AssertReturn(enmVMState == VMSTATE_SUSPENDED, VERR_INVALID_STATE);
/* Determine the base path for the device instance. */
PCFGMNODE pCtlInst;
- pCtlInst = CFGMR3GetChildF(CFGMR3GetRoot(pVM), "Devices/%s/%u/", pcszDevice, uInstance);
+ pCtlInst = CFGMR3GetChildF(CFGMR3GetRootU(pUVM), "Devices/%s/%u/", pcszDevice, uInstance);
AssertReturn(pCtlInst, VERR_INTERNAL_ERROR);
#define H() AssertMsgReturn(!FAILED(hrc), ("hrc=%Rhrc\n", hrc), VERR_GENERAL_FAILURE)
@@ -4362,14 +4140,19 @@ DECLCALLBACK(int) Console::detachStorageDevice(Console *pConsole,
pLunL0 = CFGMR3GetChildF(pCtlInst, "LUN#%u", uLUN);
if (pLunL0)
{
- rc = PDMR3DeviceDetach(pVM, pcszDevice, uInstance, uLUN, 0);
+ uint32_t fFlags = 0;
+
+ if (fSilent)
+ fFlags |= PDM_TACH_FLAGS_NOT_HOT_PLUG;
+
+ rc = PDMR3DeviceDetach(pUVM, pcszDevice, uInstance, uLUN, fFlags);
if (rc == VERR_PDM_NO_DRIVER_ATTACHED_TO_LUN)
rc = VINF_SUCCESS;
AssertRCReturn(rc, rc);
CFGMR3RemoveNode(pLunL0);
Utf8Str devicePath = Utf8StrFmt("%s/%u/LUN#%u", pcszDevice, uInstance, uLUN);
- pConsole->mapMediumAttachments.erase(devicePath);
+ pThis->mapMediumAttachments.erase(devicePath);
}
else
@@ -4377,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(pVM);
- pConsole->mVMStateChangeCallbackDisabled = false;
- AssertRC(rc);
- if (RT_FAILURE(rc))
- {
- /* too bad, we failed. try to sync the console state with the VMM state */
- vmstateChangeCallback(pVM, 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;
}
@@ -4423,7 +4180,7 @@ HRESULT Console::onNetworkAdapterChange(INetworkAdapter *aNetworkAdapter, BOOL c
HRESULT rc = S_OK;
- /* don't trigger network change if the VM isn't running */
+ /* don't trigger network changes if the VM isn't running */
SafeVMPtrQuiet ptrVM(this);
if (ptrVM.isOk())
{
@@ -4456,7 +4213,7 @@ HRESULT Console::onNetworkAdapterChange(INetworkAdapter *aNetworkAdapter, BOOL c
alock.release();
PPDMIBASE pBase;
- int vrc = PDMR3QueryDeviceLun(ptrVM, pszAdapterName, ulInstance, 0, &pBase);
+ int vrc = PDMR3QueryDeviceLun(ptrVM.rawUVM(), pszAdapterName, ulInstance, 0, &pBase);
if (RT_SUCCESS(vrc))
{
Assert(pBase);
@@ -4473,7 +4230,7 @@ HRESULT Console::onNetworkAdapterChange(INetworkAdapter *aNetworkAdapter, BOOL c
}
if (RT_SUCCESS(vrc) && changeAdapter)
{
- VMSTATE enmVMState = VMR3GetState(ptrVM);
+ VMSTATE enmVMState = VMR3GetStateU(ptrVM.rawUVM());
if ( enmVMState == VMSTATE_RUNNING /** @todo LiveMigration: Forbid or deal correctly with the _LS variants */
|| enmVMState == VMSTATE_SUSPENDED)
{
@@ -4483,7 +4240,7 @@ HRESULT Console::onNetworkAdapterChange(INetworkAdapter *aNetworkAdapter, BOOL c
ComAssertRC(vrc);
}
- rc = doNetworkAdapterChange(ptrVM, pszAdapterName, ulInstance, 0, aNetworkAdapter);
+ rc = doNetworkAdapterChange(ptrVM.rawUVM(), pszAdapterName, ulInstance, 0, aNetworkAdapter);
if (fTraceEnabled && fCableConnected && pINetCfg)
{
@@ -4536,7 +4293,7 @@ HRESULT Console::onNATRedirectRuleChange(ULONG ulInstance, BOOL aNatRuleRemove,
HRESULT rc = S_OK;
- /* don't trigger nat engine change if the VM isn't running */
+ /* don't trigger NAT engine changes if the VM isn't running */
SafeVMPtrQuiet ptrVM(this);
if (ptrVM.isOk())
{
@@ -4563,7 +4320,7 @@ HRESULT Console::onNATRedirectRuleChange(ULONG ulInstance, BOOL aNatRuleRemove,
const char *pszAdapterName = networkAdapterTypeToName(adapterType);
PPDMIBASE pBase;
- int vrc = PDMR3QueryLun(ptrVM, pszAdapterName, ulInstance, 0, &pBase);
+ int vrc = PDMR3QueryLun(ptrVM.rawUVM(), pszAdapterName, ulInstance, 0, &pBase);
if (RT_FAILURE(vrc))
{
ComAssertRC(vrc);
@@ -4596,8 +4353,8 @@ HRESULT Console::onNATRedirectRuleChange(ULONG ulInstance, BOOL aNatRuleRemove,
bool fUdp = aProto == NATProtocol_UDP;
vrc = pNetNatCfg->pfnRedirectRuleCommand(pNetNatCfg, !!aNatRuleRemove, fUdp,
- Utf8Str(aHostIP).c_str(), aHostPort, Utf8Str(aGuestIP).c_str(),
- aGuestPort);
+ Utf8Str(aHostIP).c_str(), (uint16_t)aHostPort, Utf8Str(aGuestIP).c_str(),
+ (uint16_t)aGuestPort);
if (RT_FAILURE(vrc))
rc = E_FAIL;
} while (0); /* break loop */
@@ -4608,19 +4365,28 @@ HRESULT Console::onNATRedirectRuleChange(ULONG ulInstance, BOOL aNatRuleRemove,
return rc;
}
+VMMDevMouseInterface *Console::getVMMDevMouseInterface()
+{
+ return m_pVMMDev;
+}
+
+DisplayMouseInterface *Console::getDisplayMouseInterface()
+{
+ return mDisplay;
+}
/**
* Process a network adaptor change.
*
* @returns COM status code.
*
- * @parma pVM The VM handle (caller hold this safely).
+ * @parma pUVM The VM handle (caller hold this safely).
* @param pszDevice The PDM device name.
* @param uInstance The PDM device instance.
* @param uLun The PDM LUN number of the drive.
* @param aNetworkAdapter The network adapter whose attachment needs to be changed
*/
-HRESULT Console::doNetworkAdapterChange(PVM pVM,
+HRESULT Console::doNetworkAdapterChange(PUVM pUVM,
const char *pszDevice,
unsigned uInstance,
unsigned uLun,
@@ -4632,10 +4398,13 @@ HRESULT Console::doNetworkAdapterChange(PVM pVM,
AutoCaller autoCaller(this);
AssertComRCReturnRC(autoCaller.rc());
- /* Get the VM handle. */
- SafeVMPtr ptrVM(this);
- if (!ptrVM.isOk())
- return ptrVM.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
@@ -4643,9 +4412,9 @@ HRESULT Console::doNetworkAdapterChange(PVM pVM,
* here to make requests from under the lock in order to serialize them.
*/
PVMREQ pReq;
- int vrc = VMR3ReqCall(pVM, 0 /*idDstCpu*/, &pReq, 0 /* no wait! */, VMREQFLAGS_VBOX_STATUS,
- (PFNRT) Console::changeNetworkAttachment, 6,
- this, ptrVM.raw(), pszDevice, uInstance, uLun, aNetworkAdapter);
+ int vrc = VMR3ReqCallU(pUVM, 0 /*idDstCpu*/, &pReq, 0 /* no wait! */, VMREQFLAGS_VBOX_STATUS,
+ (PFNRT)changeNetworkAttachment, 6,
+ this, pUVM, pszDevice, uInstance, uLun, aNetworkAdapter);
if (vrc == VERR_TIMEOUT || RT_SUCCESS(vrc))
{
@@ -4656,6 +4425,9 @@ HRESULT Console::doNetworkAdapterChange(PVM pVM,
}
VMR3ReqFree(pReq);
+ if (fResume)
+ resumeAfterConfigChange(pUVM);
+
if (RT_SUCCESS(vrc))
{
LogFlowThisFunc(("Returns S_OK\n"));
@@ -4674,7 +4446,7 @@ HRESULT Console::doNetworkAdapterChange(PVM pVM,
* @returns VBox status code.
*
* @param pThis Pointer to the Console object.
- * @param pVM The VM handle.
+ * @param pUVM The VM handle.
* @param pszDevice The PDM device name.
* @param uInstance The PDM device instance.
* @param uLun The PDM LUN number of the drive.
@@ -4682,9 +4454,10 @@ HRESULT Console::doNetworkAdapterChange(PVM pVM,
*
* @thread EMT
* @note Locks the Console object for writing.
+ * @note The VM must not be running.
*/
DECLCALLBACK(int) Console::changeNetworkAttachment(Console *pThis,
- PVM pVM,
+ PUVM pUVM,
const char *pszDevice,
unsigned uInstance,
unsigned uLun,
@@ -4717,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 = VMR3GetState(pVM);
- 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(pVM);
- 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;
+ VMSTATE enmVMState = VMR3GetStateU(pUVM);
+ AssertReturn(enmVMState == VMSTATE_SUSPENDED, VERR_INVALID_STATE);
PCFGMNODE pCfg = NULL; /* /Devices/Dev/.../Config/ */
PCFGMNODE pLunL0 = NULL; /* /Devices/Dev/0/LUN#0/ */
- PCFGMNODE pInst = CFGMR3GetChildF(CFGMR3GetRoot(pVM), "Devices/%s/%d/", pszDevice, uInstance);
+ 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(pVM);
- pThis->mVMStateChangeCallbackDisabled = false;
- AssertRC(rc);
- if (RT_FAILURE(rc))
- {
- /* too bad, we failed. try to sync the console state with the VMM state */
- vmstateChangeCallback(pVM, 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;
}
@@ -4850,11 +4568,11 @@ HRESULT Console::onMediumChange(IMediumAttachment *aMediumAttachment, BOOL aForc
HRESULT rc = S_OK;
- /* don't trigger medium change if the VM isn't running */
+ /* don't trigger medium changes if the VM isn't running */
SafeVMPtrQuiet ptrVM(this);
if (ptrVM.isOk())
{
- rc = doMediumChange(aMediumAttachment, !!aForce, ptrVM);
+ rc = doMediumChange(aMediumAttachment, !!aForce, ptrVM.rawUVM());
ptrVM.release();
}
@@ -4880,14 +4598,14 @@ HRESULT Console::onCPUChange(ULONG aCPU, BOOL aRemove)
HRESULT rc = S_OK;
- /* don't trigger CPU change if the VM isn't running */
+ /* don't trigger CPU changes if the VM isn't running */
SafeVMPtrQuiet ptrVM(this);
if (ptrVM.isOk())
{
if (aRemove)
- rc = doCPURemove(aCPU, ptrVM);
+ rc = doCPURemove(aCPU, ptrVM.rawUVM());
else
- rc = doCPUAdd(aCPU, ptrVM);
+ rc = doCPUAdd(aCPU, ptrVM.rawUVM());
ptrVM.release();
}
@@ -4925,7 +4643,7 @@ HRESULT Console::onCPUExecutionCapChange(ULONG aExecutionCap)
)
{
/* No need to call in the EMT thread. */
- rc = VMR3SetCpuExecutionCap(ptrVM, aExecutionCap);
+ rc = VMR3SetCpuExecutionCap(ptrVM.rawUVM(), aExecutionCap);
}
else
rc = setInvalidMachineStateError();
@@ -4959,7 +4677,7 @@ HRESULT Console::onClipboardModeChange(ClipboardMode_T aClipboardMode)
HRESULT rc = S_OK;
- /* don't trigger the Clipboard mode change if the VM isn't running */
+ /* don't trigger the clipboard mode change if the VM isn't running */
SafeVMPtrQuiet ptrVM(this);
if (ptrVM.isOk())
{
@@ -4999,7 +4717,7 @@ HRESULT Console::onDragAndDropModeChange(DragAndDropMode_T aDragAndDropMode)
HRESULT rc = S_OK;
- /* don't trigger the Drag'n'drop mode change if the VM isn't running */
+ /* don't trigger the drag'n'drop mode change if the VM isn't running */
SafeVMPtrQuiet ptrVM(this);
if (ptrVM.isOk())
{
@@ -5037,42 +4755,63 @@ HRESULT Console::onVRDEServerChange(BOOL aRestart)
HRESULT rc = S_OK;
- if ( mVRDEServer
- && ( mMachineState == MachineState_Running
- || mMachineState == MachineState_Teleporting
- || mMachineState == MachineState_LiveSnapshotting
- )
- )
+ /* don't trigger VRDE server changes if the VM isn't running */
+ SafeVMPtrQuiet ptrVM(this);
+ if (ptrVM.isOk())
{
- BOOL vrdpEnabled = FALSE;
+ /* Serialize. */
+ if (mfVRDEChangeInProcess)
+ mfVRDEChangePending = true;
+ else
+ {
+ do {
+ mfVRDEChangeInProcess = true;
+ mfVRDEChangePending = false;
+
+ if ( mVRDEServer
+ && ( mMachineState == MachineState_Running
+ || mMachineState == MachineState_Teleporting
+ || mMachineState == MachineState_LiveSnapshotting
+ || mMachineState == MachineState_Paused
+ )
+ )
+ {
+ BOOL vrdpEnabled = FALSE;
- rc = mVRDEServer->COMGETTER(Enabled)(&vrdpEnabled);
- ComAssertComRCRetRC(rc);
+ rc = mVRDEServer->COMGETTER(Enabled)(&vrdpEnabled);
+ ComAssertComRCRetRC(rc);
- if (aRestart)
- {
- /* VRDP server may call this Console object back from other threads (VRDP INPUT or OUTPUT). */
- alock.release();
+ if (aRestart)
+ {
+ /* VRDP server may call this Console object back from other threads (VRDP INPUT or OUTPUT). */
+ alock.release();
- if (vrdpEnabled)
- {
- // If there was no VRDP server started the 'stop' will do nothing.
- // However if a server was started and this notification was called,
- // we have to restart the server.
- mConsoleVRDPServer->Stop();
+ if (vrdpEnabled)
+ {
+ // If there was no VRDP server started the 'stop' will do nothing.
+ // However if a server was started and this notification was called,
+ // we have to restart the server.
+ mConsoleVRDPServer->Stop();
+
+ if (RT_FAILURE(mConsoleVRDPServer->Launch()))
+ rc = E_FAIL;
+ else
+ mConsoleVRDPServer->EnableConnections();
+ }
+ else
+ mConsoleVRDPServer->Stop();
- if (RT_FAILURE(mConsoleVRDPServer->Launch()))
- rc = E_FAIL;
+ alock.acquire();
+ }
+ }
else
- mConsoleVRDPServer->EnableConnections();
- }
- else
- {
- mConsoleVRDPServer->Stop();
- }
+ rc = setInvalidMachineStateError();
- alock.acquire();
+ mfVRDEChangeInProcess = false;
+ } while (mfVRDEChangePending && SUCCEEDED(rc));
}
+
+ ptrVM.release();
}
/* notify console callbacks on success */
@@ -5093,6 +4832,55 @@ void Console::onVRDEServerInfoChange()
fireVRDEServerInfoChangedEvent(mEventSource);
}
+HRESULT Console::onVideoCaptureChange()
+{
+ AutoCaller autoCaller(this);
+ AssertComRCReturnRC(autoCaller.rc());
+
+ AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ HRESULT rc = S_OK;
+
+ /* don't trigger video capture changes if the VM isn't running */
+ SafeVMPtrQuiet ptrVM(this);
+ if (ptrVM.isOk())
+ {
+ BOOL fEnabled;
+ rc = mMachine->COMGETTER(VideoCaptureEnabled)(&fEnabled);
+ SafeArray<BOOL> screens;
+ if (SUCCEEDED(rc))
+ rc = mMachine->COMGETTER(VideoCaptureScreens)(ComSafeArrayAsOutParam(screens));
+ if (mDisplay)
+ {
+ int vrc = VINF_SUCCESS;
+ if (SUCCEEDED(rc))
+ vrc = mDisplay->VideoCaptureEnableScreens(ComSafeArrayAsInParam(screens));
+ if (RT_SUCCESS(vrc))
+ {
+ if (fEnabled)
+ {
+ vrc = mDisplay->VideoCaptureStart();
+ if (RT_FAILURE(vrc))
+ rc = setError(E_FAIL, tr("Unable to start video capturing (%Rrc)"), vrc);
+ }
+ else
+ mDisplay->VideoCaptureStop();
+ }
+ else
+ rc = setError(E_FAIL, tr("Unable to set screens for capturing (%Rrc)"), vrc);
+ }
+ ptrVM.release();
+ }
+
+ /* notify console callbacks on success */
+ if (SUCCEEDED(rc))
+ {
+ alock.release();
+ fireVideoCaptureChangedEvent(mEventSource);
+ }
+
+ return rc;
+}
/**
* Called by IInternalSessionControl::OnUSBControllerChange().
@@ -5181,7 +4969,7 @@ HRESULT Console::onUSBDeviceAttach(IUSBDevice *aDevice, IVirtualBoxErrorInfo *aE
}
/* Don't proceed unless there's at least one USB hub. */
- if (!PDMR3USBHasHub(ptrVM))
+ if (!PDMR3UsbHasHub(ptrVM.rawUVM()))
{
LogFlowThisFunc(("Attach request ignored (no USB controller).\n"));
return E_FAIL;
@@ -5318,7 +5106,7 @@ HRESULT Console::onBandwidthGroupChange(IBandwidthGroup *aBandwidthGroup)
HRESULT rc = S_OK;
- /* don't trigger the CPU priority change if the VM isn't running */
+ /* don't trigger bandwidth group changes if the VM isn't running */
SafeVMPtrQuiet ptrVM(this);
if (ptrVM.isOk())
{
@@ -5341,12 +5129,10 @@ HRESULT Console::onBandwidthGroupChange(IBandwidthGroup *aBandwidthGroup)
{
int vrc = VINF_SUCCESS;
if (enmType == BandwidthGroupType_Disk)
- vrc = PDMR3AsyncCompletionBwMgrSetMaxForFile(ptrVM, Utf8Str(strName).c_str(),
- cMax);
+ vrc = PDMR3AsyncCompletionBwMgrSetMaxForFile(ptrVM.rawUVM(), Utf8Str(strName).c_str(), (uint32_t)cMax);
#ifdef VBOX_WITH_NETSHAPER
else if (enmType == BandwidthGroupType_Network)
- vrc = PDMR3NsBwGroupSetLimit(ptrVM, Utf8Str(strName).c_str(),
- cMax);
+ vrc = PDMR3NsBwGroupSetLimit(ptrVM.rawUVM(), Utf8Str(strName).c_str(), cMax);
else
rc = E_NOTIMPL;
#endif /* VBOX_WITH_NETSHAPER */
@@ -5374,7 +5160,7 @@ HRESULT Console::onBandwidthGroupChange(IBandwidthGroup *aBandwidthGroup)
*
* @note Locks this object for writing.
*/
-HRESULT Console::onStorageDeviceChange(IMediumAttachment *aMediumAttachment, BOOL aRemove)
+HRESULT Console::onStorageDeviceChange(IMediumAttachment *aMediumAttachment, BOOL aRemove, BOOL aSilent)
{
LogFlowThisFunc(("\n"));
@@ -5383,25 +5169,67 @@ HRESULT Console::onStorageDeviceChange(IMediumAttachment *aMediumAttachment, BOO
HRESULT rc = S_OK;
- /* don't trigger medium change if the VM isn't running */
+ /* don't trigger medium changes if the VM isn't running */
SafeVMPtrQuiet ptrVM(this);
if (ptrVM.isOk())
{
if (aRemove)
- rc = doStorageDeviceDetach(aMediumAttachment, ptrVM);
+ rc = doStorageDeviceDetach(aMediumAttachment, ptrVM.rawUVM(), RT_BOOL(aSilent));
else
- rc = doStorageDeviceAttach(aMediumAttachment, ptrVM);
+ rc = doStorageDeviceAttach(aMediumAttachment, ptrVM.rawUVM(), RT_BOOL(aSilent));
ptrVM.release();
}
/* notify console callbacks on success */
if (SUCCEEDED(rc))
- fireStorageDeviceChangedEvent(mEventSource, aMediumAttachment, aRemove);
+ fireStorageDeviceChangedEvent(mEventSource, aMediumAttachment, aRemove, aSilent);
LogFlowThisFunc(("Leaving rc=%#x\n", rc));
return rc;
}
+HRESULT Console::onExtraDataChange(IN_BSTR aMachineId, IN_BSTR aKey, IN_BSTR aVal)
+{
+ LogFlowThisFunc(("\n"));
+
+ AutoCaller autoCaller(this);
+ AssertComRCReturnRC(autoCaller.rc());
+
+ if (!aMachineId)
+ return S_OK;
+
+ HRESULT hrc = S_OK;
+ Bstr idMachine(aMachineId);
+ Bstr idSelf;
+ hrc = mMachine->COMGETTER(Id)(idSelf.asOutParam());
+ if ( FAILED(hrc)
+ || idMachine != idSelf)
+ return hrc;
+
+ /* don't do anything if the VM isn't running */
+ SafeVMPtrQuiet ptrVM(this);
+ if (ptrVM.isOk())
+ {
+ Bstr strKey(aKey);
+ Bstr strVal(aVal);
+
+ if (strKey == "VBoxInternal2/TurnResetIntoPowerOff")
+ {
+ int vrc = VMR3SetPowerOffInsteadOfReset(ptrVM.rawUVM(), strVal == "1");
+ AssertRC(vrc);
+ }
+
+ ptrVM.release();
+ }
+
+ /* notify console callbacks on success */
+ if (SUCCEEDED(hrc))
+ fireExtraDataChangedEvent(mEventSource, aMachineId, aKey, aVal);
+
+ LogFlowThisFunc(("Leaving hrc=%#x\n", hrc));
+ return hrc;
+}
+
/**
* @note Temporarily locks this object for writing.
*/
@@ -5423,12 +5251,13 @@ HRESULT Console::getGuestProperty(IN_BSTR aName, BSTR *aValue,
AutoCaller autoCaller(this);
AssertComRCReturnRC(autoCaller.rc());
- /* protect mpVM (if not NULL) */
- AutoVMCallerWeak autoVMCaller(this);
- if (FAILED(autoVMCaller.rc())) return autoVMCaller.rc();
+ /* protect mpUVM (if not NULL) */
+ SafeVMPtrQuiet ptrVM(this);
+ if (FAILED(ptrVM.rc()))
+ return ptrVM.rc();
/* Note: validity of mVMMDev which is bound to uninit() is guaranteed by
- * autoVMCaller, so there is no need to hold a lock of this */
+ * ptrVM, so there is no need to hold a lock of this */
HRESULT rc = E_UNEXPECTED;
using namespace guestProp;
@@ -5492,51 +5321,56 @@ HRESULT Console::setGuestProperty(IN_BSTR aName, IN_BSTR aValue, IN_BSTR aFlags)
#ifndef VBOX_WITH_GUEST_PROPS
ReturnComNotImplemented();
#else /* VBOX_WITH_GUEST_PROPS */
- if (!VALID_PTR(aName))
- return E_INVALIDARG;
- if ((aValue != NULL) && !VALID_PTR(aValue))
- return E_INVALIDARG;
- if ((aFlags != NULL) && !VALID_PTR(aFlags))
- return E_INVALIDARG;
+ if (!RT_VALID_PTR(aName))
+ return setError(E_INVALIDARG, tr("Name cannot be NULL or an invalid pointer"));
+ if (aValue != NULL && !RT_VALID_PTR(aValue))
+ return setError(E_INVALIDARG, tr("Invalid value pointer"));
+ if (aFlags != NULL && !RT_VALID_PTR(aFlags))
+ return setError(E_INVALIDARG, tr("Invalid flags pointer"));
AutoCaller autoCaller(this);
AssertComRCReturnRC(autoCaller.rc());
- /* protect mpVM (if not NULL) */
- AutoVMCallerWeak autoVMCaller(this);
- if (FAILED(autoVMCaller.rc())) return autoVMCaller.rc();
+ /* protect mpUVM (if not NULL) */
+ SafeVMPtrQuiet ptrVM(this);
+ if (FAILED(ptrVM.rc()))
+ return ptrVM.rc();
/* Note: validity of mVMMDev which is bound to uninit() is guaranteed by
- * autoVMCaller, so there is no need to hold a lock of this */
+ * ptrVM, so there is no need to hold a lock of this */
- HRESULT rc = E_UNEXPECTED;
using namespace guestProp;
VBOXHGCMSVCPARM parm[3];
- Utf8Str Utf8Name = aName;
- int vrc = VINF_SUCCESS;
+ Utf8Str Utf8Name = aName;
parm[0].type = VBOX_HGCM_SVC_PARM_PTR;
parm[0].u.pointer.addr = (void*)Utf8Name.c_str();
/* The + 1 is the null terminator */
parm[0].u.pointer.size = (uint32_t)Utf8Name.length() + 1;
- Utf8Str Utf8Value = aValue;
+
+ Utf8Str Utf8Value;
if (aValue != NULL)
{
+ Utf8Value = aValue;
parm[1].type = VBOX_HGCM_SVC_PARM_PTR;
- parm[1].u.pointer.addr = (void*)Utf8Value.c_str();
+ parm[1].u.pointer.addr = (void *)Utf8Value.c_str();
/* The + 1 is the null terminator */
parm[1].u.pointer.size = (uint32_t)Utf8Value.length() + 1;
}
- Utf8Str Utf8Flags = aFlags;
+
+ Utf8Str Utf8Flags;
if (aFlags != NULL)
{
+ Utf8Flags = aFlags;
parm[2].type = VBOX_HGCM_SVC_PARM_PTR;
parm[2].u.pointer.addr = (void*)Utf8Flags.c_str();
/* The + 1 is the null terminator */
parm[2].u.pointer.size = (uint32_t)Utf8Flags.length() + 1;
}
- if ((aValue != NULL) && (aFlags != NULL))
+
+ int vrc;
+ if (aValue != NULL && aFlags != NULL)
vrc = m_pVMMDev->hgcmHostCall("VBoxGuestPropSvc", SET_PROP_HOST,
3, &parm[0]);
else if (aValue != NULL)
@@ -5545,13 +5379,12 @@ HRESULT Console::setGuestProperty(IN_BSTR aName, IN_BSTR aValue, IN_BSTR aFlags)
else
vrc = m_pVMMDev->hgcmHostCall("VBoxGuestPropSvc", DEL_PROP_HOST,
1, &parm[0]);
+ HRESULT hrc;
if (RT_SUCCESS(vrc))
- rc = S_OK;
+ hrc = S_OK;
else
- rc = setError(E_UNEXPECTED,
- tr("The service call failed with the error %Rrc"),
- vrc);
- return rc;
+ hrc = setError(E_UNEXPECTED, tr("The service call failed with the error %Rrc"), vrc);
+ return hrc;
#endif /* VBOX_WITH_GUEST_PROPS */
}
@@ -5582,9 +5415,10 @@ HRESULT Console::enumerateGuestProperties(IN_BSTR aPatterns,
AutoCaller autoCaller(this);
AssertComRCReturnRC(autoCaller.rc());
- /* protect mpVM (if not NULL) */
+ /* protect mpUVM (if not NULL) */
AutoVMCallerWeak autoVMCaller(this);
- if (FAILED(autoVMCaller.rc())) return autoVMCaller.rc();
+ if (FAILED(autoVMCaller.rc()))
+ return autoVMCaller.rc();
/* Note: validity of mVMMDev which is bound to uninit() is guaranteed by
* autoVMCaller, so there is no need to hold a lock of this */
@@ -5614,10 +5448,6 @@ static int onlineMergeMediumProgress(void *pvUser, unsigned uPercentage)
*/
HRESULT Console::onlineMergeMedium(IMediumAttachment *aMediumAttachment,
ULONG aSourceIdx, ULONG aTargetIdx,
- IMedium *aSource, IMedium *aTarget,
- BOOL aMergeForward,
- IMedium *aParentForTarget,
- ComSafeArrayIn(IMedium *, aChildrenToReparent),
IProgress *aProgress)
{
AutoCaller autoCaller(this);
@@ -5711,34 +5541,22 @@ HRESULT Console::onlineMergeMedium(IMediumAttachment *aMediumAttachment,
alock.release();
/* Pause the VM, as it might have pending IO on this drive */
- VMSTATE enmVMState = VMR3GetState(ptrVM);
+ VMSTATE enmVMState = VMR3GetStateU(ptrVM.rawUVM());
if (mMachineState == MachineState_DeletingSnapshotOnline)
{
LogFlowFunc(("Suspending the VM...\n"));
/* disable the callback to prevent Console-level state change */
mVMStateChangeCallbackDisabled = true;
- int vrc2 = VMR3Suspend(ptrVM);
+ int vrc2 = VMR3Suspend(ptrVM.rawUVM(), VMSUSPENDREASON_RECONFIG);
mVMStateChangeCallbackDisabled = false;
AssertRCReturn(vrc2, E_FAIL);
}
- vrc = VMR3ReqCallWait(ptrVM,
- VMCPUID_ANY,
- (PFNRT)reconfigureMediumAttachment,
- 13,
- this,
- ptrVM.raw(),
- 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)
@@ -5746,13 +5564,13 @@ HRESULT Console::onlineMergeMedium(IMediumAttachment *aMediumAttachment,
LogFlowFunc(("Resuming the VM...\n"));
/* disable the callback to prevent Console-level state change */
mVMStateChangeCallbackDisabled = true;
- int vrc2 = VMR3Resume(ptrVM);
+ int vrc2 = VMR3Resume(ptrVM.rawUVM(), VMRESUMEREASON_RECONFIG);
mVMStateChangeCallbackDisabled = false;
if (RT_FAILURE(vrc2))
{
/* too bad, we failed. try to sync the console state with the VMM state */
AssertLogRelRC(vrc2);
- vmstateChangeCallback(ptrVM, VMSTATE_SUSPENDED, enmVMState, this);
+ vmstateChangeCallback(ptrVM.rawUVM(), VMSTATE_SUSPENDED, enmVMState, this);
}
}
@@ -5763,7 +5581,7 @@ HRESULT Console::onlineMergeMedium(IMediumAttachment *aMediumAttachment,
PPDMIBASE pIBase = NULL;
PPDMIMEDIA pIMedium = NULL;
- vrc = PDMR3QueryDriverOnLun(ptrVM, pcszDevice, uInstance, uLUN, "VD", &pIBase);
+ vrc = PDMR3QueryDriverOnLun(ptrVM.rawUVM(), pcszDevice, uInstance, uLUN, "VD", &pIBase);
if (RT_SUCCESS(vrc))
{
if (pIBase)
@@ -5782,39 +5600,25 @@ HRESULT Console::onlineMergeMedium(IMediumAttachment *aMediumAttachment,
return setError(E_FAIL, tr("Failed to perform an online medium merge (%Rrc)"), vrc);
/* Pause the VM, as it might have pending IO on this drive */
- enmVMState = VMR3GetState(ptrVM);
+ enmVMState = VMR3GetStateU(ptrVM.rawUVM());
if (mMachineState == MachineState_DeletingSnapshotOnline)
{
LogFlowFunc(("Suspending the VM...\n"));
/* disable the callback to prevent Console-level state change */
mVMStateChangeCallbackDisabled = true;
- int vrc2 = VMR3Suspend(ptrVM);
+ int vrc2 = VMR3Suspend(ptrVM.rawUVM(), VMSUSPENDREASON_RECONFIG);
mVMStateChangeCallbackDisabled = false;
AssertRCReturn(vrc2, E_FAIL);
}
/* Update medium chain and state now, so that the VM can continue. */
- rc = mControl->FinishOnlineMergeMedium(aMediumAttachment, aSource, aTarget,
- aMergeForward, aParentForTarget,
- ComSafeArrayInArg(aChildrenToReparent));
-
- vrc = VMR3ReqCallWait(ptrVM,
- VMCPUID_ANY,
- (PFNRT)reconfigureMediumAttachment,
- 13,
- this,
- ptrVM.raw(),
- pcszDevice,
- uInstance,
- enmBus,
- fUseHostIOCache,
- fBuiltinIOCache,
- false /* fSetupMerge */,
- 0 /* uMergeSource */,
- 0 /* uMergeTarget */,
- aMediumAttachment,
- mMachineState,
- &rc);
+ 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);
/* error handling is after resuming the VM */
if (mMachineState == MachineState_DeletingSnapshotOnline)
@@ -5822,13 +5626,13 @@ HRESULT Console::onlineMergeMedium(IMediumAttachment *aMediumAttachment,
LogFlowFunc(("Resuming the VM...\n"));
/* disable the callback to prevent Console-level state change */
mVMStateChangeCallbackDisabled = true;
- int vrc2 = VMR3Resume(ptrVM);
+ int vrc2 = VMR3Resume(ptrVM.rawUVM(), VMRESUMEREASON_RECONFIG);
mVMStateChangeCallbackDisabled = false;
AssertRC(vrc2);
if (RT_FAILURE(vrc2))
{
/* too bad, we failed. try to sync the console state with the VMM state */
- vmstateChangeCallback(ptrVM, VMSTATE_SUSPENDED, enmVMState, this);
+ vmstateChangeCallback(ptrVM.rawUVM(), VMSTATE_SUSPENDED, enmVMState, this);
}
}
@@ -5842,6 +5646,23 @@ HRESULT Console::onlineMergeMedium(IMediumAttachment *aMediumAttachment,
/**
+ * Load an HGCM service.
+ *
+ * Main purpose of this method is to allow extension packs to load HGCM
+ * service modules, which they can't, because the HGCM functionality lives
+ * in module VBoxC (and ConsoleImpl.cpp is part of it and thus can call it).
+ * Extension modules must not link directly against VBoxC, (XP)COM is
+ * handling this.
+ */
+int Console::hgcmLoadService(const char *pszServiceLibrary, const char *pszServiceName)
+{
+ /* Everyone seems to delegate all HGCM calls to VMMDev, so stick to this
+ * convention. Adds one level of indirection for no obvious reason. */
+ AssertPtrReturn(m_pVMMDev, VERR_INVALID_STATE);
+ return m_pVMMDev->hgcmLoadService(pszServiceLibrary, pszServiceName);
+}
+
+/**
* Merely passes the call to Guest::enableVMMStatistics().
*/
void Console::enableVMMStatistics(BOOL aEnable)
@@ -5851,6 +5672,289 @@ void Console::enableVMMStatistics(BOOL aEnable)
}
/**
+ * Worker for Console::Pause and internal entry point for pausing a VM for
+ * a specific reason.
+ */
+HRESULT Console::pause(Reason_T aReason)
+{
+ LogFlowThisFuncEnter();
+
+ AutoCaller autoCaller(this);
+ if (FAILED(autoCaller.rc())) return autoCaller.rc();
+
+ AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ switch (mMachineState)
+ {
+ case MachineState_Running:
+ case MachineState_Teleporting:
+ case MachineState_LiveSnapshotting:
+ break;
+
+ case MachineState_Paused:
+ case MachineState_TeleportingPausedVM:
+ case MachineState_Saving:
+ return setError(VBOX_E_INVALID_VM_STATE, tr("Already paused"));
+
+ default:
+ return setInvalidMachineStateError();
+ }
+
+ /* get the VM handle. */
+ SafeVMPtr ptrVM(this);
+ if (!ptrVM.isOk())
+ return ptrVM.rc();
+
+ /* release the lock before a VMR3* call (EMT will call us back)! */
+ alock.release();
+
+ LogFlowThisFunc(("Sending PAUSE request...\n"));
+ if (aReason != Reason_Unspecified)
+ LogRel(("Pausing VM execution, reason \"%s\"\n", Global::stringifyReason(aReason)));
+
+ /** @todo r=klaus make use of aReason */
+ VMSUSPENDREASON enmReason = VMSUSPENDREASON_USER;
+ if (aReason == Reason_HostSuspend)
+ enmReason = VMSUSPENDREASON_HOST_SUSPEND;
+ else if (aReason == Reason_HostBatteryLow)
+ enmReason = VMSUSPENDREASON_HOST_BATTERY_LOW;
+ int vrc = VMR3Suspend(ptrVM.rawUVM(), enmReason);
+
+ HRESULT hrc = S_OK;
+ if (RT_FAILURE(vrc))
+ hrc = setError(VBOX_E_VM_ERROR, tr("Could not suspend the machine execution (%Rrc)"), vrc);
+
+ LogFlowThisFunc(("hrc=%Rhrc\n", hrc));
+ LogFlowThisFuncLeave();
+ return hrc;
+}
+
+/**
+ * Worker for Console::Resume and internal entry point for resuming a VM for
+ * a specific reason.
+ */
+HRESULT Console::resume(Reason_T aReason)
+{
+ LogFlowThisFuncEnter();
+
+ AutoCaller autoCaller(this);
+ if (FAILED(autoCaller.rc())) return autoCaller.rc();
+
+ AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ if (mMachineState != MachineState_Paused)
+ return setError(VBOX_E_INVALID_VM_STATE,
+ tr("Cannot resume the machine as it is not paused (machine state: %s)"),
+ Global::stringifyMachineState(mMachineState));
+
+ /* get the VM handle. */
+ SafeVMPtr ptrVM(this);
+ if (!ptrVM.isOk())
+ return ptrVM.rc();
+
+ /* release the lock before a VMR3* call (EMT will call us back)! */
+ alock.release();
+
+ LogFlowThisFunc(("Sending RESUME request...\n"));
+ if (aReason != Reason_Unspecified)
+ LogRel(("Resuming VM execution, reason \"%s\"\n", Global::stringifyReason(aReason)));
+
+ int vrc;
+ if (VMR3GetStateU(ptrVM.rawUVM()) == VMSTATE_CREATED)
+ {
+#ifdef VBOX_WITH_EXTPACK
+ vrc = mptrExtPackManager->callAllVmPowerOnHooks(this, VMR3GetVM(ptrVM.rawUVM()));
+#else
+ vrc = VINF_SUCCESS;
+#endif
+ if (RT_SUCCESS(vrc))
+ vrc = VMR3PowerOn(ptrVM.rawUVM()); /* (PowerUpPaused) */
+ }
+ else
+ {
+ VMRESUMEREASON enmReason = VMRESUMEREASON_USER;
+ if (aReason == Reason_HostResume)
+ enmReason = VMRESUMEREASON_HOST_RESUME;
+ vrc = VMR3Resume(ptrVM.rawUVM(), enmReason);
+ }
+
+ HRESULT rc = RT_SUCCESS(vrc) ? S_OK :
+ setError(VBOX_E_VM_ERROR,
+ tr("Could not resume the machine execution (%Rrc)"),
+ vrc);
+
+ LogFlowThisFunc(("rc=%Rhrc\n", rc));
+ LogFlowThisFuncLeave();
+ return rc;
+}
+
+/**
+ * Worker for Console::SaveState and internal entry point for saving state of
+ * a VM for a specific reason.
+ */
+HRESULT Console::saveState(Reason_T aReason, IProgress **aProgress)
+{
+ LogFlowThisFuncEnter();
+
+ CheckComArgOutPointerValid(aProgress);
+
+ AutoCaller autoCaller(this);
+ if (FAILED(autoCaller.rc())) return autoCaller.rc();
+
+ AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ LogFlowThisFunc(("mMachineState=%d\n", mMachineState));
+ if ( mMachineState != MachineState_Running
+ && mMachineState != MachineState_Paused)
+ {
+ return setError(VBOX_E_INVALID_VM_STATE,
+ tr("Cannot save the execution state as the machine is not running or paused (machine state: %s)"),
+ Global::stringifyMachineState(mMachineState));
+ }
+
+ if (aReason != Reason_Unspecified)
+ LogRel(("Saving state of VM, reason \"%s\"\n", Global::stringifyReason(aReason)));
+
+ /* memorize the current machine state */
+ MachineState_T lastMachineState = mMachineState;
+
+ if (mMachineState == MachineState_Running)
+ {
+ /* get the VM handle. */
+ SafeVMPtr ptrVM(this);
+ if (!ptrVM.isOk())
+ return ptrVM.rc();
+
+ /* release the lock before a VMR3* call (EMT will call us back)! */
+ alock.release();
+ VMSUSPENDREASON enmReason = VMSUSPENDREASON_USER;
+ if (aReason == Reason_HostSuspend)
+ enmReason = VMSUSPENDREASON_HOST_SUSPEND;
+ else if (aReason == Reason_HostBatteryLow)
+ enmReason = VMSUSPENDREASON_HOST_BATTERY_LOW;
+ int vrc = VMR3Suspend(ptrVM.rawUVM(), enmReason);
+ alock.acquire();
+
+ HRESULT hrc = S_OK;
+ if (RT_FAILURE(vrc))
+ hrc = setError(VBOX_E_VM_ERROR, tr("Could not suspend the machine execution (%Rrc)"), vrc);
+ if (FAILED(hrc))
+ return hrc;
+ }
+
+ HRESULT rc = S_OK;
+ bool fBeganSavingState = false;
+ bool fTaskCreationFailed = false;
+
+ do
+ {
+ ComPtr<IProgress> pProgress;
+ Bstr stateFilePath;
+
+ /*
+ * request a saved state file path from the server
+ * (this will set the machine state to Saving on the server to block
+ * others from accessing this machine)
+ */
+ rc = mControl->BeginSavingState(pProgress.asOutParam(),
+ stateFilePath.asOutParam());
+ if (FAILED(rc))
+ break;
+
+ fBeganSavingState = true;
+
+ /* sync the state with the server */
+ setMachineStateLocally(MachineState_Saving);
+
+ /* ensure the directory for the saved state file exists */
+ {
+ Utf8Str dir = stateFilePath;
+ dir.stripFilename();
+ if (!RTDirExists(dir.c_str()))
+ {
+ int vrc = RTDirCreateFullPath(dir.c_str(), 0700);
+ if (RT_FAILURE(vrc))
+ {
+ rc = setError(VBOX_E_FILE_ERROR,
+ tr("Could not create a directory '%s' to save the state to (%Rrc)"),
+ dir.c_str(), vrc);
+ break;
+ }
+ }
+ }
+
+ /* Create a task object early to ensure mpUVM protection is successful. */
+ std::auto_ptr<VMSaveTask> task(new VMSaveTask(this, pProgress,
+ stateFilePath,
+ lastMachineState,
+ aReason));
+ rc = task->rc();
+ /*
+ * If we fail here it means a PowerDown() call happened on another
+ * thread while we were doing Pause() (which releases the Console lock).
+ * We assign PowerDown() a higher precedence than SaveState(),
+ * therefore just return the error to the caller.
+ */
+ if (FAILED(rc))
+ {
+ fTaskCreationFailed = true;
+ break;
+ }
+
+ /* create a thread to wait until the VM state is saved */
+ int vrc = RTThreadCreate(NULL, Console::saveStateThread, (void *)task.get(),
+ 0, RTTHREADTYPE_MAIN_WORKER, 0, "VMSave");
+ if (RT_FAILURE(vrc))
+ {
+ rc = setError(E_FAIL, "Could not create VMSave thread (%Rrc)", vrc);
+ break;
+ }
+
+ /* task is now owned by saveStateThread(), so release it */
+ task.release();
+
+ /* return the progress to the caller */
+ pProgress.queryInterfaceTo(aProgress);
+ } while (0);
+
+ if (FAILED(rc) && !fTaskCreationFailed)
+ {
+ /* preserve existing error info */
+ ErrorInfoKeeper eik;
+
+ if (fBeganSavingState)
+ {
+ /*
+ * cancel the requested save state procedure.
+ * This will reset the machine state to the state it had right
+ * before calling mControl->BeginSavingState().
+ */
+ mControl->EndSavingState(eik.getResultCode(), eik.getText().raw());
+ }
+
+ if (lastMachineState == MachineState_Running)
+ {
+ /* restore the paused state if appropriate */
+ setMachineStateLocally(MachineState_Paused);
+ /* restore the running state if appropriate */
+ SafeVMPtr ptrVM(this);
+ if (ptrVM.isOk())
+ {
+ alock.release();
+ VMR3Resume(ptrVM.rawUVM(), VMRESUMEREASON_STATE_RESTORED);
+ alock.acquire();
+ }
+ }
+ else
+ setMachineStateLocally(lastMachineState);
+ }
+
+ LogFlowThisFunc(("rc=%Rhrc\n", rc));
+ LogFlowThisFuncLeave();
+ return rc;
+}
+
+/**
* Gets called by Session::UpdateMachineState()
* (IInternalSessionControl::updateMachineState()).
*
@@ -5933,7 +6037,8 @@ void Console::onMousePointerShapeChange(bool fVisible, bool fAlpha,
* @note Locks this object for writing.
*/
#endif
-void Console::onMouseCapabilityChange(BOOL supportsAbsolute, BOOL supportsRelative, BOOL needsHostCursor)
+void Console::onMouseCapabilityChange(BOOL supportsAbsolute, BOOL supportsRelative,
+ BOOL supportsMT, BOOL needsHostCursor)
{
LogFlowThisFunc(("supportsAbsolute=%d supportsRelative=%d needsHostCursor=%d\n",
supportsAbsolute, supportsRelative, needsHostCursor));
@@ -5954,14 +6059,13 @@ void Console::onMouseCapabilityChange(BOOL supportsAbsolute, BOOL supportsRelati
}
#endif
- fireMouseCapabilityChangedEvent(mEventSource, supportsAbsolute, supportsRelative, needsHostCursor);
+ fireMouseCapabilityChangedEvent(mEventSource, supportsAbsolute, supportsRelative, supportsMT, needsHostCursor);
}
void Console::onStateChange(MachineState_T machineState)
{
AutoCaller autoCaller(this);
AssertComRCReturnVoid(autoCaller.rc());
-
fireStateChangedEvent(mEventSource, machineState);
}
@@ -6098,25 +6202,27 @@ HRESULT Console::onShowWindow(BOOL aCheck, BOOL *aCanShow, LONG64 *aWinId)
////////////////////////////////////////////////////////////////////////////////
/**
- * Increases the usage counter of the mpVM pointer. Guarantees that
- * VMR3Destroy() will not be called on it at least until releaseVMCaller()
- * is called.
+ * Increases the usage counter of the mpUVM pointer.
+ *
+ * Guarantees that VMR3Destroy() will not be called on it at least until
+ * releaseVMCaller() is called.
*
- * If this method returns a failure, the caller is not allowed to use mpVM
- * and may return the failed result code to the upper level. This method sets
- * the extended error info on failure if \a aQuiet is false.
+ * If this method returns a failure, the caller is not allowed to use mpUVM and
+ * may return the failed result code to the upper level. This method sets the
+ * extended error info on failure if \a aQuiet is false.
*
* Setting \a aQuiet to true is useful for methods that don't want to return
* the failed result code to the caller when this method fails (e.g. need to
- * silently check for the mpVM availability).
+ * silently check for the mpUVM availability).
*
- * When mpVM is NULL but \a aAllowNullVM is true, a corresponding error will be
+ * When mpUVM is NULL but \a aAllowNullVM is true, a corresponding error will be
* returned instead of asserting. Having it false is intended as a sanity check
- * for methods that have checked mMachineState and expect mpVM *NOT* to be NULL.
+ * for methods that have checked mMachineState and expect mpUVM *NOT* to be
+ * NULL.
*
* @param aQuiet true to suppress setting error info
- * @param aAllowNullVM true to accept mpVM being NULL and return a failure
- * (otherwise this method will assert if mpVM is NULL)
+ * @param aAllowNullVM true to accept mpUVM being NULL and return a failure
+ * (otherwise this method will assert if mpUVM is NULL)
*
* @note Locks this object for writing.
*/
@@ -6153,8 +6259,10 @@ HRESULT Console::addVMCaller(bool aQuiet /* = false */,
}
/**
- * Decreases the usage counter of the mpVM pointer. Must always complete
- * the addVMCaller() call after the mpVM pointer is no more necessary.
+ * Decreases the usage counter of the mpUVM pointer.
+ *
+ * Must always complete the addVMCaller() call after the mpUVM pointer is no
+ * more necessary.
*
* @note Locks this object for writing.
*/
@@ -6178,9 +6286,8 @@ void Console::releaseVMCaller()
}
-HRESULT Console::safeVMPtrRetainer(PVM *a_ppVM, PUVM *a_ppUVM, bool a_Quiet)
+HRESULT Console::safeVMPtrRetainer(PUVM *a_ppUVM, bool a_Quiet)
{
- *a_ppVM = NULL;
*a_ppUVM = NULL;
AutoCaller autoCaller(this);
@@ -6192,13 +6299,13 @@ HRESULT Console::safeVMPtrRetainer(PVM *a_ppVM, PUVM *a_ppUVM, bool a_Quiet)
*/
if (mVMDestroying) /* powerDown() is waiting for all callers to finish */
return a_Quiet
- ? E_ACCESSDENIED
- : setError(E_ACCESSDENIED, tr("The virtual machine is being powered down"));
+ ? E_ACCESSDENIED
+ : setError(E_ACCESSDENIED, tr("The virtual machine is being powered down"));
PUVM pUVM = mpUVM;
if (!pUVM)
return a_Quiet
- ? E_ACCESSDENIED
- : setError(E_ACCESSDENIED, tr("The virtual machine is was powered off"));
+ ? E_ACCESSDENIED
+ : setError(E_ACCESSDENIED, tr("The virtual machine is powered off"));
/*
* Retain a reference to the user mode VM handle and get the global handle.
@@ -6207,28 +6314,17 @@ HRESULT Console::safeVMPtrRetainer(PVM *a_ppVM, PUVM *a_ppUVM, bool a_Quiet)
if (cRefs == UINT32_MAX)
return a_Quiet
? E_ACCESSDENIED
- : setError(E_ACCESSDENIED, tr("The virtual machine is was powered off"));
-
- PVM pVM = VMR3GetVM(pUVM);
- if (!pVM)
- {
- VMR3ReleaseUVM(pUVM);
- return a_Quiet
- ? E_ACCESSDENIED
- : setError(E_ACCESSDENIED, tr("The virtual machine is was powered off"));
- }
+ : setError(E_ACCESSDENIED, tr("The virtual machine is powered off"));
/* done */
- *a_ppVM = pVM;
*a_ppUVM = pUVM;
return S_OK;
}
-void Console::safeVMPtrReleaser(PVM *a_ppVM, PUVM *a_ppUVM)
+void Console::safeVMPtrReleaser(PUVM *a_ppUVM)
{
- if (*a_ppVM && *a_ppUVM)
+ if (*a_ppUVM)
VMR3ReleaseUVM(*a_ppUVM);
- *a_ppVM = NULL;
*a_ppUVM = NULL;
}
@@ -6298,7 +6394,7 @@ HRESULT Console::consoleInitReleaseLog(const ComPtr<IMachine> aMachine)
char szError[RTPATH_MAX + 128];
int vrc = com::VBoxLogRelCreate("VM", logFile.c_str(),
RTLOGFLAGS_PREFIX_TIME_PROG | RTLOGFLAGS_RESTRICT_GROUPS,
- "all all.restrict default.unrestricted",
+ "all all.restrict -default.restrict",
"VBOX_RELEASE_LOG", RTLOGDEST_FILE,
32768 /* cMaxEntriesPerGroup */,
0 /* cHistory */, 0 /* uHistoryFileTime */,
@@ -6328,8 +6424,8 @@ HRESULT Console::consoleInitReleaseLog(const ComPtr<IMachine> aMachine)
*/
HRESULT Console::powerUp(IProgress **aProgress, bool aPaused)
{
+
LogFlowThisFuncEnter();
- LogFlowThisFunc(("mMachineState=%d\n", mMachineState));
CheckComArgOutPointerValid(aProgress);
@@ -6338,22 +6434,34 @@ HRESULT Console::powerUp(IProgress **aProgress, bool aPaused)
AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+ LogFlowThisFunc(("mMachineState=%d\n", mMachineState));
HRESULT rc = S_OK;
ComObjPtr<Progress> pPowerupProgress;
bool fBeganPoweringUp = false;
+ LONG cOperations = 1;
+ LONG ulTotalOperationsWeight = 1;
+
try
{
+
if (Global::IsOnlineOrTransient(mMachineState))
throw setError(VBOX_E_INVALID_VM_STATE,
tr("The virtual machine is already running or busy (machine state: %s)"),
Global::stringifyMachineState(mMachineState));
+ /* Set up release logging as early as possible after the check if
+ * there is already a running VM which we shouldn't disturb. */
+ rc = consoleInitReleaseLog(mMachine);
+ if (FAILED(rc))
+ throw rc;
+
/* test and clear the TeleporterEnabled property */
BOOL fTeleporterEnabled;
rc = mMachine->COMGETTER(TeleporterEnabled)(&fTeleporterEnabled);
if (FAILED(rc))
throw rc;
+
#if 0 /** @todo we should save it afterwards, but that isn't necessarily a good idea. Find a better place for this (VBoxSVC). */
if (fTeleporterEnabled)
{
@@ -6384,101 +6492,28 @@ HRESULT Console::powerUp(IProgress **aProgress, bool aPaused)
progressDesc = tr("Fault Tolerance syncing of remote virtual machine");
else
progressDesc = tr("Starting virtual machine");
- if ( mMachineState == MachineState_Saved
- || (!fTeleporterEnabled && !fFaultToleranceSyncEnabled))
- rc = pPowerupProgress->init(static_cast<IConsole *>(this),
- progressDesc.raw(),
- FALSE /* aCancelable */);
- else
- if (fTeleporterEnabled)
- rc = pPowerupProgress->init(static_cast<IConsole *>(this),
- progressDesc.raw(),
- TRUE /* aCancelable */,
- 3 /* cOperations */,
- 10 /* ulTotalOperationsWeight */,
- Bstr(tr("Teleporting virtual machine")).raw(),
- 1 /* ulFirstOperationWeight */,
- NULL);
- else
- if (fFaultToleranceSyncEnabled)
- rc = pPowerupProgress->init(static_cast<IConsole *>(this),
- progressDesc.raw(),
- TRUE /* aCancelable */,
- 3 /* cOperations */,
- 10 /* ulTotalOperationsWeight */,
- Bstr(tr("Fault Tolerance syncing of remote virtual machine")).raw(),
- 1 /* ulFirstOperationWeight */,
- NULL);
- if (FAILED(rc))
- throw rc;
-
- /* Tell VBoxSVC and Machine about the progress object so they can
- combine/proxy it to any openRemoteSession caller. */
- LogFlowThisFunc(("Calling BeginPowerUp...\n"));
- rc = mControl->BeginPowerUp(pPowerupProgress);
- if (FAILED(rc))
- {
- LogFlowThisFunc(("BeginPowerUp failed\n"));
- throw rc;
- }
- fBeganPoweringUp = true;
+ Bstr savedStateFile;
- /** @todo this code prevents starting a VM with unavailable bridged
- * networking interface. The only benefit is a slightly better error
- * message, which should be moved to the driver code. This is the
- * only reason why I left the code in for now. The driver allows
- * unavailable bridged networking interfaces in certain circumstances,
- * and this is sabotaged by this check. The VM will initially have no
- * network connectivity, but the user can fix this at runtime. */
-#if 0
- /* the network cards will undergo a quick consistency check */
- for (ULONG slot = 0;
- slot < maxNetworkAdapters;
- ++slot)
+ /*
+ * Saved VMs will have to prove that their saved states seem kosher.
+ */
+ if (mMachineState == MachineState_Saved)
{
- ComPtr<INetworkAdapter> pNetworkAdapter;
- mMachine->GetNetworkAdapter(slot, pNetworkAdapter.asOutParam());
- BOOL enabled = FALSE;
- pNetworkAdapter->COMGETTER(Enabled)(&enabled);
- if (!enabled)
- continue;
-
- NetworkAttachmentType_T netattach;
- pNetworkAdapter->COMGETTER(AttachmentType)(&netattach);
- switch (netattach)
- {
- case NetworkAttachmentType_Bridged:
- {
- /* a valid host interface must have been set */
- Bstr hostif;
- pNetworkAdapter->COMGETTER(HostInterface)(hostif.asOutParam());
- if (hostif.isEmpty())
- {
- throw setError(VBOX_E_HOST_ERROR,
- tr("VM cannot start because host interface networking requires a host interface name to be set"));
- }
- ComPtr<IVirtualBox> pVirtualBox;
- mMachine->COMGETTER(Parent)(pVirtualBox.asOutParam());
- ComPtr<IHost> pHost;
- pVirtualBox->COMGETTER(Host)(pHost.asOutParam());
- ComPtr<IHostNetworkInterface> pHostInterface;
- if (!SUCCEEDED(pHost->FindHostNetworkInterfaceByName(hostif.raw(),
- pHostInterface.asOutParam())))
- {
- throw setError(VBOX_E_HOST_ERROR,
- tr("VM cannot start because the host interface '%ls' does not exist"),
- hostif.raw());
- }
- break;
- }
- default:
- break;
- }
+ rc = mMachine->COMGETTER(StateFilePath)(savedStateFile.asOutParam());
+ if (FAILED(rc))
+ throw rc;
+ ComAssertRet(!savedStateFile.isEmpty(), E_FAIL);
+ int vrc = SSMR3ValidateFile(Utf8Str(savedStateFile).c_str(), false /* fChecksumIt */);
+ if (RT_FAILURE(vrc))
+ throw setError(VBOX_E_FILE_ERROR,
+ tr("VM cannot start because the saved state file '%ls' is invalid (%Rrc). Delete the saved state prior to starting the VM"),
+ savedStateFile.raw(), vrc);
}
-#endif // 0
- /* Read console data stored in the saved state file (if not yet done) */
+ /* Read console data, including console shared folders, stored in the
+ * saved state file (if not yet done).
+ */
rc = loadDataFromSavedState();
if (FAILED(rc))
throw rc;
@@ -6518,39 +6553,8 @@ HRESULT Console::powerUp(IProgress **aProgress, bool aPaused)
}
}
- Bstr savedStateFile;
-
- /*
- * Saved VMs will have to prove that their saved states seem kosher.
- */
- if (mMachineState == MachineState_Saved)
- {
- rc = mMachine->COMGETTER(StateFilePath)(savedStateFile.asOutParam());
- if (FAILED(rc))
- throw rc;
- ComAssertRet(!savedStateFile.isEmpty(), E_FAIL);
- int vrc = SSMR3ValidateFile(Utf8Str(savedStateFile).c_str(), false /* fChecksumIt */);
- if (RT_FAILURE(vrc))
- throw setError(VBOX_E_FILE_ERROR,
- tr("VM cannot start because the saved state file '%ls' is invalid (%Rrc). Delete the saved state prior to starting the VM"),
- savedStateFile.raw(), vrc);
- }
-
- LogFlowThisFunc(("Checking if canceled...\n"));
- BOOL fCanceled;
- rc = pPowerupProgress->COMGETTER(Canceled)(&fCanceled);
- if (FAILED(rc))
- throw rc;
- if (fCanceled)
- {
- LogFlowThisFunc(("Canceled in BeginPowerUp\n"));
- throw setError(E_FAIL, tr("Powerup was canceled"));
- }
- LogFlowThisFunc(("Not canceled yet.\n"));
-
- /* setup task object and thread to carry out the operation
- * asynchronously */
-
+ /* Setup task object and thread to carry out the operaton
+ * Asycnhronously */
std::auto_ptr<VMPowerUpTask> task(new VMPowerUpTask(this, pPowerupProgress));
ComAssertComRCRetRC(task->rc());
@@ -6628,9 +6632,9 @@ HRESULT Console::powerUp(IProgress **aProgress, bool aPaused)
else
LogFlowThisFunc(("Machine has a current snapshot which is online, skipping immutable images reset\n"));
- rc = consoleInitReleaseLog(mMachine);
- if (FAILED(rc))
- throw rc;
+ /* setup task object and thread to carry out the operation
+ * asynchronously */
+
#ifdef VBOX_WITH_EXTPACK
mptrExtPackManager->dumpAllToReleaseLog();
#endif
@@ -6649,15 +6653,11 @@ HRESULT Console::powerUp(IProgress **aProgress, bool aPaused)
uint32_t fCoreFlags = 0;
if ( coreDumpReplaceSys.isEmpty() == false
&& Utf8Str(coreDumpReplaceSys).toUInt32() == 1)
- {
fCoreFlags |= RTCOREDUMPER_FLAGS_REPLACE_SYSTEM_DUMP;
- }
if ( coreDumpLive.isEmpty() == false
&& Utf8Str(coreDumpLive).toUInt32() == 1)
- {
fCoreFlags |= RTCOREDUMPER_FLAGS_LIVE_CORE;
- }
Utf8Str strDumpDir(coreDumpDir);
const char *pszDumpDir = strDumpDir.c_str();
@@ -6685,29 +6685,143 @@ HRESULT Console::powerUp(IProgress **aProgress, bool aPaused)
}
#endif
- /* pass the progress object to the caller if requested */
- if (aProgress)
- {
- if (task->hardDiskProgresses.size() == 0)
+
+ // If there is immutable drive the process that.
+ VMPowerUpTask::ProgressList progresses(task->hardDiskProgresses);
+ if (aProgress && progresses.size() > 0){
+
+ for (VMPowerUpTask::ProgressList::const_iterator it = progresses.begin(); it != progresses.end(); ++it)
{
- /* there are no other operations to track, return the powerup
- * progress only */
- pPowerupProgress.queryInterfaceTo(aProgress);
+ ++cOperations;
+ ulTotalOperationsWeight += 1;
}
- else
+ rc = pPowerupProgress->init(static_cast<IConsole *>(this),
+ progressDesc.raw(),
+ TRUE, // Cancelable
+ cOperations,
+ ulTotalOperationsWeight,
+ Bstr(tr("Starting Hard Disk operations")).raw(),
+ 1,
+ NULL);
+ AssertComRCReturnRC(rc);
+ }
+ else if ( mMachineState == MachineState_Saved
+ || (!fTeleporterEnabled && !fFaultToleranceSyncEnabled))
+ {
+ rc = pPowerupProgress->init(static_cast<IConsole *>(this),
+ progressDesc.raw(),
+ FALSE /* aCancelable */);
+ }
+ else if (fTeleporterEnabled)
+ {
+ rc = pPowerupProgress->init(static_cast<IConsole *>(this),
+ progressDesc.raw(),
+ TRUE /* aCancelable */,
+ 3 /* cOperations */,
+ 10 /* ulTotalOperationsWeight */,
+ Bstr(tr("Teleporting virtual machine")).raw(),
+ 1 /* ulFirstOperationWeight */,
+ NULL);
+ }
+ else if (fFaultToleranceSyncEnabled)
+ {
+ rc = pPowerupProgress->init(static_cast<IConsole *>(this),
+ progressDesc.raw(),
+ TRUE /* aCancelable */,
+ 3 /* cOperations */,
+ 10 /* ulTotalOperationsWeight */,
+ Bstr(tr("Fault Tolerance syncing of remote virtual machine")).raw(),
+ 1 /* ulFirstOperationWeight */,
+ NULL);
+ }
+
+ if (FAILED(rc))
+ throw rc;
+
+ /* Tell VBoxSVC and Machine about the progress object so they can
+ combine/proxy it to any openRemoteSession caller. */
+ LogFlowThisFunc(("Calling BeginPowerUp...\n"));
+ rc = mControl->BeginPowerUp(pPowerupProgress);
+ if (FAILED(rc))
+ {
+ LogFlowThisFunc(("BeginPowerUp failed\n"));
+ throw rc;
+ }
+ fBeganPoweringUp = true;
+
+ LogFlowThisFunc(("Checking if canceled...\n"));
+ BOOL fCanceled;
+ rc = pPowerupProgress->COMGETTER(Canceled)(&fCanceled);
+ if (FAILED(rc))
+ throw rc;
+
+ if (fCanceled)
+ {
+ LogFlowThisFunc(("Canceled in BeginPowerUp\n"));
+ throw setError(E_FAIL, tr("Powerup was canceled"));
+ }
+ LogFlowThisFunc(("Not canceled yet.\n"));
+
+ /** @todo this code prevents starting a VM with unavailable bridged
+ * networking interface. The only benefit is a slightly better error
+ * message, which should be moved to the driver code. This is the
+ * only reason why I left the code in for now. The driver allows
+ * unavailable bridged networking interfaces in certain circumstances,
+ * and this is sabotaged by this check. The VM will initially have no
+ * network connectivity, but the user can fix this at runtime. */
+#if 0
+ /* the network cards will undergo a quick consistency check */
+ for (ULONG slot = 0;
+ slot < maxNetworkAdapters;
+ ++slot)
+ {
+ ComPtr<INetworkAdapter> pNetworkAdapter;
+ mMachine->GetNetworkAdapter(slot, pNetworkAdapter.asOutParam());
+ BOOL enabled = FALSE;
+ pNetworkAdapter->COMGETTER(Enabled)(&enabled);
+ if (!enabled)
+ continue;
+
+ NetworkAttachmentType_T netattach;
+ pNetworkAdapter->COMGETTER(AttachmentType)(&netattach);
+ switch (netattach)
{
- /* create a combined progress object */
- ComObjPtr<CombinedProgress> pProgress;
- pProgress.createObject();
- VMPowerUpTask::ProgressList progresses(task->hardDiskProgresses);
- progresses.push_back(ComPtr<IProgress> (pPowerupProgress));
- rc = pProgress->init(static_cast<IConsole *>(this),
- progressDesc.raw(), progresses.begin(),
- progresses.end());
- AssertComRCReturnRC(rc);
- pProgress.queryInterfaceTo(aProgress);
+ case NetworkAttachmentType_Bridged:
+ {
+ /* a valid host interface must have been set */
+ Bstr hostif;
+ pNetworkAdapter->COMGETTER(HostInterface)(hostif.asOutParam());
+ if (hostif.isEmpty())
+ {
+ throw setError(VBOX_E_HOST_ERROR,
+ tr("VM cannot start because host interface networking requires a host interface name to be set"));
+ }
+ ComPtr<IVirtualBox> pVirtualBox;
+ mMachine->COMGETTER(Parent)(pVirtualBox.asOutParam());
+ ComPtr<IHost> pHost;
+ pVirtualBox->COMGETTER(Host)(pHost.asOutParam());
+ ComPtr<IHostNetworkInterface> pHostInterface;
+ if (!SUCCEEDED(pHost->FindHostNetworkInterfaceByName(hostif.raw(),
+ pHostInterface.asOutParam())))
+ {
+ throw setError(VBOX_E_HOST_ERROR,
+ tr("VM cannot start because the host interface '%ls' does not exist"),
+ hostif.raw());
+ }
+ break;
+ }
+ default:
+ break;
}
}
+#endif // 0
+
+ /* setup task object and thread to carry out the operation
+ * asynchronously */
+ if (aProgress){
+ rc = pPowerupProgress.queryInterfaceTo(aProgress);
+ AssertComRCReturnRC(rc);
+ }
int vrc = RTThreadCreate(NULL, Console::powerUpThread,
(void *)task.get(), 0,
@@ -6724,7 +6838,7 @@ HRESULT Console::powerUp(IProgress **aProgress, bool aPaused)
if (mMachineState == MachineState_Saved)
setMachineState(MachineState_Restoring);
else if (fTeleporterEnabled)
- setMachineState(MachineState_TeleportingIn);
+ setMachineState(MachineState_TeleportingIn);
else if (enmFaultToleranceState == FaultToleranceState_Standby)
setMachineState(MachineState_FaultTolerantSyncing);
else
@@ -6771,7 +6885,7 @@ HRESULT Console::powerUp(IProgress **aProgress, bool aPaused)
*
* Calling it in situations other than the above will cause unexpected behavior.
*
- * Note that this method should be the only one that destroys mpVM and sets it
+ * Note that this method should be the only one that destroys mpUVM and sets it
* to NULL.
*
* @param aProgress Progress object to run (may be NULL).
@@ -6878,8 +6992,8 @@ HRESULT Console::powerDown(IProgress *aProgress /*= NULL*/)
/* ----------------------------------------------------------------------
- * Now, wait for all mpVM callers to finish their work if there are still
- * some on other threads. NO methods that need mpVM (or initiate other calls
+ * Now, wait for all mpUVM callers to finish their work if there are still
+ * some on other threads. NO methods that need mpUVM (or initiate other calls
* that need it) may be called after this point
* ---------------------------------------------------------------------- */
@@ -6892,8 +7006,7 @@ HRESULT Console::powerDown(IProgress *aProgress /*= NULL*/)
if (mVMZeroCallersSem == NIL_RTSEMEVENT)
RTSemEventCreate(&mVMZeroCallersSem);
- LogFlowThisFunc(("Waiting for mpVM callers (%d) to drop to zero...\n",
- mVMCallers));
+ LogFlowThisFunc(("Waiting for mpUVM callers (%d) to drop to zero...\n", mVMCallers));
alock.release();
@@ -6920,7 +7033,7 @@ HRESULT Console::powerDown(IProgress *aProgress /*= NULL*/)
{
LogFlowThisFunc(("Powering off the VM...\n"));
alock.release();
- vrc = VMR3PowerOff(VMR3GetVM(pUVM));
+ vrc = VMR3PowerOff(pUVM);
#ifdef VBOX_WITH_EXTPACK
mptrExtPackManager->callAllVmPowerOffHooks(this, VMR3GetVM(pUVM));
#endif
@@ -6957,26 +7070,20 @@ HRESULT Console::powerDown(IProgress *aProgress /*= NULL*/)
* on failure (this will most likely fail too, but what to do?..) */
if (RT_SUCCESS(vrc) || autoCaller.state() == InUninit)
{
- /* If the machine has an USB controller, release all USB devices
+ /* If the machine has a USB controller, release all USB devices
* (symmetric to the code in captureUSBDevices()) */
- bool fHasUSBController = false;
+ if (mfVMHasUsbController)
{
- PPDMIBASE pBase;
- vrc = PDMR3QueryLun(VMR3GetVM(pUVM), "usb-ohci", 0, 0, &pBase);
- if (RT_SUCCESS(vrc))
- {
- fHasUSBController = true;
- alock.release();
- detachAllUSBDevices(false /* aDone */);
- alock.acquire();
- }
+ alock.release();
+ detachAllUSBDevices(false /* aDone */);
+ alock.acquire();
}
- /* Now we've got to destroy the VM as well. (mpVM is not valid beyond
+ /* Now we've got to destroy the VM as well. (mpUVM is not valid beyond
* this point). We release the lock before calling VMR3Destroy() because
* it will result into calling destructors of drivers associated with
* Console children which may in turn try to lock Console (e.g. by
- * instantiating SafeVMPtr to access mpVM). It's safe here because
+ * instantiating SafeVMPtr to access mpUVM). It's safe here because
* mVMDestroying is set which should prevent any activity. */
/* Set mpUVM to NULL early just in case if some old code is not using
@@ -6988,7 +7095,7 @@ HRESULT Console::powerDown(IProgress *aProgress /*= NULL*/)
alock.release();
- vrc = VMR3Destroy(VMR3GetVM(pUVM));
+ vrc = VMR3Destroy(pUVM);
/* take the lock again */
alock.acquire();
@@ -7000,7 +7107,7 @@ HRESULT Console::powerDown(IProgress *aProgress /*= NULL*/)
if (RT_SUCCESS(vrc))
{
LogFlowThisFunc(("Machine has been destroyed (mMachineState=%d)\n",
- mMachineState));
+ mMachineState));
/* Note: the Console-level machine state change happens on the
* VMSTATE_TERMINATE state change in vmstateChangeCallback(). If
* powerDown() is called from EMT (i.e. from vmstateChangeCallback()
@@ -7020,7 +7127,7 @@ HRESULT Console::powerDown(IProgress *aProgress /*= NULL*/)
}
/* Complete the detaching of the USB devices. */
- if (fHasUSBController)
+ if (mfVMHasUsbController)
{
alock.release();
detachAllUSBDevices(true /* aDone */);
@@ -7046,7 +7153,7 @@ HRESULT Console::powerDown(IProgress *aProgress /*= NULL*/)
* something like Stopping, so most Console methods will return an error
* to the caller.
*/
- if (mpUVM != NULL)
+ if (pUVM != NULL)
VMR3ReleaseUVM(pUVM);
else
mVMDestroying = false;
@@ -7281,8 +7388,9 @@ HRESULT Console::fetchSharedFolders(BOOL aGlobal)
}
catch (HRESULT rc2)
{
+ rc = rc2;
if (online)
- setVMRuntimeErrorCallbackF(ptrVM, this, 0, "BrokenSharedFolder",
+ setVMRuntimeErrorCallbackF(0, "BrokenSharedFolder",
N_("Broken shared folder!"));
}
@@ -7326,7 +7434,7 @@ bool Console::findOtherSharedFolder(const Utf8Str &strName,
* @param aName Shared folder name.
* @param aHostPath Shared folder path.
*
- * @note Must be called from under AutoVMCaller and when mpVM != NULL!
+ * @note Must be called from under AutoVMCaller and when mpUVM != NULL!
* @note Doesn't lock anything.
*/
HRESULT Console::createSharedFolder(const Utf8Str &strName, const SharedFolderData &aData)
@@ -7356,14 +7464,15 @@ HRESULT Console::createSharedFolder(const Utf8Str &strName, const SharedFolderDa
aData.m_strHostPath.c_str(),
hostPathFull,
sizeof(hostPathFull));
+
+ bool fMissing = false;
if (RT_FAILURE(vrc))
return setError(E_INVALIDARG,
tr("Invalid shared folder path: '%s' (%Rrc)"),
aData.m_strHostPath.c_str(), vrc);
if (!RTPathExists(hostPathFull))
- return setError(E_INVALIDARG,
- tr("Shared folder path '%s' does not exist on the host"),
- aData.m_strHostPath.c_str());
+ fMissing = true;
+
/* Check whether the path is full (absolute) */
if (RTPathCompare(aData.m_strHostPath.c_str(), hostPathFull) != 0)
return setError(E_INVALIDARG,
@@ -7409,7 +7518,9 @@ HRESULT Console::createSharedFolder(const Utf8Str &strName, const SharedFolderDa
parms[2].type = VBOX_HGCM_SVC_PARM_32BIT;
parms[2].u.uint32 = (aData.m_fWritable ? SHFL_ADD_MAPPING_F_WRITABLE : 0)
| (aData.m_fAutoMount ? SHFL_ADD_MAPPING_F_AUTOMOUNT : 0)
- | (fSymlinksCreate ? SHFL_ADD_MAPPING_F_CREATE_SYMLINKS : 0);
+ | (fSymlinksCreate ? SHFL_ADD_MAPPING_F_CREATE_SYMLINKS : 0)
+ | (fMissing ? SHFL_ADD_MAPPING_F_MISSING : 0)
+ ;
vrc = m_pVMMDev->hgcmHostCall("VBoxSharedFolders",
SHFL_FN_ADD_MAPPING,
@@ -7422,6 +7533,11 @@ HRESULT Console::createSharedFolder(const Utf8Str &strName, const SharedFolderDa
tr("Could not create a shared folder '%s' mapped to '%s' (%Rrc)"),
strName.c_str(), aData.m_strHostPath.c_str(), vrc);
+ if (fMissing)
+ return setError(E_INVALIDARG,
+ tr("Shared folder path '%s' does not exist on the host"),
+ aData.m_strHostPath.c_str());
+
return S_OK;
}
@@ -7430,7 +7546,7 @@ HRESULT Console::createSharedFolder(const Utf8Str &strName, const SharedFolderDa
*
* @param aName Shared folder name.
*
- * @note Must be called from under AutoVMCaller and when mpVM != NULL!
+ * @note Must be called from under AutoVMCaller and when mpUVM != NULL!
* @note Doesn't lock anything.
*/
HRESULT Console::removeSharedFolder(const Utf8Str &strName)
@@ -7474,31 +7590,18 @@ HRESULT Console::removeSharedFolder(const Utf8Str &strName)
return S_OK;
}
-/**
- * VM state callback function. Called by the VMM
- * using its state machine states.
- *
- * Primarily used to handle VM initiated power off, suspend and state saving,
- * but also for doing termination completed work (VMSTATE_TERMINATE).
+/** @callback_method_impl{FNVMATSTATE}
*
- * In general this function is called in the context of the EMT.
- *
- * @param aVM The VM handle.
- * @param aState The new state.
- * @param aOldState The old state.
- * @param aUser The user argument (pointer to the Console object).
- *
- * @note Locks the Console object for writing.
+ * @note Locks the Console object for writing.
+ * @remarks The @a pUVM parameter can be NULL in one case where powerUpThread()
+ * calls after the VM was destroyed.
*/
-DECLCALLBACK(void) Console::vmstateChangeCallback(PVM aVM,
- VMSTATE aState,
- VMSTATE aOldState,
- void *aUser)
+DECLCALLBACK(void) Console::vmstateChangeCallback(PUVM pUVM, VMSTATE enmState, VMSTATE enmOldState, void *pvUser)
{
- LogFlowFunc(("Changing state from %s to %s (aVM=%p)\n",
- VMR3GetStateName(aOldState), VMR3GetStateName(aState), aVM));
+ LogFlowFunc(("Changing state from %s to %s (pUVM=%p)\n",
+ VMR3GetStateName(enmOldState), VMR3GetStateName(enmState), pUVM));
- Console *that = static_cast<Console *>(aUser);
+ Console *that = static_cast<Console *>(pvUser);
AssertReturnVoid(that);
AutoCaller autoCaller(that);
@@ -7510,17 +7613,34 @@ DECLCALLBACK(void) Console::vmstateChangeCallback(PVM aVM,
AssertReturnVoid( autoCaller.isOk()
|| autoCaller.state() == InUninit);
- switch (aState)
+ switch (enmState)
{
/*
* The VM has terminated
*/
case VMSTATE_OFF:
{
+#ifdef VBOX_WITH_GUEST_PROPS
+ if (that->isResetTurnedIntoPowerOff())
+ {
+ Bstr strPowerOffReason;
+
+ if (that->mfPowerOffCausedByReset)
+ strPowerOffReason = Bstr("Reset");
+ else
+ strPowerOffReason = Bstr("PowerOff");
+
+ that->mMachine->DeleteGuestProperty(Bstr("/VirtualBox/HostInfo/VMPowerOffReason").raw());
+ that->mMachine->SetGuestProperty(Bstr("/VirtualBox/HostInfo/VMPowerOffReason").raw(),
+ strPowerOffReason.raw(), Bstr("RDONLYGUEST").raw());
+ that->mMachine->SaveSettings();
+ }
+#endif
+
AutoWriteLock alock(that COMMA_LOCKVAL_SRC_POS);
if (that->mVMStateChangeCallbackDisabled)
- break;
+ return;
/* Do we still think that it is running? It may happen if this is a
* VM-(guest-)initiated shutdown/poweroff.
@@ -7536,7 +7656,11 @@ DECLCALLBACK(void) Console::vmstateChangeCallback(PVM aVM,
{
LogFlowFunc(("VM has powered itself off but Console still thinks it is running. Notifying.\n"));
- /* prevent powerDown() from calling VMR3PowerOff() again */
+ /*
+ * Prevent powerDown() from calling VMR3PowerOff() again if this was called from
+ * the power off state change.
+ * When called from the Reset state make sure to call VMR3PowerOff() first.
+ */
Assert(that->mVMPoweredOff == false);
that->mVMPoweredOff = true;
@@ -7554,11 +7678,10 @@ DECLCALLBACK(void) Console::vmstateChangeCallback(PVM aVM,
/* Setup task object and thread to carry out the operation
* asynchronously (if we call powerDown() right here but there
- * is one or more mpVM callers (added with addVMCaller()) we'll
+ * is one or more mpUVM callers (added with addVMCaller()) we'll
* deadlock).
*/
- std::auto_ptr<VMPowerDownTask> task(new VMPowerDownTask(that,
- pProgress));
+ std::auto_ptr<VMPowerDownTask> task(new VMPowerDownTask(that, pProgress));
/* If creating a task failed, this can currently mean one of
* two: either Console::uninit() has been called just a ms
@@ -7569,14 +7692,14 @@ DECLCALLBACK(void) Console::vmstateChangeCallback(PVM aVM,
if (!task->isOk())
{
LogFlowFunc(("Console is already being uninitialized.\n"));
- break;
+ return;
}
int vrc = RTThreadCreate(NULL, Console::powerDownThread,
- (void *) task.get(), 0,
+ (void *)task.get(), 0,
RTTHREADTYPE_MAIN_WORKER, 0,
"VMPwrDwn");
- AssertMsgRCBreak(vrc, ("Could not create VMPowerDown thread (%Rrc)\n", vrc));
+ AssertMsgRCReturnVoid(vrc, ("Could not create VMPowerDown thread (%Rrc)\n", vrc));
/* task is now owned by powerDownThread(), so release it */
task.release();
@@ -7598,12 +7721,12 @@ DECLCALLBACK(void) Console::vmstateChangeCallback(PVM aVM,
if (that->mVMStateChangeCallbackDisabled)
break;
- /* Terminate host interface networking. If aVM is NULL, we've been
+ /* Terminate host interface networking. If pUVM is NULL, we've been
* manually called from powerUpThread() either before calling
* VMR3Create() or after VMR3Create() failed, so no need to touch
* networking.
*/
- if (aVM)
+ if (pUVM)
that->powerDownHostInterfaces();
/* From now on the machine is officially powered down or remains in
@@ -7718,7 +7841,7 @@ DECLCALLBACK(void) Console::vmstateChangeCallback(PVM aVM,
break;
default:
- AssertMsgFailed(("%s/%s -> %s\n", Global::stringifyMachineState(that->mMachineState), VMR3GetStateName(aOldState), VMR3GetStateName(aState) ));
+ AssertMsgFailed(("%s/%s -> %s\n", Global::stringifyMachineState(that->mMachineState), VMR3GetStateName(enmOldState), VMR3GetStateName(enmState) ));
that->setMachineState(MachineState_Paused);
break;
}
@@ -7727,9 +7850,9 @@ DECLCALLBACK(void) Console::vmstateChangeCallback(PVM aVM,
case VMSTATE_RUNNING:
{
- if ( aOldState == VMSTATE_POWERING_ON
- || aOldState == VMSTATE_RESUMING
- || aOldState == VMSTATE_RUNNING_FT)
+ if ( enmOldState == VMSTATE_POWERING_ON
+ || enmOldState == VMSTATE_RESUMING
+ || enmOldState == VMSTATE_RUNNING_FT)
{
AutoWriteLock alock(that COMMA_LOCKVAL_SRC_POS);
@@ -7738,15 +7861,15 @@ DECLCALLBACK(void) Console::vmstateChangeCallback(PVM aVM,
Assert( ( ( that->mMachineState == MachineState_Starting
|| that->mMachineState == MachineState_Paused)
- && aOldState == VMSTATE_POWERING_ON)
+ && enmOldState == VMSTATE_POWERING_ON)
|| ( ( that->mMachineState == MachineState_Restoring
|| that->mMachineState == MachineState_TeleportingIn
|| that->mMachineState == MachineState_Paused
|| that->mMachineState == MachineState_Saving
)
- && aOldState == VMSTATE_RESUMING)
+ && enmOldState == VMSTATE_RESUMING)
|| ( that->mMachineState == MachineState_FaultTolerantSyncing
- && aOldState == VMSTATE_RUNNING_FT));
+ && enmOldState == VMSTATE_RUNNING_FT));
that->setMachineState(MachineState_Running);
}
@@ -7757,12 +7880,12 @@ DECLCALLBACK(void) Console::vmstateChangeCallback(PVM aVM,
case VMSTATE_RUNNING_LS:
AssertMsg( that->mMachineState == MachineState_LiveSnapshotting
|| that->mMachineState == MachineState_Teleporting,
- ("%s/%s -> %s\n", Global::stringifyMachineState(that->mMachineState), VMR3GetStateName(aOldState), VMR3GetStateName(aState) ));
+ ("%s/%s -> %s\n", Global::stringifyMachineState(that->mMachineState), VMR3GetStateName(enmOldState), VMR3GetStateName(enmState) ));
break;
case VMSTATE_RUNNING_FT:
AssertMsg(that->mMachineState == MachineState_FaultTolerantSyncing,
- ("%s/%s -> %s\n", Global::stringifyMachineState(that->mMachineState), VMR3GetStateName(aOldState), VMR3GetStateName(aState) ));
+ ("%s/%s -> %s\n", Global::stringifyMachineState(that->mMachineState), VMR3GetStateName(enmOldState), VMR3GetStateName(enmState) ));
break;
case VMSTATE_FATAL_ERROR:
@@ -7859,15 +7982,15 @@ void Console::changeDragAndDropMode(DragAndDropMode_T aDragAndDropMode)
LogRel(("Drag'n'drop mode: Off\n"));
parm.u.uint32 = VBOX_DRAG_AND_DROP_MODE_OFF;
break;
- case ClipboardMode_GuestToHost:
+ case DragAndDropMode_GuestToHost:
LogRel(("Drag'n'drop mode: Guest to Host\n"));
parm.u.uint32 = VBOX_DRAG_AND_DROP_MODE_GUEST_TO_HOST;
break;
- case ClipboardMode_HostToGuest:
+ case DragAndDropMode_HostToGuest:
LogRel(("Drag'n'drop mode: Host to Guest\n"));
parm.u.uint32 = VBOX_DRAG_AND_DROP_MODE_HOST_TO_GUEST;
break;
- case ClipboardMode_Bidirectional:
+ case DragAndDropMode_Bidirectional:
LogRel(("Drag'n'drop mode: Bidirectional\n"));
parm.u.uint32 = VBOX_DRAG_AND_DROP_MODE_BIDIRECTIONAL;
break;
@@ -7934,10 +8057,10 @@ HRESULT Console::attachUSBDevice(IUSBDevice *aHostDevice, ULONG aMaskedIfs)
AssertComRCReturnRC(hrc);
Assert(portVersion == 1 || portVersion == 2);
- int vrc = VMR3ReqCallWait(ptrVM, 0 /* idDstCpu (saved state, see #6232) */,
- (PFNRT)usbAttachCallback, 9,
- this, ptrVM.raw(), aHostDevice, uuid.raw(), fRemote, Address.c_str(), pvRemoteBackend, portVersion, aMaskedIfs);
-
+ int vrc = VMR3ReqCallWaitU(ptrVM.rawUVM(), 0 /* idDstCpu (saved state, see #6232) */,
+ (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 */
@@ -7962,17 +8085,13 @@ HRESULT Console::attachUSBDevice(IUSBDevice *aHostDevice, ULONG aMaskedIfs)
switch (vrc)
{
case VERR_VUSB_NO_PORTS:
- hrc = setError(E_FAIL,
- tr("Failed to attach the USB device. (No available ports on the USB controller)."));
+ hrc = setError(E_FAIL, tr("Failed to attach the USB device. (No available ports on the USB controller)."));
break;
case VERR_VUSB_USBFS_PERMISSION:
- hrc = setError(E_FAIL,
- tr("Not permitted to open the USB device, check usbfs options"));
+ hrc = setError(E_FAIL, tr("Not permitted to open the USB device, check usbfs options"));
break;
default:
- hrc = setError(E_FAIL,
- tr("Failed to create a proxy device for the USB device. (Error: %Rrc)"),
- vrc);
+ hrc = setError(E_FAIL, tr("Failed to create a proxy device for the USB device. (Error: %Rrc)"), vrc);
break;
}
}
@@ -7991,7 +8110,8 @@ HRESULT Console::attachUSBDevice(IUSBDevice *aHostDevice, ULONG aMaskedIfs)
*/
//static
DECLCALLBACK(int)
-Console::usbAttachCallback(Console *that, PVM pVM, IUSBDevice *aHostDevice, PCRTUUID aUuid, bool aRemote, const char *aAddress, void *pvRemoteBackend, USHORT aPortVersion, ULONG aMaskedIfs)
+Console::usbAttachCallback(Console *that, PUVM pUVM, IUSBDevice *aHostDevice, PCRTUUID aUuid, bool aRemote,
+ const char *aAddress, void *pvRemoteBackend, USHORT aPortVersion, ULONG aMaskedIfs)
{
LogFlowFuncEnter();
LogFlowFunc(("that={%p} aUuid={%RTuuid}\n", that, aUuid));
@@ -7999,7 +8119,7 @@ Console::usbAttachCallback(Console *that, PVM pVM, IUSBDevice *aHostDevice, PCRT
AssertReturn(that && aUuid, VERR_INVALID_PARAMETER);
AssertReturn(!that->isWriteLockOnCurrentThread(), VERR_GENERAL_FAILURE);
- int vrc = PDMR3USBCreateProxyDevice(pVM, aUuid, aRemote, aAddress, pvRemoteBackend,
+ int vrc = PDMR3UsbCreateProxyDevice(pUVM, aUuid, aRemote, aAddress, pvRemoteBackend,
aPortVersion == 1 ? VUSB_STDVER_11 : VUSB_STDVER_20, aMaskedIfs);
LogFlowFunc(("vrc=%Rrc\n", vrc));
LogFlowFuncLeave();
@@ -8025,7 +8145,7 @@ HRESULT Console::detachUSBDevice(const ComObjPtr<OUSBDevice> &aHostDevice)
return ptrVM.rc();
/* if the device is attached, then there must at least one USB hub. */
- AssertReturn(PDMR3USBHasHub(ptrVM), E_FAIL);
+ AssertReturn(PDMR3UsbHasHub(ptrVM.rawUVM()), E_FAIL);
AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
LogFlowThisFunc(("Detaching USB proxy device {%RTuuid}...\n",
@@ -8049,9 +8169,9 @@ HRESULT Console::detachUSBDevice(const ComObjPtr<OUSBDevice> &aHostDevice)
}
alock.release();
- int vrc = VMR3ReqCallWait(ptrVM, 0 /* idDstCpu (saved state, see #6232) */,
- (PFNRT)usbDetachCallback, 5,
- this, ptrVM.raw(), pUuid);
+ int vrc = VMR3ReqCallWaitU(ptrVM.rawUVM(), 0 /* idDstCpu (saved state, see #6232) */,
+ (PFNRT)usbDetachCallback, 5,
+ this, ptrVM.rawUVM(), pUuid);
if (RT_SUCCESS(vrc))
{
LogFlowFunc(("Detached device {%RTuuid}\n", pUuid));
@@ -8067,6 +8187,7 @@ HRESULT Console::detachUSBDevice(const ComObjPtr<OUSBDevice> &aHostDevice)
/**
* USB device detach callback used by DetachUSBDevice().
+ *
* Note that DetachUSBDevice() doesn't return until this callback is executed,
* so we don't use AutoCaller and don't care about reference counters of
* interface pointers passed in.
@@ -8075,7 +8196,7 @@ HRESULT Console::detachUSBDevice(const ComObjPtr<OUSBDevice> &aHostDevice)
*/
//static
DECLCALLBACK(int)
-Console::usbDetachCallback(Console *that, PVM pVM, PCRTUUID aUuid)
+Console::usbDetachCallback(Console *that, PUVM pUVM, PCRTUUID aUuid)
{
LogFlowFuncEnter();
LogFlowFunc(("that={%p} aUuid={%RTuuid}\n", that, aUuid));
@@ -8083,7 +8204,7 @@ Console::usbDetachCallback(Console *that, PVM pVM, PCRTUUID aUuid)
AssertReturn(that && aUuid, VERR_INVALID_PARAMETER);
AssertReturn(!that->isWriteLockOnCurrentThread(), VERR_GENERAL_FAILURE);
- int vrc = PDMR3USBDetachDevice(pVM, aUuid);
+ int vrc = PDMR3UsbDetachDevice(pUVM, aUuid);
LogFlowFunc(("vrc=%Rrc\n", vrc));
LogFlowFuncLeave();
@@ -8134,7 +8255,7 @@ HRESULT Console::attachToTapInterface(INetworkAdapter *networkAdapter)
* Set/obtain the tap interface.
*/
struct ifreq IfReq;
- memset(&IfReq, 0, sizeof(IfReq));
+ RT_ZERO(IfReq);
/* The name of the TAP interface we are using */
Bstr tapDeviceName;
rc = networkAdapter->COMGETTER(BridgedInterface)(tapDeviceName.asOutParam());
@@ -8150,10 +8271,7 @@ HRESULT Console::attachToTapInterface(INetworkAdapter *networkAdapter)
{
/* If we are using a static TAP device then try to open it. */
Utf8Str str(tapDeviceName);
- if (str.length() <= sizeof(IfReq.ifr_name))
- strcpy(IfReq.ifr_name, str.c_str());
- else
- memcpy(IfReq.ifr_name, str.c_str(), sizeof(IfReq.ifr_name) - 1); /** @todo bitch about names which are too long... */
+ RTStrCopy(IfReq.ifr_name, sizeof(IfReq.ifr_name), str.c_str()); /** @todo bitch about names which are too long... */
IfReq.ifr_flags = IFF_TAP | IFF_NO_PI;
rcVBox = ioctl(maTapFD[slot], TUNSETIFF, &IfReq);
if (rcVBox != 0)
@@ -8387,13 +8505,13 @@ HRESULT Console::powerDownHostInterfaces()
* Process callback handler for VMR3LoadFromFile, VMR3LoadFromStream, VMR3Save
* and VMR3Teleport.
*
- * @param pVM The VM handle.
+ * @param pUVM The user mode VM handle.
* @param uPercent Completion percentage (0-100).
* @param pvUser Pointer to an IProgress instance.
* @return VINF_SUCCESS.
*/
/*static*/
-DECLCALLBACK(int) Console::stateProgressCallback(PVM pVM, unsigned uPercent, void *pvUser)
+DECLCALLBACK(int) Console::stateProgressCallback(PUVM pUVM, unsigned uPercent, void *pvUser)
{
IProgress *pProgress = static_cast<IProgress *>(pvUser);
@@ -8401,6 +8519,7 @@ DECLCALLBACK(int) Console::stateProgressCallback(PVM pVM, unsigned uPercent, voi
if (pProgress)
pProgress->SetCurrentOperationProgress(uPercent);
+ NOREF(pUVM);
return VINF_SUCCESS;
}
@@ -8411,7 +8530,7 @@ DECLCALLBACK(int) Console::stateProgressCallback(PVM pVM, unsigned uPercent, voi
* object here...
*/
/*static*/ DECLCALLBACK(void)
-Console::genericVMSetErrorCallback(PVM pVM, void *pvUser, int rc, RT_SRC_POS_DECL,
+Console::genericVMSetErrorCallback(PUVM pUVM, void *pvUser, int rc, RT_SRC_POS_DECL,
const char *pszErrorFmt, va_list va)
{
Utf8Str *pErrorText = (Utf8Str *)pvUser;
@@ -8429,14 +8548,17 @@ Console::genericVMSetErrorCallback(PVM pVM, void *pvUser, int rc, RT_SRC_POS_DEC
*pErrorText = Utf8StrFmt("%N (%Rrc)", pszErrorFmt, &va2, rc, rc);
va_end(va2);
+
+ NOREF(pUVM);
}
/**
* VM runtime error callback function.
* See VMSetRuntimeError for the detailed description of parameters.
*
- * @param pVM The VM handle.
- * @param pvUser The user argument.
+ * @param pUVM The user mode VM handle. Ignored, so passing NULL
+ * is fine.
+ * @param pvUser The user argument, pointer to the Console instance.
* @param fFlags The action flags. See VMSETRTERR_FLAGS_*.
* @param pszErrorId Error ID string.
* @param pszFormat Error message format string.
@@ -8444,7 +8566,7 @@ Console::genericVMSetErrorCallback(PVM pVM, void *pvUser, int rc, RT_SRC_POS_DEC
* @thread EMT.
*/
/* static */ DECLCALLBACK(void)
-Console::setVMRuntimeErrorCallback(PVM pVM, void *pvUser, uint32_t fFlags,
+Console::setVMRuntimeErrorCallback(PUVM pUVM, void *pvUser, uint32_t fFlags,
const char *pszErrorId,
const char *pszFormat, va_list va)
{
@@ -8457,21 +8579,20 @@ Console::setVMRuntimeErrorCallback(PVM pVM, void *pvUser, uint32_t fFlags,
Utf8Str message(pszFormat, va);
LogRel(("Console: VM runtime error: fatal=%RTbool, errorID=%s message=\"%s\"\n",
- fFatal, pszErrorId, message.c_str()));
+ fFatal, pszErrorId, message.c_str()));
- that->onRuntimeError(BOOL(fFatal), Bstr(pszErrorId).raw(),
- Bstr(message).raw());
+ that->onRuntimeError(BOOL(fFatal), Bstr(pszErrorId).raw(), Bstr(message).raw());
- LogFlowFuncLeave();
+ LogFlowFuncLeave(); NOREF(pUVM);
}
/**
* Captures USB devices that match filters of the VM.
* Called at VM startup.
*
- * @param pVM The VM handle.
+ * @param pUVM The VM handle.
*/
-HRESULT Console::captureUSBDevices(PVM pVM)
+HRESULT Console::captureUSBDevices(PUVM pUVM)
{
LogFlowThisFunc(("\n"));
@@ -8479,11 +8600,9 @@ HRESULT Console::captureUSBDevices(PVM pVM)
AssertReturn(!isWriteLockOnCurrentThread(), E_FAIL);
AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
- /* If the machine has an USB controller, ask the USB proxy service to
+ /* If the machine has a USB controller, ask the USB proxy service to
* capture devices */
- PPDMIBASE pBase;
- int vrc = PDMR3QueryLun(pVM, "usb-ohci", 0, 0, &pBase);
- if (RT_SUCCESS(vrc))
+ if (mfVMHasUsbController)
{
/* release the lock before calling Host in VBoxSVC since Host may call
* us back from under its lock (e.g. onUSBDeviceAttach()) which would
@@ -8493,13 +8612,8 @@ HRESULT Console::captureUSBDevices(PVM pVM)
HRESULT hrc = mControl->AutoCaptureUSBDevices();
ComAssertComRCRetRC(hrc);
}
- else if ( vrc == VERR_PDM_DEVICE_NOT_FOUND
- || vrc == VERR_PDM_DEVICE_INSTANCE_NOT_FOUND)
- vrc = VINF_SUCCESS;
- else
- AssertRC(vrc);
- return RT_SUCCESS(vrc) ? S_OK : E_FAIL;
+ return S_OK;
}
@@ -8702,10 +8816,10 @@ void Console::processRemoteUSBDevices(uint32_t u32ClientId, VRDEUSBDEVICEDESC *p
*/
static void faultToleranceProgressCancelCallback(void *pvUser)
{
- PVM pVM = (PVM)pvUser;
+ PUVM pUVM = (PUVM)pvUser;
- if (pVM)
- FTMR3CancelStandby(pVM);
+ if (pUVM)
+ FTMR3CancelStandby(pUVM);
}
/**
@@ -8771,6 +8885,9 @@ DECLCALLBACK(int) Console::powerUpThread(RTTHREAD Thread, void *pvUser)
{
HRESULT rc2 = (*it)->WaitForCompletion(-1);
AssertComRC(rc2);
+
+ rc = task->mProgress->SetNextOperation(BstrFmt(tr("Disk Image Reset Operation - Immutable Image")).raw(), 1);
+ AssertComRCReturnRC(rc);
}
/*
@@ -8844,21 +8961,20 @@ DECLCALLBACK(int) Console::powerUpThread(RTTHREAD Thread, void *pvUser)
/*
* Create the VM
- */
- PVM pVM;
- /*
- * release the lock since EMT will call Console. It's safe because
- * mMachineState is either Starting or Restoring state here.
+ *
+ * Note! Release the lock since EMT will call Console. It's safe because
+ * mMachineState is either Starting or Restoring state here.
*/
alock.release();
+ PVM pVM;
vrc = VMR3Create(cCpus,
pConsole->mpVmm2UserMethods,
Console::genericVMSetErrorCallback,
&task->mErrorMsg,
task->mConfigConstructor,
static_cast<Console *>(pConsole),
- &pVM);
+ &pVM, NULL);
alock.acquire();
@@ -8872,14 +8988,14 @@ DECLCALLBACK(int) Console::powerUpThread(RTTHREAD Thread, void *pvUser)
/*
* Register our load/save state file handlers
*/
- vrc = SSMR3RegisterExternal(pVM, sSSMConsoleUnit, 0 /*iInstance*/, sSSMConsoleVer, 0 /* cbGuess */,
+ vrc = SSMR3RegisterExternal(pConsole->mpUVM, sSSMConsoleUnit, 0 /*iInstance*/, sSSMConsoleVer, 0 /* cbGuess */,
NULL, NULL, NULL,
NULL, saveStateFileExec, NULL,
NULL, loadStateFileExec, NULL,
static_cast<Console *>(pConsole));
AssertRCBreak(vrc);
- vrc = static_cast<Console *>(pConsole)->getDisplay()->registerSSM(pVM);
+ vrc = static_cast<Console *>(pConsole)->getDisplay()->registerSSM(pConsole->mpUVM);
AssertRC(vrc);
if (RT_FAILURE(vrc))
break;
@@ -8909,10 +9025,11 @@ DECLCALLBACK(int) Console::powerUpThread(RTTHREAD Thread, void *pvUser)
if (FAILED(rc))
{
ErrorInfoKeeper eik;
- setVMRuntimeErrorCallbackF(pVM, pConsole, 0, "BrokenSharedFolder",
- N_("The shared folder '%s' could not be set up: %ls.\n"
- "The shared folder setup will not be complete. It is recommended to power down the virtual machine and fix the shared folder settings while the machine is not running"),
- it->first.c_str(), eik.getText().raw());
+ pConsole->setVMRuntimeErrorCallbackF(0, "BrokenSharedFolder",
+ N_("The shared folder '%s' could not be set up: %ls.\n"
+ "The shared folder setup will not be complete. It is recommended to power down the virtual "
+ "machine and fix the shared folder settings while the machine is not running"),
+ it->first.c_str(), eik.getText().raw());
}
}
if (FAILED(rc))
@@ -8928,8 +9045,9 @@ DECLCALLBACK(int) Console::powerUpThread(RTTHREAD Thread, void *pvUser)
/*
* Capture USB devices.
*/
- rc = pConsole->captureUSBDevices(pVM);
- if (FAILED(rc)) break;
+ rc = pConsole->captureUSBDevices(pConsole->mpUVM);
+ if (FAILED(rc))
+ break;
/* Load saved state? */
if (task->mSavedStateFile.length())
@@ -8937,7 +9055,7 @@ DECLCALLBACK(int) Console::powerUpThread(RTTHREAD Thread, void *pvUser)
LogFlowFunc(("Restoring saved state from '%s'...\n",
task->mSavedStateFile.c_str()));
- vrc = VMR3LoadFromFile(pVM,
+ vrc = VMR3LoadFromFile(pConsole->mpUVM,
task->mSavedStateFile.c_str(),
Console::stateProgressCallback,
static_cast<IProgress *>(task->mProgress));
@@ -8954,7 +9072,7 @@ DECLCALLBACK(int) Console::powerUpThread(RTTHREAD Thread, void *pvUser)
vrc = pConsole->mptrExtPackManager->callAllVmPowerOnHooks(pConsole, pVM);
#endif
if (RT_SUCCESS(vrc))
- vrc = VMR3Resume(pVM);
+ vrc = VMR3Resume(pConsole->mpUVM, VMRESUMEREASON_STATE_RESTORED);
AssertLogRelRC(vrc);
}
}
@@ -8962,7 +9080,7 @@ DECLCALLBACK(int) Console::powerUpThread(RTTHREAD Thread, void *pvUser)
/* Power off in case we failed loading or resuming the VM */
if (RT_FAILURE(vrc))
{
- int vrc2 = VMR3PowerOff(pVM); AssertLogRelRC(vrc2);
+ int vrc2 = VMR3PowerOff(pConsole->mpUVM); AssertLogRelRC(vrc2);
#ifdef VBOX_WITH_EXTPACK
pConsole->mptrExtPackManager->callAllVmPowerOffHooks(pConsole, pVM);
#endif
@@ -8972,12 +9090,12 @@ DECLCALLBACK(int) Console::powerUpThread(RTTHREAD Thread, void *pvUser)
{
/* -> ConsoleImplTeleporter.cpp */
bool fPowerOffOnFailure;
- rc = pConsole->teleporterTrg(VMR3GetUVM(pVM), pMachine, &task->mErrorMsg, task->mStartPaused,
+ rc = pConsole->teleporterTrg(pConsole->mpUVM, pMachine, &task->mErrorMsg, task->mStartPaused,
task->mProgress, &fPowerOffOnFailure);
if (FAILED(rc) && fPowerOffOnFailure)
{
ErrorInfoKeeper eik;
- int vrc2 = VMR3PowerOff(pVM); AssertLogRelRC(vrc2);
+ int vrc2 = VMR3PowerOff(pConsole->mpUVM); AssertLogRelRC(vrc2);
#ifdef VBOX_WITH_EXTPACK
pConsole->mptrExtPackManager->callAllVmPowerOffHooks(pConsole, pVM);
#endif
@@ -9001,7 +9119,7 @@ DECLCALLBACK(int) Console::powerUpThread(RTTHREAD Thread, void *pvUser)
if (SUCCEEDED(rc))
rc = pMachine->COMGETTER(FaultTolerancePassword)(bstrPassword.asOutParam());
}
- if (task->mProgress->setCancelCallback(faultToleranceProgressCancelCallback, pVM))
+ if (task->mProgress->setCancelCallback(faultToleranceProgressCancelCallback, pConsole->mpUVM))
{
if (SUCCEEDED(rc))
{
@@ -9015,7 +9133,7 @@ DECLCALLBACK(int) Console::powerUpThread(RTTHREAD Thread, void *pvUser)
vrc = pConsole->mptrExtPackManager->callAllVmPowerOnHooks(pConsole, pVM);
#endif
if (RT_SUCCESS(vrc))
- vrc = FTMR3PowerOn(pVM,
+ vrc = FTMR3PowerOn(pConsole->mpUVM,
task->mEnmFaultToleranceState == FaultToleranceState_Master /* fMaster */,
uInterval,
pszAddress,
@@ -9038,7 +9156,7 @@ DECLCALLBACK(int) Console::powerUpThread(RTTHREAD Thread, void *pvUser)
vrc = pConsole->mptrExtPackManager->callAllVmPowerOnHooks(pConsole, pVM);
#endif
if (RT_SUCCESS(vrc))
- vrc = VMR3PowerOn(pVM);
+ vrc = VMR3PowerOn(pConsole->mpUVM);
AssertLogRelRC(vrc);
}
@@ -9068,7 +9186,7 @@ DECLCALLBACK(int) Console::powerUpThread(RTTHREAD Thread, void *pvUser)
* be sticky but our error callback isn't.
*/
alock.release();
- VMR3AtErrorDeregister(pVM, Console::genericVMSetErrorCallback, &task->mErrorMsg);
+ VMR3AtErrorDeregister(pConsole->mpUVM, Console::genericVMSetErrorCallback, &task->mErrorMsg);
/** @todo register another VMSetError callback? */
alock.acquire();
}
@@ -9127,8 +9245,7 @@ DECLCALLBACK(int) Console::powerUpThread(RTTHREAD Thread, void *pvUser)
ErrorInfoKeeper eik;
Assert(pConsole->mpUVM == NULL);
- vmstateChangeCallback(NULL, VMSTATE_TERMINATED, VMSTATE_CREATING,
- pConsole);
+ vmstateChangeCallback(NULL, VMSTATE_TERMINATED, VMSTATE_CREATING, pConsole);
}
/*
@@ -9168,8 +9285,8 @@ 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 pVM The VM handle.
+ * @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.
* @param enmBus The storage bus type of the controller.
@@ -9182,8 +9299,8 @@ DECLCALLBACK(int) Console::powerUpThread(RTTHREAD Thread, void *pvUser)
* @return VBox status code.
*/
/* static */
-DECLCALLBACK(int) Console::reconfigureMediumAttachment(Console *pConsole,
- PVM pVM,
+DECLCALLBACK(int) Console::reconfigureMediumAttachment(Console *pThis,
+ PUVM pUVM,
const char *pcszDevice,
unsigned uInstance,
StorageBus_T enmBus,
@@ -9196,13 +9313,11 @@ DECLCALLBACK(int) Console::reconfigureMediumAttachment(Console *pConsole,
MachineState_T aMachineState,
HRESULT *phrc)
{
- LogFlowFunc(("pVM=%p aMediumAtt=%p phrc=%p\n", pVM, aMediumAtt, phrc));
+ 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
@@ -9214,33 +9329,37 @@ DECLCALLBACK(int) Console::reconfigureMediumAttachment(Console *pConsole,
/* Determine the base path for the device instance. */
PCFGMNODE pCtlInst;
- pCtlInst = CFGMR3GetChildF(CFGMR3GetRoot(pVM), "Devices/%s/%u/", pcszDevice, uInstance);
+ pCtlInst = CFGMR3GetChildF(CFGMR3GetRootU(pUVM), "Devices/%s/%u/", pcszDevice, uInstance);
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 */,
- pVM,
- 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"));
@@ -9253,7 +9372,7 @@ DECLCALLBACK(int) Console::reconfigureMediumAttachment(Console *pConsole,
static void takesnapshotProgressCancelCallback(void *pvUser)
{
PUVM pUVM = (PUVM)pvUser;
- SSMR3Cancel(VMR3GetVM(pUVM));
+ SSMR3Cancel(pUVM);
}
/**
@@ -9308,13 +9427,13 @@ DECLCALLBACK(int) Console::fntTakeSnapshotWorker(RTTHREAD Thread, void *pvUser)
fBeganTakingSnapshot = true;
- /*
- * state file is non-null only when the VM is paused
- * (i.e. creating a snapshot online)
- */
- bool f = (!pTask->bstrSavedStateFile.isEmpty() && pTask->fTakingSnapshotOnline)
- || ( pTask->bstrSavedStateFile.isEmpty() && !pTask->fTakingSnapshotOnline);
- if (!f)
+ /* Check sanity: for offline snapshots there must not be a saved state
+ * file name. All other combinations are valid (even though online
+ * snapshots without saved state file seems inconsistent - there are
+ * some exotic use cases, which need to be explicitly enabled, see the
+ * code of SessionMachine::BeginTakingSnapshot. */
+ if ( !pTask->fTakingSnapshotOnline
+ && !pTask->bstrSavedStateFile.isEmpty())
throw setErrorStatic(E_FAIL, "Invalid state of saved state file");
/* sync the state with the server */
@@ -9326,31 +9445,38 @@ DECLCALLBACK(int) Console::fntTakeSnapshotWorker(RTTHREAD Thread, void *pvUser)
// STEP 3: save the VM state (if online)
if (pTask->fTakingSnapshotOnline)
{
- Utf8Str strSavedStateFile(pTask->bstrSavedStateFile);
-
+ int vrc;
SafeVMPtr ptrVM(that);
if (!ptrVM.isOk())
throw ptrVM.rc();
pTask->mProgress->SetNextOperation(Bstr(tr("Saving the machine state")).raw(),
pTask->ulMemSize); // operation weight, same as computed when setting up progress object
- pTask->mProgress->setCancelCallback(takesnapshotProgressCancelCallback, ptrVM.rawUVM());
+ if (!pTask->bstrSavedStateFile.isEmpty())
+ {
+ Utf8Str strSavedStateFile(pTask->bstrSavedStateFile);
- alock.release();
- LogFlowFunc(("VMR3Save...\n"));
- int vrc = VMR3Save(ptrVM,
+ pTask->mProgress->setCancelCallback(takesnapshotProgressCancelCallback, ptrVM.rawUVM());
+
+ alock.release();
+ LogFlowFunc(("VMR3Save...\n"));
+ vrc = VMR3Save(ptrVM.rawUVM(),
strSavedStateFile.c_str(),
true /*fContinueAfterwards*/,
Console::stateProgressCallback,
static_cast<IProgress *>(pTask->mProgress),
&fSuspenededBySave);
- alock.acquire();
- if (RT_FAILURE(vrc))
- throw setErrorStatic(E_FAIL,
- tr("Failed to save the machine state to '%s' (%Rrc)"),
- strSavedStateFile.c_str(), vrc);
+ alock.acquire();
+ if (RT_FAILURE(vrc))
+ throw setErrorStatic(E_FAIL,
+ tr("Failed to save the machine state to '%s' (%Rrc)"),
+ strSavedStateFile.c_str(), vrc);
+
+ pTask->mProgress->setCancelCallback(NULL, NULL);
+ }
+ else
+ LogRel(("Console: skipped saving state as part of online snapshot\n"));
- pTask->mProgress->setCancelCallback(NULL, NULL);
if (!pTask->mProgress->notifyPointOfNoReturn())
throw setErrorStatic(E_FAIL, tr("Canceled"));
that->mptrCancelableProgress.setNull();
@@ -9415,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 = VMR3ReqCallWait(ptrVM,
- VMCPUID_ANY,
- (PFNRT)reconfigureMediumAttachment,
- 13,
- that,
- ptrVM.raw(),
- 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))
@@ -9488,7 +9602,7 @@ DECLCALLBACK(int) Console::fntTakeSnapshotWorker(RTTHREAD Thread, void *pvUser)
LogFlowFunc(("VMR3Resume...\n"));
SafeVMPtr ptrVM(that);
alock.release();
- int vrc = VMR3Resume(ptrVM);
+ int vrc = VMR3Resume(ptrVM.rawUVM(), VMRESUMEREASON_STATE_SAVED);
alock.acquire();
if (RT_FAILURE(vrc))
{
@@ -9546,7 +9660,7 @@ DECLCALLBACK(int) Console::fntTakeSnapshotWorker(RTTHREAD Thread, void *pvUser)
LogFlowFunc(("VMR3Resume (on failure)...\n"));
SafeVMPtr ptrVM(that);
alock.release();
- int vrc = VMR3Resume(ptrVM); AssertLogRelRC(vrc);
+ int vrc = VMR3Resume(ptrVM.rawUVM(), VMRESUMEREASON_STATE_SAVED); AssertLogRelRC(vrc);
alock.acquire();
if (RT_FAILURE(vrc))
that->setMachineState(MachineState_Paused);
@@ -9606,7 +9720,7 @@ DECLCALLBACK(int) Console::saveStateThread(RTTHREAD Thread, void *pvUser)
LogFlowFunc(("Saving the state to '%s'...\n", task->mSavedStateFile.c_str()));
bool fSuspenededBySave;
- int vrc = VMR3Save(task->mpVM,
+ int vrc = VMR3Save(task->mpUVM,
task->mSavedStateFile.c_str(),
false, /*fContinueAfterwards*/
Console::stateProgressCallback,
@@ -9758,6 +9872,18 @@ Console::vmm2User_NotifyPdmtTerm(PCVMM2USERMETHODS pThis, PUVM pUVM)
VirtualBoxBase::uninitializeComForThread();
}
+/**
+ * @interface_method_impl{VMM2USERMETHODS,pfnNotifyResetTurnedIntoPowerOff}
+ */
+/*static*/ DECLCALLBACK(void)
+Console::vmm2User_NotifyResetTurnedIntoPowerOff(PCVMM2USERMETHODS pThis, PUVM pUVM)
+{
+ Console *pConsole = ((MYVMM2USERMETHODS *)pThis)->pConsole;
+ NOREF(pUVM);
+
+ pConsole->mfPowerOffCausedByReset = true;
+}
+
@@ -9802,14 +9928,14 @@ typedef struct DRVMAINSTATUS
*/
DECLCALLBACK(void) Console::drvStatus_UnitChanged(PPDMILEDCONNECTORS pInterface, unsigned iLUN)
{
- PDRVMAINSTATUS pData = (PDRVMAINSTATUS)((uintptr_t)pInterface - RT_OFFSETOF(DRVMAINSTATUS, ILedConnectors));
- if (iLUN >= pData->iFirstLUN && iLUN <= pData->iLastLUN)
+ PDRVMAINSTATUS pThis = (PDRVMAINSTATUS)((uintptr_t)pInterface - RT_OFFSETOF(DRVMAINSTATUS, ILedConnectors));
+ if (iLUN >= pThis->iFirstLUN && iLUN <= pThis->iLastLUN)
{
PPDMLED pLed;
- int rc = pData->pLedPorts->pfnQueryStatusLed(pData->pLedPorts, iLUN, &pLed);
+ int rc = pThis->pLedPorts->pfnQueryStatusLed(pThis->pLedPorts, iLUN, &pLed);
if (RT_FAILURE(rc))
pLed = NULL;
- ASMAtomicWritePtr(&pData->papLeds[iLUN - pData->iFirstLUN], pLed);
+ ASMAtomicWritePtr(&pThis->papLeds[iLUN - pThis->iFirstLUN], pLed);
Log(("drvStatus_UnitChanged: iLUN=%d pLed=%p\n", iLUN, pLed));
}
}
@@ -9824,17 +9950,17 @@ DECLCALLBACK(void) Console::drvStatus_UnitChanged(PPDMILEDCONNECTORS pInterface,
*/
DECLCALLBACK(int) Console::drvStatus_MediumEjected(PPDMIMEDIANOTIFY pInterface, unsigned uLUN)
{
- PDRVMAINSTATUS pData = (PDRVMAINSTATUS)((uintptr_t)pInterface - RT_OFFSETOF(DRVMAINSTATUS, IMediaNotify));
- PPDMDRVINS pDrvIns = pData->pDrvIns;
+ PDRVMAINSTATUS pThis = (PDRVMAINSTATUS)((uintptr_t)pInterface - RT_OFFSETOF(DRVMAINSTATUS, IMediaNotify));
+ PPDMDRVINS pDrvIns = pThis->pDrvIns;
LogFunc(("uLUN=%d\n", uLUN));
- if (pData->pmapMediumAttachments)
+ if (pThis->pmapMediumAttachments)
{
- AutoWriteLock alock(pData->pConsole COMMA_LOCKVAL_SRC_POS);
+ AutoWriteLock alock(pThis->pConsole COMMA_LOCKVAL_SRC_POS);
ComPtr<IMediumAttachment> pMediumAtt;
- Utf8Str devicePath = Utf8StrFmt("%s/LUN#%u", pData->pszDeviceInstance, uLUN);
- Console::MediumAttachmentMap::const_iterator end = pData->pmapMediumAttachments->end();
- Console::MediumAttachmentMap::const_iterator it = pData->pmapMediumAttachments->find(devicePath);
+ Utf8Str devicePath = Utf8StrFmt("%s/LUN#%u", pThis->pszDeviceInstance, uLUN);
+ Console::MediumAttachmentMap::const_iterator end = pThis->pmapMediumAttachments->end();
+ Console::MediumAttachmentMap::const_iterator it = pThis->pmapMediumAttachments->find(devicePath);
if (it != end)
pMediumAtt = it->second;
Assert(!pMediumAtt.isNull());
@@ -9853,15 +9979,15 @@ DECLCALLBACK(int) Console::drvStatus_MediumEjected(PPDMIMEDIANOTIFY pInterface,
alock.release();
ComPtr<IMediumAttachment> pNewMediumAtt;
- rc = pData->pConsole->mControl->EjectMedium(pMediumAtt, pNewMediumAtt.asOutParam());
+ rc = pThis->pConsole->mControl->EjectMedium(pMediumAtt, pNewMediumAtt.asOutParam());
if (SUCCEEDED(rc))
- fireMediumChangedEvent(pData->pConsole->mEventSource, pNewMediumAtt);
+ fireMediumChangedEvent(pThis->pConsole->mEventSource, pNewMediumAtt);
alock.acquire();
if (pNewMediumAtt != pMediumAtt)
{
- pData->pmapMediumAttachments->erase(devicePath);
- pData->pmapMediumAttachments->insert(std::make_pair(devicePath, pNewMediumAtt));
+ pThis->pmapMediumAttachments->erase(devicePath);
+ pThis->pmapMediumAttachments->insert(std::make_pair(devicePath, pNewMediumAtt));
}
}
}
@@ -9893,15 +10019,15 @@ DECLCALLBACK(void *) Console::drvStatus_QueryInterface(PPDMIBASE pInterface, co
*/
DECLCALLBACK(void) Console::drvStatus_Destruct(PPDMDRVINS pDrvIns)
{
- PDRVMAINSTATUS pData = PDMINS_2_DATA(pDrvIns, PDRVMAINSTATUS);
- LogFlowFunc(("iInstance=%d\n", pDrvIns->iInstance));
PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns);
+ PDRVMAINSTATUS pThis = PDMINS_2_DATA(pDrvIns, PDRVMAINSTATUS);
+ LogFlowFunc(("iInstance=%d\n", pDrvIns->iInstance));
- if (pData->papLeds)
+ if (pThis->papLeds)
{
- unsigned iLed = pData->iLastLUN - pData->iFirstLUN + 1;
+ unsigned iLed = pThis->iLastLUN - pThis->iFirstLUN + 1;
while (iLed-- > 0)
- ASMAtomicWriteNullPtr(&pData->papLeds[iLed]);
+ ASMAtomicWriteNullPtr(&pThis->papLeds[iLed]);
}
}
@@ -9913,9 +10039,9 @@ DECLCALLBACK(void) Console::drvStatus_Destruct(PPDMDRVINS pDrvIns)
*/
DECLCALLBACK(int) Console::drvStatus_Construct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
{
- PDRVMAINSTATUS pData = PDMINS_2_DATA(pDrvIns, PDRVMAINSTATUS);
- LogFlowFunc(("iInstance=%d\n", pDrvIns->iInstance));
PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
+ PDRVMAINSTATUS pThis = PDMINS_2_DATA(pDrvIns, PDRVMAINSTATUS);
+ LogFlowFunc(("iInstance=%d\n", pDrvIns->iInstance));
/*
* Validate configuration.
@@ -9930,36 +10056,36 @@ DECLCALLBACK(int) Console::drvStatus_Construct(PPDMDRVINS pDrvIns, PCFGMNODE pCf
* Data.
*/
pDrvIns->IBase.pfnQueryInterface = Console::drvStatus_QueryInterface;
- pData->ILedConnectors.pfnUnitChanged = Console::drvStatus_UnitChanged;
- pData->IMediaNotify.pfnEjected = Console::drvStatus_MediumEjected;
- pData->pDrvIns = pDrvIns;
- pData->pszDeviceInstance = NULL;
+ pThis->ILedConnectors.pfnUnitChanged = Console::drvStatus_UnitChanged;
+ pThis->IMediaNotify.pfnEjected = Console::drvStatus_MediumEjected;
+ pThis->pDrvIns = pDrvIns;
+ pThis->pszDeviceInstance = NULL;
/*
* Read config.
*/
- int rc = CFGMR3QueryPtr(pCfg, "papLeds", (void **)&pData->papLeds);
+ int rc = CFGMR3QueryPtr(pCfg, "papLeds", (void **)&pThis->papLeds);
if (RT_FAILURE(rc))
{
AssertMsgFailed(("Configuration error: Failed to query the \"papLeds\" value! rc=%Rrc\n", rc));
return rc;
}
- rc = CFGMR3QueryPtrDef(pCfg, "pmapMediumAttachments", (void **)&pData->pmapMediumAttachments, NULL);
+ rc = CFGMR3QueryPtrDef(pCfg, "pmapMediumAttachments", (void **)&pThis->pmapMediumAttachments, NULL);
if (RT_FAILURE(rc))
{
AssertMsgFailed(("Configuration error: Failed to query the \"pmapMediumAttachments\" value! rc=%Rrc\n", rc));
return rc;
}
- if (pData->pmapMediumAttachments)
+ if (pThis->pmapMediumAttachments)
{
- rc = CFGMR3QueryStringAlloc(pCfg, "DeviceInstance", &pData->pszDeviceInstance);
+ rc = CFGMR3QueryStringAlloc(pCfg, "DeviceInstance", &pThis->pszDeviceInstance);
if (RT_FAILURE(rc))
{
AssertMsgFailed(("Configuration error: Failed to query the \"DeviceInstance\" value! rc=%Rrc\n", rc));
return rc;
}
- rc = CFGMR3QueryPtr(pCfg, "pConsole", (void **)&pData->pConsole);
+ rc = CFGMR3QueryPtr(pCfg, "pConsole", (void **)&pThis->pConsole);
if (RT_FAILURE(rc))
{
AssertMsgFailed(("Configuration error: Failed to query the \"pConsole\" value! rc=%Rrc\n", rc));
@@ -9967,26 +10093,26 @@ DECLCALLBACK(int) Console::drvStatus_Construct(PPDMDRVINS pDrvIns, PCFGMNODE pCf
}
}
- rc = CFGMR3QueryU32(pCfg, "First", &pData->iFirstLUN);
+ rc = CFGMR3QueryU32(pCfg, "First", &pThis->iFirstLUN);
if (rc == VERR_CFGM_VALUE_NOT_FOUND)
- pData->iFirstLUN = 0;
+ pThis->iFirstLUN = 0;
else if (RT_FAILURE(rc))
{
AssertMsgFailed(("Configuration error: Failed to query the \"First\" value! rc=%Rrc\n", rc));
return rc;
}
- rc = CFGMR3QueryU32(pCfg, "Last", &pData->iLastLUN);
+ rc = CFGMR3QueryU32(pCfg, "Last", &pThis->iLastLUN);
if (rc == VERR_CFGM_VALUE_NOT_FOUND)
- pData->iLastLUN = 0;
+ pThis->iLastLUN = 0;
else if (RT_FAILURE(rc))
{
AssertMsgFailed(("Configuration error: Failed to query the \"Last\" value! rc=%Rrc\n", rc));
return rc;
}
- if (pData->iFirstLUN > pData->iLastLUN)
+ if (pThis->iFirstLUN > pThis->iLastLUN)
{
- AssertMsgFailed(("Configuration error: Invalid unit range %u-%u\n", pData->iFirstLUN, pData->iLastLUN));
+ AssertMsgFailed(("Configuration error: Invalid unit range %u-%u\n", pThis->iFirstLUN, pThis->iLastLUN));
return VERR_GENERAL_FAILURE;
}
@@ -9994,12 +10120,12 @@ DECLCALLBACK(int) Console::drvStatus_Construct(PPDMDRVINS pDrvIns, PCFGMNODE pCf
* Get the ILedPorts interface of the above driver/device and
* query the LEDs we want.
*/
- pData->pLedPorts = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMILEDPORTS);
- AssertMsgReturn(pData->pLedPorts, ("Configuration error: No led ports interface above!\n"),
+ pThis->pLedPorts = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMILEDPORTS);
+ AssertMsgReturn(pThis->pLedPorts, ("Configuration error: No led ports interface above!\n"),
VERR_PDM_MISSING_INTERFACE_ABOVE);
- for (unsigned i = pData->iFirstLUN; i <= pData->iLastLUN; ++i)
- Console::drvStatus_UnitChanged(&pData->ILedConnectors, i);
+ for (unsigned i = pThis->iFirstLUN; i <= pThis->iLastLUN; ++i)
+ Console::drvStatus_UnitChanged(&pThis->ILedConnectors, i);
return VINF_SUCCESS;
}