summaryrefslogtreecommitdiff
path: root/src/VBox/Main/src-client/ConsoleImpl.cpp
diff options
context:
space:
mode:
authorFelix Geyer <debfx-pkg@fobos.de>2011-07-29 17:55:18 +0200
committerFelix Geyer <debfx-pkg@fobos.de>2011-07-29 17:55:18 +0200
commitcba113ca2826bc4814be2f69a7704c865a37d4ea (patch)
tree511123b10dd1e58e56958520534f5c50e6f570fc /src/VBox/Main/src-client/ConsoleImpl.cpp
parent6a16f6900dd884e07125b51c9625f6be0a1f9b70 (diff)
downloadvirtualbox-cba113ca2826bc4814be2f69a7704c865a37d4ea.tar.gz
Imported Upstream version 4.1.0-dfsgupstream/4.1.0-dfsg
Diffstat (limited to 'src/VBox/Main/src-client/ConsoleImpl.cpp')
-rw-r--r--src/VBox/Main/src-client/ConsoleImpl.cpp1631
1 files changed, 1229 insertions, 402 deletions
diff --git a/src/VBox/Main/src-client/ConsoleImpl.cpp b/src/VBox/Main/src-client/ConsoleImpl.cpp
index c3d2025b7..126edde3a 100644
--- a/src/VBox/Main/src-client/ConsoleImpl.cpp
+++ b/src/VBox/Main/src-client/ConsoleImpl.cpp
@@ -1,4 +1,4 @@
-/* $Id: ConsoleImpl.cpp $ */
+/* $Id: ConsoleImpl.cpp 37851 2011-07-08 17:04:03Z vboxsync $ */
/** @file
* VBox Console COM Class implementation
*/
@@ -56,6 +56,9 @@
#include "RemoteUSBDeviceImpl.h"
#include "SharedFolderImpl.h"
#include "AudioSnifferInterface.h"
+#ifdef VBOX_WITH_USB_VIDEO
+# include "UsbWebcamInterface.h"
+#endif
#include "ProgressCombinedImpl.h"
#include "ConsoleVRDPServer.h"
#include "VMMDev.h"
@@ -136,7 +139,7 @@
* callers.
*
* If \a aUsesVMPtr parameter is true, the task structure will also add itself
- * as a Console::mpVM caller with the same meaning as above. See
+ * as a Console::mpUVM caller with the same meaning as above. See
* Console::addVMCaller() for more info.
*/
struct VMTask
@@ -149,7 +152,9 @@ struct VMTask
mConsoleCaller(aConsole),
mProgress(aProgress),
mServerProgress(aServerProgress),
- mVMCallerAdded(false)
+ mpVM(NULL),
+ mRC(E_FAIL),
+ mpSafeVMPtr(NULL)
{
AssertReturnVoid(aConsole);
mRC = mConsoleCaller.rc();
@@ -157,16 +162,17 @@ struct VMTask
return;
if (aUsesVMPtr)
{
- mRC = aConsole->addVMCaller();
- if (SUCCEEDED(mRC))
- mVMCallerAdded = true;
+ mpSafeVMPtr = new Console::SafeVMPtr(aConsole);
+ if (mpSafeVMPtr->isOk())
+ mpVM = mpSafeVMPtr->raw();
+ else
+ mRC = mpSafeVMPtr->rc();
}
}
~VMTask()
{
- if (mVMCallerAdded)
- mConsole->releaseVMCaller();
+ releaseVMCaller();
}
HRESULT rc() const { return mRC; }
@@ -175,21 +181,23 @@ struct VMTask
/** Releases the VM caller before destruction. Not normally necessary. */
void releaseVMCaller()
{
- AssertReturnVoid(mVMCallerAdded);
- mConsole->releaseVMCaller();
- mVMCallerAdded = false;
+ if (mpSafeVMPtr)
+ {
+ delete mpSafeVMPtr;
+ mpSafeVMPtr = NULL;
+ }
}
- const ComObjPtr<Console> mConsole;
- AutoCaller mConsoleCaller;
- const ComObjPtr<Progress> mProgress;
- Utf8Str mErrorMsg;
- const ComPtr<IProgress> mServerProgress;
+ const ComObjPtr<Console> mConsole;
+ AutoCaller mConsoleCaller;
+ const ComObjPtr<Progress> mProgress;
+ Utf8Str mErrorMsg;
+ const ComPtr<IProgress> mServerProgress;
+ PVM mpVM;
private:
-
- HRESULT mRC;
- bool mVMCallerAdded : 1;
+ HRESULT mRC;
+ Console::SafeVMPtr *mpSafeVMPtr;
};
struct VMTakeSnapshotTask : public VMTask
@@ -265,9 +273,18 @@ inline static const char *networkAdapterTypeToName(NetworkAdapterType_T adapterT
class VmEventListener {
public:
- VmEventListener(Console *aConsole)
+ VmEventListener()
+ {}
+
+
+ HRESULT init(Console *aConsole)
{
mConsole = aConsole;
+ return S_OK;
+ }
+
+ void uninit()
+ {
}
virtual ~VmEventListener()
@@ -313,8 +330,15 @@ public:
mConsole->onNATRedirectRuleChange(ulSlot, fRemove, proto, hostIp.raw(), hostPort, guestIp.raw(), guestPort);
}
break;
+
+ case VBoxEventType_OnHostPciDevicePlug:
+ {
+ // handle if needed
+ break;
+ }
+
default:
- AssertFailed();
+ AssertFailed();
}
return S_OK;
}
@@ -334,7 +358,7 @@ VBOX_LISTENER_DECLARE(VmEventListenerImpl)
Console::Console()
: mSavedStateDataLoaded(false)
, mConsoleVRDPServer(NULL)
- , mpVM(NULL)
+ , mpUVM(NULL)
, mVMCallers(0)
, mVMZeroCallersSem(NIL_RTSEMEVENT)
, mVMDestroying(false)
@@ -346,8 +370,12 @@ Console::Console()
, mpVmm2UserMethods(NULL)
, m_pVMMDev(NULL)
, mAudioSniffer(NULL)
+#ifdef VBOX_WITH_USB_VIDEO
+ , mUsbWebcamInterface(NULL)
+#endif
, mBusMgr(NULL)
, mVMStateChangeCallbackDisabled(false)
+ , mfUseHostClipboard(true)
, mMachineState(MachineState_PoweredOff)
{
for (ULONG slot = 0; slot < SchemaDefs::NetworkAdapterCount; ++slot)
@@ -383,7 +411,7 @@ HRESULT Console::FinalConstruct()
pVmm2UserMethods->pConsole = this;
mpVmm2UserMethods = pVmm2UserMethods;
- return S_OK;
+ return BaseFinalConstruct();
}
void Console::FinalRelease()
@@ -391,6 +419,8 @@ void Console::FinalRelease()
LogFlowThisFunc(("\n"));
uninit();
+
+ BaseFinalRelease();
}
// public initializer/uninitializer for internal purposes only
@@ -480,6 +510,10 @@ HRESULT Console::init(IMachine *aMachine, IInternalMachineControl *aControl)
unconst(mAudioSniffer) = new AudioSniffer(this);
AssertReturn(mAudioSniffer, E_FAIL);
+#ifdef VBOX_WITH_USB_VIDEO
+ unconst(mUsbWebcamInterface) = new UsbWebcamInterface(this);
+ AssertReturn(mUsbWebcamInterface, E_FAIL);
+#endif
/* VirtualBox events registration. */
{
@@ -490,10 +524,14 @@ HRESULT Console::init(IMachine *aMachine, IInternalMachineControl *aControl)
ComPtr<IEventSource> pES;
rc = pVirtualBox->COMGETTER(EventSource)(pES.asOutParam());
AssertComRC(rc);
- mVmListner = new VmEventListenerImpl(this);
+ ComObjPtr<VmEventListenerImpl> aVmListener;
+ aVmListener.createObject();
+ aVmListener->init(new VmEventListener(), this);
+ mVmListener = aVmListener;
com::SafeArray<VBoxEventType_T> eventTypes;
eventTypes.push_back(VBoxEventType_OnNATRedirect);
- rc = pES->RegisterListener(mVmListner, ComSafeArrayAsInParam(eventTypes), true);
+ eventTypes.push_back(VBoxEventType_OnHostPciDevicePlug);
+ rc = pES->RegisterListener(aVmListener, ComSafeArrayAsInParam(eventTypes), true);
AssertComRC(rc);
}
@@ -529,7 +567,7 @@ void Console::uninit()
}
LogFlowThisFunc(("initFailed()=%d\n", autoUninitSpan.initFailed()));
- if (mVmListner)
+ if (mVmListener)
{
ComPtr<IEventSource> pES;
ComPtr<IVirtualBox> pVirtualBox;
@@ -541,18 +579,18 @@ void Console::uninit()
AssertComRC(rc);
if (!pES.isNull())
{
- rc = pES->UnregisterListener(mVmListner);
+ rc = pES->UnregisterListener(mVmListener);
AssertComRC(rc);
}
}
- mVmListner->Release();
+ mVmListener.setNull();
}
/* power down the VM if necessary */
- if (mpVM)
+ if (mpUVM)
{
powerDown();
- Assert(mpVM == NULL);
+ Assert(mpUVM == NULL);
}
if (mVMZeroCallersSem != NIL_RTSEMEVENT)
@@ -567,6 +605,14 @@ void Console::uninit()
mpVmm2UserMethods = NULL;
}
+#ifdef VBOX_WITH_USB_VIDEO
+ if (mUsbWebcamInterface)
+ {
+ delete mUsbWebcamInterface;
+ unconst(mUsbWebcamInterface) = NULL;
+ }
+#endif
+
if (mAudioSniffer)
{
delete mAudioSniffer;
@@ -652,8 +698,13 @@ void Console::uninit()
/**
* Handles guest properties on a VM reset.
- * At the moment we only delete properties which have the flag
- * "TRANSRESET".
+ *
+ * We must delete properties that are flagged TRANSRESET.
+ *
+ * @todo r=bird: Would be more efficient if we added a request to the HGCM
+ * service to do this instead of detouring thru VBoxSVC.
+ * (IMachine::SetGuestProperty ends up in VBoxSVC, which in turns calls
+ * back into the VM process and the HGCM service.)
*/
void Console::guestPropertiesHandleVMReset(void)
{
@@ -1745,7 +1796,39 @@ STDMETHODIMP Console::COMGETTER(AttachedPciDevices)(ComSafeArrayOut(IPciDeviceAt
AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
- mBusMgr->listAttachedPciDevices(ComSafeArrayOutArg(aAttachments));
+ if (mBusMgr)
+ mBusMgr->listAttachedPciDevices(ComSafeArrayOutArg(aAttachments));
+ else
+ {
+ com::SafeIfaceArray<IPciDeviceAttachment> result((size_t)0);
+ result.detachTo(ComSafeArrayOutArg(aAttachments));
+ }
+
+ return S_OK;
+}
+
+STDMETHODIMP Console::COMGETTER(UseHostClipboard)(BOOL *aUseHostClipboard)
+{
+ CheckComArgOutPointerValid(aUseHostClipboard);
+
+ AutoCaller autoCaller(this);
+ if (FAILED(autoCaller.rc())) return autoCaller.rc();
+
+ AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ *aUseHostClipboard = mfUseHostClipboard;
+
+ return S_OK;
+}
+
+STDMETHODIMP Console::COMSETTER(UseHostClipboard)(BOOL aUseHostClipboard)
+{
+ AutoCaller autoCaller(this);
+ if (FAILED(autoCaller.rc())) return autoCaller.rc();
+
+ AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ mfUseHostClipboard = aUseHostClipboard;
return S_OK;
}
@@ -1913,14 +1996,15 @@ STDMETHODIMP Console::Reset()
)
return setInvalidMachineStateError();
- /* protect mpVM */
- AutoVMCaller autoVMCaller(this);
- if (FAILED(autoVMCaller.rc())) return autoVMCaller.rc();
+ /* protect mpUVM */
+ SafeVMPtr ptrVM(this);
+ if (!ptrVM.isOk())
+ return ptrVM.rc();
/* leave the lock before a VMR3* call (EMT will call us back)! */
alock.leave();
- int vrc = VMR3Reset(mpVM);
+ int vrc = VMR3Reset(ptrVM);
HRESULT rc = RT_SUCCESS(vrc) ? S_OK :
setError(VBOX_E_VM_ERROR,
@@ -1932,19 +2016,19 @@ STDMETHODIMP Console::Reset()
return rc;
}
-DECLCALLBACK(int) Console::unplugCpu(Console *pThis, unsigned uCpu)
+/*static*/ DECLCALLBACK(int) Console::unplugCpu(Console *pThis, PVM pVM, unsigned uCpu)
{
- LogFlowFunc(("pThis=%p uCpu=%u\n", pThis, uCpu));
+ LogFlowFunc(("pThis=%p pVM=%p uCpu=%u\n", pThis, pVM, uCpu));
AssertReturn(pThis, VERR_INVALID_PARAMETER);
- int vrc = PDMR3DeviceDetach(pThis->mpVM, "acpi", 0, uCpu, 0);
+ int vrc = PDMR3DeviceDetach(pVM, "acpi", 0, uCpu, 0);
Log(("UnplugCpu: rc=%Rrc\n", vrc));
return vrc;
}
-HRESULT Console::doCPURemove(ULONG aCpu)
+HRESULT Console::doCPURemove(ULONG aCpu, PVM pVM)
{
HRESULT rc = S_OK;
@@ -1957,8 +2041,8 @@ HRESULT Console::doCPURemove(ULONG aCpu)
AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
AssertReturn(m_pVMMDev, E_FAIL);
- PPDMIVMMDEVPORT pDevPort = m_pVMMDev->getVMMDevPort();
- AssertReturn(pDevPort, E_FAIL);
+ PPDMIVMMDEVPORT pVmmDevPort = m_pVMMDev->getVMMDevPort();
+ AssertReturn(pVmmDevPort, E_FAIL);
if ( mMachineState != MachineState_Running
&& mMachineState != MachineState_Teleporting
@@ -1966,48 +2050,38 @@ HRESULT Console::doCPURemove(ULONG aCpu)
)
return setInvalidMachineStateError();
- /* protect mpVM */
- AutoVMCaller autoVMCaller(this);
- if (FAILED(autoVMCaller.rc())) return autoVMCaller.rc();
-
/* Check if the CPU is present */
BOOL fCpuAttached;
rc = mMachine->GetCPUStatus(aCpu, &fCpuAttached);
- if (FAILED(rc)) return rc;
-
+ if (FAILED(rc))
+ return rc;
if (!fCpuAttached)
- return setError(E_FAIL,
- tr("CPU %d is not attached"), aCpu);
+ return setError(E_FAIL, tr("CPU %d is not attached"), aCpu);
/* Leave the lock before any EMT/VMMDev call. */
alock.release();
+ bool fLocked = true;
/* Check if the CPU is unlocked */
PPDMIBASE pBase;
- int vrc = PDMR3QueryDeviceLun(mpVM, "acpi", 0, aCpu, &pBase);
- bool fLocked = true;
+ int vrc = PDMR3QueryDeviceLun(pVM, "acpi", 0, aCpu, &pBase);
if (RT_SUCCESS(vrc))
{
- uint32_t idCpuCore, idCpuPackage;
-
- /* Notify the guest if possible. */
- vrc = VMR3GetCpuCoreAndPackageIdFromCpuId(mpVM, aCpu, &idCpuCore, &idCpuPackage);
- AssertRC(vrc);
-
Assert(pBase);
+ PPDMIACPIPORT pApicPort = PDMIBASE_QUERY_INTERFACE(pBase, PDMIACPIPORT);
- PPDMIACPIPORT pPort = PDMIBASE_QUERY_INTERFACE(pBase, PDMIACPIPORT);
-
- vrc = pDevPort->pfnCpuHotUnplug(pDevPort, idCpuCore, idCpuPackage);
+ /* Notify the guest if possible. */
+ uint32_t idCpuCore, idCpuPackage;
+ vrc = VMR3GetCpuCoreAndPackageIdFromCpuId(pVM, aCpu, &idCpuCore, &idCpuPackage); AssertRC(vrc);
+ if (RT_SUCCESS(vrc))
+ vrc = pVmmDevPort->pfnCpuHotUnplug(pVmmDevPort, idCpuCore, idCpuPackage);
if (RT_SUCCESS(vrc))
{
unsigned cTries = 100;
-
do
{
- /* It will take some time until the event is processed in the guest. Wait */
- vrc = pPort ? pPort->pfnGetCpuStatus(pPort, aCpu, &fLocked) : VERR_INVALID_POINTER;
-
+ /* It will take some time until the event is processed in the guest. Wait... */
+ vrc = pApicPort ? pApicPort->pfnGetCpuStatus(pApicPort, aCpu, &fLocked) : VERR_INVALID_POINTER;
if (RT_SUCCESS(vrc) && !fLocked)
break;
@@ -2018,7 +2092,7 @@ HRESULT Console::doCPURemove(ULONG aCpu)
else if (vrc == VERR_CPU_HOTPLUG_NOT_MONITORED_BY_GUEST)
{
/* Query one time. It is possible that the user ejected the CPU. */
- vrc = pPort ? pPort->pfnGetCpuStatus(pPort, aCpu, &fLocked) : VERR_INVALID_POINTER;
+ vrc = pApicPort ? pApicPort->pfnGetCpuStatus(pApicPort, aCpu, &fLocked) : VERR_INVALID_POINTER;
}
}
@@ -2030,10 +2104,9 @@ HRESULT Console::doCPURemove(ULONG aCpu)
* using VMR3ReqCall.
*/
PVMREQ pReq;
- vrc = VMR3ReqCall(mpVM, 0, &pReq, 0 /* no wait! */, VMREQFLAGS_VBOX_STATUS,
- (PFNRT)Console::unplugCpu, 2,
- this, aCpu);
-
+ vrc = VMR3ReqCall(pVM, 0, &pReq, 0 /* no wait! */, VMREQFLAGS_VBOX_STATUS,
+ (PFNRT)Console::unplugCpu, 3,
+ this, pVM, aCpu);
if (vrc == VERR_TIMEOUT || RT_SUCCESS(vrc))
{
vrc = VMR3ReqWait(pReq, RT_INDEFINITE_WAIT);
@@ -2046,7 +2119,7 @@ HRESULT Console::doCPURemove(ULONG aCpu)
if (RT_SUCCESS(vrc))
{
/* Detach it from the VM */
- vrc = VMR3HotUnplugCpu(mpVM, aCpu);
+ vrc = VMR3HotUnplugCpu(pVM, aCpu);
AssertRC(vrc);
}
else
@@ -2062,16 +2135,16 @@ HRESULT Console::doCPURemove(ULONG aCpu)
return rc;
}
-DECLCALLBACK(int) Console::plugCpu(Console *pThis, unsigned uCpu)
+/*static*/ DECLCALLBACK(int) Console::plugCpu(Console *pThis, PVM pVM, unsigned uCpu)
{
LogFlowFunc(("pThis=%p uCpu=%u\n", pThis, uCpu));
AssertReturn(pThis, VERR_INVALID_PARAMETER);
- int rc = VMR3HotPlugCpu(pThis->mpVM, uCpu);
+ int rc = VMR3HotPlugCpu(pVM, uCpu);
AssertRC(rc);
- PCFGMNODE pInst = CFGMR3GetChild(CFGMR3GetRoot(pThis->mpVM), "Devices/acpi/0/");
+ PCFGMNODE pInst = CFGMR3GetChild(CFGMR3GetRoot(pVM), "Devices/acpi/0/");
AssertRelease(pInst);
/* nuke anything which might have been left behind. */
CFGMR3RemoveNode(CFGMR3GetChildF(pInst, "LUN#%d", uCpu));
@@ -2088,7 +2161,7 @@ DECLCALLBACK(int) Console::plugCpu(Console *pThis, unsigned uCpu)
* Attach the driver.
*/
PPDMIBASE pBase;
- rc = PDMR3DeviceAttach(pThis->mpVM, "acpi", 0, uCpu, 0, &pBase); RC_CHECK();
+ rc = PDMR3DeviceAttach(pVM, "acpi", 0, uCpu, 0, &pBase); RC_CHECK();
Log(("PlugCpu: rc=%Rrc\n", rc));
@@ -2099,7 +2172,7 @@ DECLCALLBACK(int) Console::plugCpu(Console *pThis, unsigned uCpu)
return VINF_SUCCESS;
}
-HRESULT Console::doCPUAdd(ULONG aCpu)
+HRESULT Console::doCPUAdd(ULONG aCpu, PVM pVM)
{
HRESULT rc = S_OK;
@@ -2122,10 +2195,6 @@ HRESULT Console::doCPUAdd(ULONG aCpu)
PPDMIVMMDEVPORT pDevPort = m_pVMMDev->getVMMDevPort();
AssertReturn(pDevPort, E_FAIL);
- /* protect mpVM */
- AutoVMCaller autoVMCaller(this);
- if (FAILED(autoVMCaller.rc())) return autoVMCaller.rc();
-
/* Check if the CPU is present */
BOOL fCpuAttached;
rc = mMachine->GetCPUStatus(aCpu, &fCpuAttached);
@@ -2141,9 +2210,9 @@ HRESULT Console::doCPUAdd(ULONG aCpu)
* here to make requests from under the lock in order to serialize them.
*/
PVMREQ pReq;
- int vrc = VMR3ReqCall(mpVM, 0, &pReq, 0 /* no wait! */, VMREQFLAGS_VBOX_STATUS,
- (PFNRT)Console::plugCpu, 2,
- this, aCpu);
+ int vrc = VMR3ReqCall(pVM, 0, &pReq, 0 /* no wait! */, VMREQFLAGS_VBOX_STATUS,
+ (PFNRT)Console::plugCpu, 3,
+ this, pVM, aCpu);
/* leave the lock before a VMR3* call (EMT will call us back)! */
alock.release();
@@ -2164,13 +2233,11 @@ HRESULT Console::doCPUAdd(ULONG aCpu)
if (RT_SUCCESS(vrc))
{
- uint32_t idCpuCore, idCpuPackage;
-
/* Notify the guest if possible. */
- vrc = VMR3GetCpuCoreAndPackageIdFromCpuId(mpVM, aCpu, &idCpuCore, &idCpuPackage);
- AssertRC(vrc);
-
- vrc = pDevPort->pfnCpuHotPlug(pDevPort, idCpuCore, idCpuPackage);
+ uint32_t idCpuCore, idCpuPackage;
+ vrc = VMR3GetCpuCoreAndPackageIdFromCpuId(pVM, aCpu, &idCpuCore, &idCpuPackage); AssertRC(vrc);
+ if (RT_SUCCESS(vrc))
+ vrc = pDevPort->pfnCpuHotPlug(pDevPort, idCpuCore, idCpuPackage);
/** @todo warning if the guest doesn't support it */
}
@@ -2204,16 +2271,17 @@ STDMETHODIMP Console::Pause()
return setInvalidMachineStateError();
}
- /* protect mpVM */
- AutoVMCaller autoVMCaller(this);
- if (FAILED(autoVMCaller.rc())) return autoVMCaller.rc();
+ /* get the VM handle. */
+ SafeVMPtr ptrVM(this);
+ if (!ptrVM.isOk())
+ return ptrVM.rc();
LogFlowThisFunc(("Sending PAUSE request...\n"));
/* leave the lock before a VMR3* call (EMT will call us back)! */
alock.leave();
- int vrc = VMR3Suspend(mpVM);
+ int vrc = VMR3Suspend(ptrVM);
HRESULT hrc = S_OK;
if (RT_FAILURE(vrc))
@@ -2238,9 +2306,10 @@ STDMETHODIMP Console::Resume()
tr("Cannot resume the machine as it is not paused (machine state: %s)"),
Global::stringifyMachineState(mMachineState));
- /* protect mpVM */
- AutoVMCaller autoVMCaller(this);
- if (FAILED(autoVMCaller.rc())) return autoVMCaller.rc();
+ /* get the VM handle. */
+ SafeVMPtr ptrVM(this);
+ if (!ptrVM.isOk())
+ return ptrVM.rc();
LogFlowThisFunc(("Sending RESUME request...\n"));
@@ -2248,16 +2317,16 @@ STDMETHODIMP Console::Resume()
alock.leave();
#ifdef VBOX_WITH_EXTPACK
- int vrc = mptrExtPackManager->callAllVmPowerOnHooks(this, mpVM); /** @todo called a few times too many... */
+ 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(mpVM) == VMSTATE_CREATED)
- vrc = VMR3PowerOn(mpVM); /* (PowerUpPaused) */
+ if (VMR3GetState(ptrVM) == VMSTATE_CREATED)
+ vrc = VMR3PowerOn(ptrVM); /* (PowerUpPaused) */
else
- vrc = VMR3Resume(mpVM);
+ vrc = VMR3Resume(ptrVM);
}
HRESULT rc = RT_SUCCESS(vrc) ? S_OK :
@@ -2285,17 +2354,23 @@ STDMETHODIMP Console::PowerButton()
)
return setInvalidMachineStateError();
- /* protect mpVM */
- AutoVMCaller autoVMCaller(this);
- if (FAILED(autoVMCaller.rc())) return autoVMCaller.rc();
+ /* get the VM handle. */
+ SafeVMPtr ptrVM(this);
+ if (!ptrVM.isOk())
+ return ptrVM.rc();
+/** @todo leave the console lock? */
+ /* get the acpi device interface and press the button. */
PPDMIBASE pBase;
- int vrc = PDMR3QueryDeviceLun(mpVM, "acpi", 0, 0, &pBase);
+ int vrc = PDMR3QueryDeviceLun(ptrVM, "acpi", 0, 0, &pBase);
if (RT_SUCCESS(vrc))
{
Assert(pBase);
PPDMIACPIPORT pPort = PDMIBASE_QUERY_INTERFACE(pBase, PDMIACPIPORT);
- vrc = pPort ? pPort->pfnPowerButtonPress(pPort) : VERR_INVALID_POINTER;
+ if (pPort)
+ vrc = pPort->pfnPowerButtonPress(pPort);
+ else
+ vrc = VERR_PDM_MISSING_INTERFACE;
}
HRESULT rc = RT_SUCCESS(vrc) ? S_OK :
@@ -2326,18 +2401,28 @@ STDMETHODIMP Console::GetPowerButtonHandled(BOOL *aHandled)
)
return setInvalidMachineStateError();
- /* protect mpVM */
- AutoVMCaller autoVMCaller(this);
- if (FAILED(autoVMCaller.rc())) return autoVMCaller.rc();
+ /* get the VM handle. */
+ SafeVMPtr ptrVM(this);
+ if (!ptrVM.isOk())
+ return ptrVM.rc();
+/** @todo leave the console lock? */
+ /* get the acpi device interface and check if the button press was handled. */
PPDMIBASE pBase;
- int vrc = PDMR3QueryDeviceLun(mpVM, "acpi", 0, 0, &pBase);
- bool handled = false;
+ int vrc = PDMR3QueryDeviceLun(ptrVM, "acpi", 0, 0, &pBase);
if (RT_SUCCESS(vrc))
{
Assert(pBase);
PPDMIACPIPORT pPort = PDMIBASE_QUERY_INTERFACE(pBase, PDMIACPIPORT);
- vrc = pPort ? pPort->pfnGetPowerButtonHandled(pPort, &handled) : VERR_INVALID_POINTER;
+ if (pPort)
+ {
+ bool fHandled = false;
+ vrc = pPort->pfnGetPowerButtonHandled(pPort, &fHandled);
+ if (RT_SUCCESS(vrc))
+ *aHandled = fHandled;
+ }
+ else
+ vrc = VERR_PDM_MISSING_INTERFACE;
}
HRESULT rc = RT_SUCCESS(vrc) ? S_OK :
@@ -2345,8 +2430,6 @@ STDMETHODIMP Console::GetPowerButtonHandled(BOOL *aHandled)
tr("Checking if the ACPI Power Button event was handled by the guest OS failed (%Rrc)"),
vrc);
- *aHandled = handled;
-
LogFlowThisFunc(("rc=%Rhrc\n", rc));
LogFlowThisFuncLeave();
return rc;
@@ -2372,22 +2455,31 @@ STDMETHODIMP Console::GetGuestEnteredACPIMode(BOOL *aEntered)
tr("Invalid machine state %s when checking if the guest entered the ACPI mode)"),
Global::stringifyMachineState(mMachineState));
- /* protect mpVM */
- AutoVMCaller autoVMCaller(this);
- if (FAILED(autoVMCaller.rc())) return autoVMCaller.rc();
+ /* get the VM handle. */
+ SafeVMPtr ptrVM(this);
+ if (!ptrVM.isOk())
+ return ptrVM.rc();
+/** @todo leave the console lock? */
+
+ /* get the acpi device interface and query the information. */
PPDMIBASE pBase;
- int vrc = PDMR3QueryDeviceLun(mpVM, "acpi", 0, 0, &pBase);
- bool entered = false;
+ int vrc = PDMR3QueryDeviceLun(ptrVM, "acpi", 0, 0, &pBase);
if (RT_SUCCESS(vrc))
{
Assert(pBase);
PPDMIACPIPORT pPort = PDMIBASE_QUERY_INTERFACE(pBase, PDMIACPIPORT);
- vrc = pPort ? pPort->pfnGetGuestEnteredACPIMode(pPort, &entered) : VERR_INVALID_POINTER;
+ if (pPort)
+ {
+ bool fEntered = false;
+ vrc = pPort->pfnGetGuestEnteredACPIMode(pPort, &fEntered);
+ if (RT_SUCCESS(vrc))
+ *aEntered = fEntered;
+ }
+ else
+ vrc = VERR_PDM_MISSING_INTERFACE;
}
- *aEntered = RT_SUCCESS(vrc) ? entered : false;
-
LogFlowThisFuncLeave();
return S_OK;
}
@@ -2404,17 +2496,24 @@ STDMETHODIMP Console::SleepButton()
if (mMachineState != MachineState_Running) /** @todo Live Migration: ??? */
return setInvalidMachineStateError();
- /* protect mpVM */
- AutoVMCaller autoVMCaller(this);
- if (FAILED(autoVMCaller.rc())) return autoVMCaller.rc();
+ /* get the VM handle. */
+ SafeVMPtr ptrVM(this);
+ if (!ptrVM.isOk())
+ return ptrVM.rc();
+
+/** @todo leave the console lock? */
+ /* get the acpi device interface and press the sleep button. */
PPDMIBASE pBase;
- int vrc = PDMR3QueryDeviceLun(mpVM, "acpi", 0, 0, &pBase);
+ int vrc = PDMR3QueryDeviceLun(ptrVM, "acpi", 0, 0, &pBase);
if (RT_SUCCESS(vrc))
{
Assert(pBase);
PPDMIACPIPORT pPort = PDMIBASE_QUERY_INTERFACE(pBase, PDMIACPIPORT);
- vrc = pPort ? pPort->pfnSleepButtonPress(pPort) : VERR_INVALID_POINTER;
+ if (pPort)
+ vrc = pPort->pfnSleepButtonPress(pPort);
+ else
+ vrc = VERR_PDM_MISSING_INTERFACE;
}
HRESULT rc = RT_SUCCESS(vrc) ? S_OK :
@@ -2453,7 +2552,8 @@ STDMETHODIMP Console::SaveState(IProgress **aProgress)
if (mMachineState == MachineState_Running)
{
HRESULT rc = Pause();
- if (FAILED(rc)) return rc;
+ if (FAILED(rc))
+ return rc;
}
HRESULT rc = S_OK;
@@ -2472,7 +2572,8 @@ STDMETHODIMP Console::SaveState(IProgress **aProgress)
*/
rc = mControl->BeginSavingState(pProgress.asOutParam(),
stateFilePath.asOutParam());
- if (FAILED(rc)) break;
+ if (FAILED(rc))
+ break;
fBeganSavingState = true;
@@ -2513,7 +2614,7 @@ STDMETHODIMP Console::SaveState(IProgress **aProgress)
}
/* create a thread to wait until the VM state is saved */
- int vrc = RTThreadCreate(NULL, Console::saveStateThread, (void *) task.get(),
+ int vrc = RTThreadCreate(NULL, Console::saveStateThread, (void *)task.get(),
0, RTTHREADTYPE_MAIN_WORKER, 0, "VMSave");
if (RT_FAILURE(vrc))
{
@@ -2526,8 +2627,7 @@ STDMETHODIMP Console::SaveState(IProgress **aProgress)
/* return the progress to the caller */
pProgress.queryInterfaceTo(aProgress);
- }
- while (0);
+ } while (0);
if (FAILED(rc) && !fTaskCreationFailed)
{
@@ -2699,13 +2799,14 @@ STDMETHODIMP Console::AttachUSBDevice(IN_BSTR aId)
tr("Cannot attach a USB device to the machine which is not running or paused (machine state: %s)"),
Global::stringifyMachineState(mMachineState));
- /* protect mpVM */
- AutoVMCaller autoVMCaller(this);
- if (FAILED(autoVMCaller.rc())) return autoVMCaller.rc();
+ /* Get the VM handle. */
+ SafeVMPtr ptrVM(this);
+ if (!ptrVM.isOk())
+ return ptrVM.rc();
/* Don't proceed unless we've found the usb controller. */
PPDMIBASE pBase = NULL;
- int vrc = PDMR3QueryLun(mpVM, "usb-ohci", 0, 0, &pBase);
+ int vrc = PDMR3QueryLun(ptrVM, "usb-ohci", 0, 0, &pBase);
if (RT_FAILURE(vrc))
return setError(VBOX_E_PDM_ERROR,
tr("The virtual machine does not have a USB controller"));
@@ -2715,10 +2816,7 @@ STDMETHODIMP Console::AttachUSBDevice(IN_BSTR aId)
alock.leave();
/* Request the device capture */
- HRESULT rc = mControl->CaptureUSBDevice(aId);
- if (FAILED(rc)) return rc;
-
- return rc;
+ return mControl->CaptureUSBDevice(aId);
#else /* !VBOX_WITH_USB */
return setError(VBOX_E_PDM_ERROR,
@@ -2903,29 +3001,27 @@ Console::CreateSharedFolder(IN_BSTR aName, IN_BSTR aHostPath, BOOL aWritable, BO
true /* fFailOnError */);
if (FAILED(rc)) return rc;
- /* protect mpVM (if not NULL) */
- AutoVMCallerQuietWeak autoVMCaller(this);
-
- if ( mpVM
- && autoVMCaller.isOk()
+ /* If the VM is online and supports shared folders, share this folder
+ * under the specified name. (Ignore any failure to obtain the VM handle.) */
+ SafeVMPtrQuiet ptrVM(this);
+ if ( ptrVM.isOk()
&& m_pVMMDev
&& m_pVMMDev->isShFlActive()
)
{
- /* If the VM is online and supports shared folders, share this folder
- * under the specified name. */
-
/* first, remove the machine or the global folder if there is any */
SharedFolderDataMap::const_iterator it;
if (findOtherSharedFolder(aName, it))
{
rc = removeSharedFolder(aName);
- if (FAILED(rc)) return rc;
+ if (FAILED(rc))
+ return rc;
}
/* second, create the given folder */
rc = createSharedFolder(aName, SharedFolderData(aHostPath, aWritable, aAutoMount));
- if (FAILED(rc)) return rc;
+ if (FAILED(rc))
+ return rc;
}
m_mapSharedFolders.insert(std::make_pair(aName, pSharedFolder));
@@ -2969,11 +3065,9 @@ STDMETHODIMP Console::RemoveSharedFolder(IN_BSTR aName)
HRESULT rc = findSharedFolder(aName, pSharedFolder, true /* aSetError */);
if (FAILED(rc)) return rc;
- /* protect mpVM (if not NULL) */
- AutoVMCallerQuietWeak autoVMCaller(this);
-
- if ( mpVM
- && autoVMCaller.isOk()
+ /* protect the VM handle (if not NULL) */
+ SafeVMPtrQuiet ptrVM(this);
+ if ( ptrVM.isOk()
&& m_pVMMDev
&& m_pVMMDev->isShFlActive()
)
@@ -3061,16 +3155,13 @@ STDMETHODIMP Console::TakeSnapshot(IN_BSTR aName,
}
// b) one extra sub-operations for online snapshots OR offline snapshots that have a saved state (needs to be copied)
- bool fTakingSnapshotOnline = ((mMachineState == MachineState_Running) || (mMachineState == MachineState_Paused));
+ bool const fTakingSnapshotOnline = Global::IsOnline(mMachineState);
LogFlowFunc(("fTakingSnapshotOnline = %d, mMachineState = %d\n", fTakingSnapshotOnline, mMachineState));
- if ( fTakingSnapshotOnline
- || mMachineState == MachineState_Saved
- )
+ if (fTakingSnapshotOnline)
{
++cOperations;
-
ulTotalOperationsWeight += ulMemSize;
}
@@ -3115,7 +3206,7 @@ STDMETHODIMP Console::TakeSnapshot(IN_BSTR aName,
int vrc = RTThreadCreate(NULL,
Console::fntTakeSnapshotWorker,
- (void*)pTask,
+ (void *)pTask,
0,
RTTHREADTYPE_MAIN_WORKER,
0,
@@ -3154,9 +3245,55 @@ STDMETHODIMP Console::DeleteSnapshot(IN_BSTR aId, IProgress **aProgress)
tr("Cannot delete a snapshot of the machine while it is changing the state (machine state: %s)"),
Global::stringifyMachineState(mMachineState));
+ MachineState_T machineState = MachineState_Null;
+ HRESULT rc = mControl->DeleteSnapshot(this, aId, aId, FALSE /* fDeleteAllChildren */, &machineState, aProgress);
+ if (FAILED(rc)) return rc;
+
+ setMachineStateLocally(machineState);
+ return S_OK;
+}
+
+STDMETHODIMP Console::DeleteSnapshotAndAllChildren(IN_BSTR aId, IProgress **aProgress)
+{
+ CheckComArgExpr(aId, Guid(aId).isEmpty() == false);
+ CheckComArgOutPointerValid(aProgress);
+
+ AutoCaller autoCaller(this);
+ if (FAILED(autoCaller.rc())) return autoCaller.rc();
+
+ AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ if (Global::IsTransient(mMachineState))
+ return setError(VBOX_E_INVALID_VM_STATE,
+ tr("Cannot delete a snapshot of the machine while it is changing the state (machine state: %s)"),
+ Global::stringifyMachineState(mMachineState));
+
+ MachineState_T machineState = MachineState_Null;
+ HRESULT rc = mControl->DeleteSnapshot(this, aId, aId, TRUE /* fDeleteAllChildren */, &machineState, aProgress);
+ if (FAILED(rc)) return rc;
+
+ setMachineStateLocally(machineState);
+ return S_OK;
+}
+
+STDMETHODIMP Console::DeleteSnapshotRange(IN_BSTR aStartId, IN_BSTR aEndId, IProgress **aProgress)
+{
+ CheckComArgExpr(aStartId, Guid(aStartId).isEmpty() == false);
+ CheckComArgExpr(aEndId, Guid(aEndId).isEmpty() == false);
+ CheckComArgOutPointerValid(aProgress);
+
+ AutoCaller autoCaller(this);
+ if (FAILED(autoCaller.rc())) return autoCaller.rc();
+
+ AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ if (Global::IsTransient(mMachineState))
+ return setError(VBOX_E_INVALID_VM_STATE,
+ tr("Cannot delete a snapshot of the machine while it is changing the state (machine state: %s)"),
+ Global::stringifyMachineState(mMachineState));
MachineState_T machineState = MachineState_Null;
- HRESULT rc = mControl->DeleteSnapshot(this, aId, &machineState, aProgress);
+ HRESULT rc = mControl->DeleteSnapshot(this, aStartId, aEndId, FALSE /* fDeleteAllChildren */, &machineState, aProgress);
if (FAILED(rc)) return rc;
setMachineStateLocally(machineState);
@@ -3296,10 +3433,11 @@ HRESULT Console::convertBusPortDeviceToLun(StorageBus_T enmBus, LONG port, LONG
*
* @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.
*
* @note Locks this object for writing.
*/
-HRESULT Console::doMediumChange(IMediumAttachment *aMediumAttachment, bool fForce)
+HRESULT Console::doMediumChange(IMediumAttachment *aMediumAttachment, bool fForce, PVM pVM)
{
AutoCaller autoCaller(this);
AssertComRCReturnRC(autoCaller.rc());
@@ -3357,24 +3495,21 @@ HRESULT Console::doMediumChange(IMediumAttachment *aMediumAttachment, bool fForc
rc = pStorageController->COMGETTER(UseHostIOCache)(&fUseHostIOCache);
AssertComRC(rc);
- /* protect mpVM */
- AutoVMCaller autoVMCaller(this);
- AssertComRCReturnRC(autoVMCaller.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(mpVM,
+ int vrc = VMR3ReqCall(pVM,
VMCPUID_ANY,
-&pReq,
+ &pReq,
0 /* no wait! */,
VMREQFLAGS_VBOX_STATUS,
(PFNRT)Console::changeRemovableMedium,
- 7,
+ 8,
this,
+ pVM,
pszDevice,
uInstance,
enmBus,
@@ -3400,7 +3535,7 @@ HRESULT Console::doMediumChange(IMediumAttachment *aMediumAttachment, bool fForc
return S_OK;
}
- if (!pMedium)
+ if (pMedium)
return setError(E_FAIL,
tr("Could not mount the media/drive '%ls' (%Rrc)"),
mediumLocation.raw(), vrc);
@@ -3416,6 +3551,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 pcszDevice The PDM device name.
* @param uInstance The PDM device instance.
* @param uLun The PDM LUN number of the drive.
@@ -3430,6 +3566,7 @@ HRESULT Console::doMediumChange(IMediumAttachment *aMediumAttachment, bool fForc
* @thread EMT
*/
DECLCALLBACK(int) Console::changeRemovableMedium(Console *pConsole,
+ PVM pVM,
const char *pcszDevice,
unsigned uInstance,
StorageBus_T enmBus,
@@ -3445,8 +3582,6 @@ DECLCALLBACK(int) Console::changeRemovableMedium(Console *pConsole,
AutoCaller autoCaller(pConsole);
AssertComRCReturn(autoCaller.rc(), VERR_ACCESS_DENIED);
- PVM pVM = pConsole->mpVM;
-
/*
* Suspend the VM first.
*
@@ -3511,6 +3646,7 @@ DECLCALLBACK(int) Console::changeRemovableMedium(Console *pConsole,
NULL /* phrc */,
true /* fAttachDetach */,
fForce /* fForceUnmount */,
+ false /* fHotplug */,
pVM,
NULL /* paLedDevType */);
/** @todo this dumps everything attached to this device instance, which
@@ -3548,6 +3684,504 @@ 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.
+ *
+ * @note Locks this object for writing.
+ */
+HRESULT Console::doStorageDeviceAttach(IMediumAttachment *aMediumAttachment, PVM pVM)
+{
+ AutoCaller autoCaller(this);
+ AssertComRCReturnRC(autoCaller.rc());
+
+ /* We will need to release the write lock before calling EMT */
+ AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ HRESULT rc = S_OK;
+ const char *pszDevice = NULL;
+
+ SafeIfaceArray<IStorageController> ctrls;
+ rc = mMachine->COMGETTER(StorageControllers)(ComSafeArrayAsOutParam(ctrls));
+ AssertComRC(rc);
+ IMedium *pMedium;
+ rc = aMediumAttachment->COMGETTER(Medium)(&pMedium);
+ AssertComRC(rc);
+ Bstr mediumLocation;
+ if (pMedium)
+ {
+ rc = pMedium->COMGETTER(Location)(mediumLocation.asOutParam());
+ AssertComRC(rc);
+ }
+
+ Bstr attCtrlName;
+ rc = aMediumAttachment->COMGETTER(Controller)(attCtrlName.asOutParam());
+ AssertComRC(rc);
+ ComPtr<IStorageController> pStorageController;
+ for (size_t i = 0; i < ctrls.size(); ++i)
+ {
+ Bstr ctrlName;
+ rc = ctrls[i]->COMGETTER(Name)(ctrlName.asOutParam());
+ AssertComRC(rc);
+ if (attCtrlName == ctrlName)
+ {
+ pStorageController = ctrls[i];
+ break;
+ }
+ }
+ if (pStorageController.isNull())
+ return setError(E_FAIL,
+ tr("Could not find storage controller '%ls'"), attCtrlName.raw());
+
+ StorageControllerType_T enmCtrlType;
+ rc = pStorageController->COMGETTER(ControllerType)(&enmCtrlType);
+ AssertComRC(rc);
+ pszDevice = convertControllerTypeToDev(enmCtrlType);
+
+ StorageBus_T enmBus;
+ rc = pStorageController->COMGETTER(Bus)(&enmBus);
+ AssertComRC(rc);
+ ULONG uInstance;
+ rc = pStorageController->COMGETTER(Instance)(&uInstance);
+ AssertComRC(rc);
+ BOOL fUseHostIOCache;
+ rc = pStorageController->COMGETTER(UseHostIOCache)(&fUseHostIOCache);
+ AssertComRC(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);
+
+ /* leave the lock before waiting for a result (EMT will call us back!) */
+ alock.leave();
+
+ if (vrc == VERR_TIMEOUT || RT_SUCCESS(vrc))
+ {
+ vrc = VMR3ReqWait(pReq, RT_INDEFINITE_WAIT);
+ AssertRC(vrc);
+ if (RT_SUCCESS(vrc))
+ vrc = pReq->iStatus;
+ }
+ VMR3ReqFree(pReq);
+
+ if (RT_SUCCESS(vrc))
+ {
+ LogFlowThisFunc(("Returns S_OK\n"));
+ return S_OK;
+ }
+
+ if (!pMedium)
+ return setError(E_FAIL,
+ tr("Could not mount the media/drive '%ls' (%Rrc)"),
+ mediumLocation.raw(), vrc);
+
+ return setError(E_FAIL,
+ tr("Could not unmount the currently mounted media/drive (%Rrc)"),
+ vrc);
+}
+
+
+/**
+ * Performs the storage attach operation in EMT.
+ *
+ * @returns VBox status code.
+ *
+ * @param pThis Pointer to the Console object.
+ * @param pVM The VM handle.
+ * @param pcszDevice The PDM device name.
+ * @param uInstance The PDM device instance.
+ *
+ * @thread EMT
+ */
+DECLCALLBACK(int) Console::attachStorageDevice(Console *pConsole,
+ PVM pVM,
+ const char *pcszDevice,
+ unsigned uInstance,
+ StorageBus_T enmBus,
+ bool fUseHostIOCache,
+ IMediumAttachment *aMediumAtt)
+{
+ LogFlowFunc(("pConsole=%p uInstance=%u pszDevice=%p:{%s} enmBus=%u, aMediumAtt=%p\n",
+ pConsole, uInstance, pcszDevice, pcszDevice, enmBus, aMediumAtt));
+
+ AssertReturn(pConsole, VERR_INVALID_PARAMETER);
+
+ AutoCaller autoCaller(pConsole);
+ 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.
+ */
+ 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);
+ }
+
+ /* Determine the base path for the device instance. */
+ PCFGMNODE pCtlInst;
+ pCtlInst = CFGMR3GetChildF(CFGMR3GetRoot(pVM), "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;
+}
+
+/**
+ * Attach a new storage device to the VM.
+ *
+ * @param aMediumAttachment The medium attachment which is added.
+ * @param pVM Safe VM handle.
+ *
+ * @note Locks this object for writing.
+ */
+HRESULT Console::doStorageDeviceDetach(IMediumAttachment *aMediumAttachment, PVM pVM)
+{
+ AutoCaller autoCaller(this);
+ AssertComRCReturnRC(autoCaller.rc());
+
+ /* We will need to release the write lock before calling EMT */
+ AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ HRESULT rc = S_OK;
+ const char *pszDevice = NULL;
+
+ SafeIfaceArray<IStorageController> ctrls;
+ rc = mMachine->COMGETTER(StorageControllers)(ComSafeArrayAsOutParam(ctrls));
+ AssertComRC(rc);
+ IMedium *pMedium;
+ rc = aMediumAttachment->COMGETTER(Medium)(&pMedium);
+ AssertComRC(rc);
+ Bstr mediumLocation;
+ if (pMedium)
+ {
+ rc = pMedium->COMGETTER(Location)(mediumLocation.asOutParam());
+ AssertComRC(rc);
+ }
+
+ Bstr attCtrlName;
+ rc = aMediumAttachment->COMGETTER(Controller)(attCtrlName.asOutParam());
+ AssertComRC(rc);
+ ComPtr<IStorageController> pStorageController;
+ for (size_t i = 0; i < ctrls.size(); ++i)
+ {
+ Bstr ctrlName;
+ rc = ctrls[i]->COMGETTER(Name)(ctrlName.asOutParam());
+ AssertComRC(rc);
+ if (attCtrlName == ctrlName)
+ {
+ pStorageController = ctrls[i];
+ break;
+ }
+ }
+ if (pStorageController.isNull())
+ return setError(E_FAIL,
+ tr("Could not find storage controller '%ls'"), attCtrlName.raw());
+
+ StorageControllerType_T enmCtrlType;
+ rc = pStorageController->COMGETTER(ControllerType)(&enmCtrlType);
+ AssertComRC(rc);
+ pszDevice = convertControllerTypeToDev(enmCtrlType);
+
+ StorageBus_T enmBus;
+ rc = pStorageController->COMGETTER(Bus)(&enmBus);
+ AssertComRC(rc);
+ ULONG uInstance;
+ rc = pStorageController->COMGETTER(Instance)(&uInstance);
+ AssertComRC(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);
+
+ /* leave the lock before waiting for a result (EMT will call us back!) */
+ alock.leave();
+
+ if (vrc == VERR_TIMEOUT || RT_SUCCESS(vrc))
+ {
+ vrc = VMR3ReqWait(pReq, RT_INDEFINITE_WAIT);
+ AssertRC(vrc);
+ if (RT_SUCCESS(vrc))
+ vrc = pReq->iStatus;
+ }
+ VMR3ReqFree(pReq);
+
+ if (RT_SUCCESS(vrc))
+ {
+ LogFlowThisFunc(("Returns S_OK\n"));
+ return S_OK;
+ }
+
+ if (!pMedium)
+ return setError(E_FAIL,
+ tr("Could not mount the media/drive '%ls' (%Rrc)"),
+ mediumLocation.raw(), vrc);
+
+ return setError(E_FAIL,
+ tr("Could not unmount the currently mounted media/drive (%Rrc)"),
+ vrc);
+}
+
+/**
+ * Performs the storage detach operation in EMT.
+ *
+ * @returns VBox status code.
+ *
+ * @param pThis Pointer to the Console object.
+ * @param pVM The VM handle.
+ * @param pcszDevice The PDM device name.
+ * @param uInstance The PDM device instance.
+ *
+ * @thread EMT
+ */
+DECLCALLBACK(int) Console::detachStorageDevice(Console *pConsole,
+ PVM pVM,
+ const char *pcszDevice,
+ unsigned uInstance,
+ StorageBus_T enmBus,
+ IMediumAttachment *pMediumAtt)
+{
+ LogFlowFunc(("pConsole=%p uInstance=%u pszDevice=%p:{%s} enmBus=%u, pMediumAtt=%p\n",
+ pConsole, uInstance, pcszDevice, pcszDevice, enmBus, pMediumAtt));
+
+ AssertReturn(pConsole, VERR_INVALID_PARAMETER);
+
+ AutoCaller autoCaller(pConsole);
+ 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.
+ */
+ 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);
+ }
+
+ /* Determine the base path for the device instance. */
+ PCFGMNODE pCtlInst;
+ pCtlInst = CFGMR3GetChildF(CFGMR3GetRoot(pVM), "Devices/%s/%u/", pcszDevice, uInstance);
+ AssertReturn(pCtlInst, VERR_INTERNAL_ERROR);
+
+#define H() AssertMsgReturn(!FAILED(hrc), ("hrc=%Rhrc\n", hrc), VERR_GENERAL_FAILURE)
+
+ HRESULT hrc;
+ int rc = VINF_SUCCESS;
+ int rcRet = VINF_SUCCESS;
+ unsigned uLUN;
+ LONG lDev;
+ LONG lPort;
+ DeviceType_T lType;
+ PCFGMNODE pLunL0 = NULL;
+ PCFGMNODE pCfg = NULL;
+
+ hrc = pMediumAtt->COMGETTER(Device)(&lDev); H();
+ hrc = pMediumAtt->COMGETTER(Port)(&lPort); H();
+ hrc = pMediumAtt->COMGETTER(Type)(&lType); H();
+ hrc = Console::convertBusPortDeviceToLun(enmBus, lPort, lDev, uLUN); H();
+
+#undef H
+
+ /* First check if the LUN really exists. */
+ pLunL0 = CFGMR3GetChildF(pCtlInst, "LUN#%u", uLUN);
+ if (pLunL0)
+ {
+ rc = PDMR3DeviceDetach(pVM, pcszDevice, uInstance, uLUN, 0);
+ 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);
+
+ }
+ else
+ AssertFailedReturn(VERR_INTERNAL_ERROR);
+
+ 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;
+}
+
+/**
* Called by IInternalSessionControl::OnNetworkAdapterChange().
*
* @note Locks this object for writing.
@@ -3564,12 +4198,9 @@ HRESULT Console::onNetworkAdapterChange(INetworkAdapter *aNetworkAdapter, BOOL c
HRESULT rc = S_OK;
/* don't trigger network change if the VM isn't running */
- if (mpVM)
+ SafeVMPtrQuiet ptrVM(this);
+ if (ptrVM.isOk())
{
- /* protect mpVM */
- AutoVMCaller autoVMCaller(this);
- if (FAILED(autoVMCaller.rc())) return autoVMCaller.rc();
-
/* Get the properties we need from the adapter */
BOOL fCableConnected, fTraceEnabled;
rc = aNetworkAdapter->COMGETTER(CableConnected)(&fCableConnected);
@@ -3595,7 +4226,7 @@ HRESULT Console::onNetworkAdapterChange(INetworkAdapter *aNetworkAdapter, BOOL c
AssertComRC(rc);
const char *pszAdapterName = networkAdapterTypeToName(adapterType);
PPDMIBASE pBase;
- int vrc = PDMR3QueryDeviceLun(mpVM, pszAdapterName, ulInstance, 0, &pBase);
+ int vrc = PDMR3QueryDeviceLun(ptrVM, pszAdapterName, ulInstance, 0, &pBase);
if (RT_SUCCESS(vrc))
{
Assert(pBase);
@@ -3612,7 +4243,7 @@ HRESULT Console::onNetworkAdapterChange(INetworkAdapter *aNetworkAdapter, BOOL c
}
if (RT_SUCCESS(vrc) && changeAdapter)
{
- VMSTATE enmVMState = VMR3GetState(mpVM);
+ VMSTATE enmVMState = VMR3GetState(ptrVM);
if ( enmVMState == VMSTATE_RUNNING /** @todo LiveMigration: Forbid or deal correctly with the _LS variants */
|| enmVMState == VMSTATE_SUSPENDED)
{
@@ -3622,7 +4253,7 @@ HRESULT Console::onNetworkAdapterChange(INetworkAdapter *aNetworkAdapter, BOOL c
ComAssertRC(vrc);
}
- rc = doNetworkAdapterChange(pszAdapterName, ulInstance, 0, aNetworkAdapter);
+ rc = doNetworkAdapterChange(ptrVM, pszAdapterName, ulInstance, 0, aNetworkAdapter);
if (fTraceEnabled && fCableConnected && pINetCfg)
{
@@ -3633,10 +4264,8 @@ HRESULT Console::onNetworkAdapterChange(INetworkAdapter *aNetworkAdapter, BOOL c
}
}
else if (vrc == VERR_PDM_DEVICE_INSTANCE_NOT_FOUND)
- {
return setError(E_FAIL,
tr("The network adapter #%u is not enabled"), ulInstance);
- }
else
ComAssertRC(vrc);
@@ -3644,6 +4273,7 @@ HRESULT Console::onNetworkAdapterChange(INetworkAdapter *aNetworkAdapter, BOOL c
rc = E_FAIL;
}
}
+ ptrVM.release();
}
/* notify console callbacks on success */
@@ -3660,7 +4290,7 @@ HRESULT Console::onNetworkAdapterChange(INetworkAdapter *aNetworkAdapter, BOOL c
* @note Locks this object for writing.
*/
HRESULT Console::onNATRedirectRuleChange(ULONG ulInstance, BOOL aNatRuleRemove,
- NATProtocol_T aProto, IN_BSTR aHostIp, LONG aHostPort, IN_BSTR aGuestIp, LONG aGuestPort)
+ NATProtocol_T aProto, IN_BSTR aHostIp, LONG aHostPort, IN_BSTR aGuestIp, LONG aGuestPort)
{
LogFlowThisFunc(("\n"));
@@ -3670,71 +4300,75 @@ HRESULT Console::onNATRedirectRuleChange(ULONG ulInstance, BOOL aNatRuleRemove,
AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
HRESULT rc = S_OK;
- int vrc = VINF_SUCCESS;
- PPDMINETWORKNATCONFIG pNetNatCfg = NULL;
+
/* don't trigger nat engine change if the VM isn't running */
- if (mpVM)
+ SafeVMPtrQuiet ptrVM(this);
+ if (ptrVM.isOk())
{
- /* protect mpVM */
- AutoVMCaller autoVMCaller(this);
- if (FAILED(autoVMCaller.rc())) return autoVMCaller.rc();
-
- ComPtr<INetworkAdapter> pNetworkAdapter;
- rc = machine()->GetNetworkAdapter(ulInstance, pNetworkAdapter.asOutParam());
- if ( FAILED(rc)
- || pNetworkAdapter.isNull())
- goto done;
-
- /*
- * Find the adapter instance, get the config interface and update
- * the link state.
- */
- NetworkAdapterType_T adapterType;
- rc = pNetworkAdapter->COMGETTER(AdapterType)(&adapterType);
- AssertComRC(rc);
- if (FAILED(rc))
+ do
{
- rc = E_FAIL;
- goto done;
- }
+ ComPtr<INetworkAdapter> pNetworkAdapter;
+ rc = machine()->GetNetworkAdapter(ulInstance, pNetworkAdapter.asOutParam());
+ if ( FAILED(rc)
+ || pNetworkAdapter.isNull())
+ break;
- const char *pszAdapterName = networkAdapterTypeToName(adapterType);
- PPDMIBASE pBase;
- vrc = PDMR3QueryLun(mpVM, pszAdapterName, ulInstance, 0, &pBase);
- ComAssertRC(vrc);
- if (RT_FAILURE(vrc))
- {
- rc = E_FAIL;
- goto done;
- }
- NetworkAttachmentType_T attachmentType;
- vrc = pNetworkAdapter->COMGETTER(AttachmentType)(&attachmentType);
+ /*
+ * Find the adapter instance, get the config interface and update
+ * the link state.
+ */
+ NetworkAdapterType_T adapterType;
+ rc = pNetworkAdapter->COMGETTER(AdapterType)(&adapterType);
+ if (FAILED(rc))
+ {
+ AssertComRC(rc);
+ rc = E_FAIL;
+ break;
+ }
- if ( RT_FAILURE(vrc)
- || attachmentType != NetworkAttachmentType_NAT)
- {
- rc = (RT_FAILURE(vrc)) ? E_FAIL: rc;
- goto done;
- }
+ const char *pszAdapterName = networkAdapterTypeToName(adapterType);
+ PPDMIBASE pBase;
+ int vrc = PDMR3QueryLun(ptrVM, pszAdapterName, ulInstance, 0, &pBase);
+ if (RT_FAILURE(vrc))
+ {
+ ComAssertRC(vrc);
+ rc = E_FAIL;
+ break;
+ }
- /* look down for PDMINETWORKNATCONFIG interface */
- while (pBase)
- {
- if ((pNetNatCfg = (PPDMINETWORKNATCONFIG)pBase->pfnQueryInterface(pBase, PDMINETWORKNATCONFIG_IID)))
+ NetworkAttachmentType_T attachmentType;
+ rc = pNetworkAdapter->COMGETTER(AttachmentType)(&attachmentType);
+ if ( FAILED(rc)
+ || attachmentType != NetworkAttachmentType_NAT)
+ {
+ rc = E_FAIL;
break;
- PPDMDRVINS drvins = PDMIBASE_2_PDMDRV(pBase);
- pBase = drvins->pDownBase;
- }
- if (!pNetNatCfg)
- goto done;
- bool fUdp = (aProto == NATProtocol_UDP);
- vrc = pNetNatCfg->pfnRedirectRuleCommand(pNetNatCfg, aNatRuleRemove, fUdp,
- Utf8Str(aHostIp).c_str(), aHostPort, Utf8Str(aGuestIp).c_str(),
- aGuestPort);
- if (RT_FAILURE(vrc))
- rc = E_FAIL;
+ }
+
+ /* look down for PDMINETWORKNATCONFIG interface */
+ PPDMINETWORKNATCONFIG pNetNatCfg = NULL;
+ while (pBase)
+ {
+ pNetNatCfg = (PPDMINETWORKNATCONFIG)pBase->pfnQueryInterface(pBase, PDMINETWORKNATCONFIG_IID);
+ if (pNetNatCfg)
+ break;
+ /** @todo r=bird: This stinks! */
+ PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pBase);
+ pBase = pDrvIns->pDownBase;
+ }
+ if (!pNetNatCfg)
+ break;
+
+ bool fUdp = aProto == NATProtocol_UDP;
+ vrc = pNetNatCfg->pfnRedirectRuleCommand(pNetNatCfg, aNatRuleRemove, fUdp,
+ Utf8Str(aHostIp).c_str(), aHostPort, Utf8Str(aGuestIp).c_str(),
+ aGuestPort);
+ if (RT_FAILURE(vrc))
+ rc = E_FAIL;
+ } while (0); /* break loop */
+ ptrVM.release();
}
-done:
+
LogFlowThisFunc(("Leaving rc=%#x\n", rc));
return rc;
}
@@ -3745,6 +4379,7 @@ done:
*
* @returns COM status code.
*
+ * @parma pVM 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.
@@ -3752,7 +4387,8 @@ done:
*
* @note Locks this object for writing.
*/
-HRESULT Console::doNetworkAdapterChange(const char *pszDevice,
+HRESULT Console::doNetworkAdapterChange(PVM pVM,
+ const char *pszDevice,
unsigned uInstance,
unsigned uLun,
INetworkAdapter *aNetworkAdapter)
@@ -3766,9 +4402,10 @@ HRESULT Console::doNetworkAdapterChange(const char *pszDevice,
/* We will need to release the write lock before calling EMT */
AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
- /* protect mpVM */
- AutoVMCaller autoVMCaller(this);
- if (FAILED(autoVMCaller.rc())) return autoVMCaller.rc();
+ /* Get the VM handle. */
+ SafeVMPtr ptrVM(this);
+ if (!ptrVM.isOk())
+ return ptrVM.rc();
/*
* Call worker in EMT, that's faster and safer than doing everything
@@ -3776,9 +4413,9 @@ HRESULT Console::doNetworkAdapterChange(const char *pszDevice,
* here to make requests from under the lock in order to serialize them.
*/
PVMREQ pReq;
- int vrc = VMR3ReqCall(mpVM, 0 /*idDstCpu*/, &pReq, 0 /* no wait! */, VMREQFLAGS_VBOX_STATUS,
- (PFNRT) Console::changeNetworkAttachment, 5,
- this, pszDevice, uInstance, uLun, aNetworkAdapter);
+ int vrc = VMR3ReqCall(pVM, 0 /*idDstCpu*/, &pReq, 0 /* no wait! */, VMREQFLAGS_VBOX_STATUS,
+ (PFNRT) Console::changeNetworkAttachment, 6,
+ this, ptrVM.raw(), pszDevice, uInstance, uLun, aNetworkAdapter);
/* leave the lock before waiting for a result (EMT will call us back!) */
alock.leave();
@@ -3810,6 +4447,7 @@ HRESULT Console::doNetworkAdapterChange(const char *pszDevice,
* @returns VBox status code.
*
* @param pThis Pointer to the Console object.
+ * @param pVM The VM handle.
* @param pszDevice The PDM device name.
* @param uInstance The PDM device instance.
* @param uLun The PDM LUN number of the drive.
@@ -3819,6 +4457,7 @@ HRESULT Console::doNetworkAdapterChange(const char *pszDevice,
* @note Locks the Console object for writing.
*/
DECLCALLBACK(int) Console::changeNetworkAttachment(Console *pThis,
+ PVM pVM,
const char *pszDevice,
unsigned uInstance,
unsigned uLun,
@@ -3832,20 +4471,14 @@ DECLCALLBACK(int) Console::changeNetworkAttachment(Console *pThis,
AssertMsg( ( !strcmp(pszDevice, "pcnet")
|| !strcmp(pszDevice, "e1000")
|| !strcmp(pszDevice, "virtio-net"))
- && (uLun == 0)
- && (uInstance < SchemaDefs::NetworkAdapterCount),
+ && uLun == 0
+ && uInstance < SchemaDefs::NetworkAdapterCount,
("pszDevice=%s uLun=%d uInstance=%d\n", pszDevice, uLun, uInstance));
Log(("pszDevice=%s uLun=%d uInstance=%d\n", pszDevice, uLun, uInstance));
AutoCaller autoCaller(pThis);
AssertComRCReturn(autoCaller.rc(), VERR_ACCESS_DENIED);
- /* protect mpVM */
- AutoVMCaller autoVMCaller(pThis);
- if (FAILED(autoVMCaller.rc())) return autoVMCaller.rc();
-
- PVM pVM = pThis->mpVM;
-
/*
* Suspend the VM first.
*
@@ -3937,13 +4570,11 @@ HRESULT Console::onSerialPortChange(ISerialPort *aSerialPort)
HRESULT rc = S_OK;
/* don't trigger serial port change if the VM isn't running */
- if (mpVM)
+ SafeVMPtrQuiet ptrVM(this);
+ if (ptrVM.isOk())
{
- /* protect mpVM */
- AutoVMCaller autoVMCaller(this);
- if (FAILED(autoVMCaller.rc())) return autoVMCaller.rc();
-
/* nothing to do so far */
+ ptrVM.release();
}
/* notify console callbacks on success */
@@ -3971,13 +4602,11 @@ HRESULT Console::onParallelPortChange(IParallelPort *aParallelPort)
HRESULT rc = S_OK;
/* don't trigger parallel port change if the VM isn't running */
- if (mpVM)
+ SafeVMPtrQuiet ptrVM(this);
+ if (ptrVM.isOk())
{
- /* protect mpVM */
- AutoVMCaller autoVMCaller(this);
- if (FAILED(autoVMCaller.rc())) return autoVMCaller.rc();
-
/* nothing to do so far */
+ ptrVM.release();
}
/* notify console callbacks on success */
@@ -4005,13 +4634,11 @@ HRESULT Console::onStorageControllerChange()
HRESULT rc = S_OK;
/* don't trigger storage controller change if the VM isn't running */
- if (mpVM)
+ SafeVMPtrQuiet ptrVM(this);
+ if (ptrVM.isOk())
{
- /* protect mpVM */
- AutoVMCaller autoVMCaller(this);
- if (FAILED(autoVMCaller.rc())) return autoVMCaller.rc();
-
/* nothing to do so far */
+ ptrVM.release();
}
/* notify console callbacks on success */
@@ -4039,13 +4666,11 @@ HRESULT Console::onMediumChange(IMediumAttachment *aMediumAttachment, BOOL aForc
HRESULT rc = S_OK;
/* don't trigger medium change if the VM isn't running */
- if (mpVM)
+ SafeVMPtrQuiet ptrVM(this);
+ if (ptrVM.isOk())
{
- /* protect mpVM */
- AutoVMCaller autoVMCaller(this);
- if (FAILED(autoVMCaller.rc())) return autoVMCaller.rc();
-
- rc = doMediumChange(aMediumAttachment, !!aForce);
+ rc = doMediumChange(aMediumAttachment, !!aForce, ptrVM);
+ ptrVM.release();
}
/* notify console callbacks on success */
@@ -4071,12 +4696,14 @@ HRESULT Console::onCPUChange(ULONG aCPU, BOOL aRemove)
HRESULT rc = S_OK;
/* don't trigger CPU change if the VM isn't running */
- if (mpVM)
+ SafeVMPtrQuiet ptrVM(this);
+ if (ptrVM.isOk())
{
if (aRemove)
- rc = doCPURemove(aCPU);
+ rc = doCPURemove(aCPU, ptrVM);
else
- rc = doCPUAdd(aCPU);
+ rc = doCPUAdd(aCPU, ptrVM);
+ ptrVM.release();
}
/* notify console callbacks on success */
@@ -4104,22 +4731,20 @@ HRESULT Console::onCPUExecutionCapChange(ULONG aExecutionCap)
HRESULT rc = S_OK;
/* don't trigger the CPU priority change if the VM isn't running */
- if (mpVM)
+ SafeVMPtrQuiet ptrVM(this);
+ if (ptrVM.isOk())
{
- /* protect mpVM */
- AutoVMCaller autoVMCaller(this);
- if (FAILED(autoVMCaller.rc())) return autoVMCaller.rc();
-
if ( mMachineState == MachineState_Running
|| mMachineState == MachineState_Teleporting
|| mMachineState == MachineState_LiveSnapshotting
)
{
/* No need to call in the EMT thread. */
- rc = VMR3SetCpuExecutionCap(mpVM, aExecutionCap);
+ rc = VMR3SetCpuExecutionCap(ptrVM, aExecutionCap);
}
else
rc = setInvalidMachineStateError();
+ ptrVM.release();
}
/* notify console callbacks on success */
@@ -4220,7 +4845,8 @@ HRESULT Console::onUSBControllerChange()
HRESULT rc = S_OK;
/* don't trigger USB controller change if the VM isn't running */
- if (mpVM)
+ SafeVMPtrQuiet ptrVM(this);
+ if (ptrVM.isOk())
{
/// @todo implement one day.
// Anyway, if we want to query the machine's USB Controller we need
@@ -4229,11 +4855,8 @@ HRESULT Console::onUSBControllerChange()
// bird: While the VM supports hot-plugging, I doubt any guest can
// handle it at this time... :-)
- /* protect mpVM */
- AutoVMCaller autoVMCaller(this);
- if (FAILED(autoVMCaller.rc())) return autoVMCaller.rc();
-
/* nothing to do so far */
+ ptrVM.release();
}
/* notify console callbacks on success */
@@ -4293,16 +4916,16 @@ HRESULT Console::onUSBDeviceAttach(IUSBDevice *aDevice, IVirtualBoxErrorInfo *aE
AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
- /* protect mpVM (we don't need error info, since it's a callback) */
- AutoVMCallerQuiet autoVMCaller(this);
- if (FAILED(autoVMCaller.rc()))
+ /* Get the VM pointer (we don't need error info, since it's a callback). */
+ SafeVMPtrQuiet ptrVM(this);
+ if (!ptrVM.isOk())
{
/* The VM may be no more operational when this message arrives
* (e.g. it may be Saving or Stopping or just PoweredOff) --
* autoVMCaller.rc() will return a failure in this case. */
LogFlowThisFunc(("Attach request ignored (mMachineState=%d).\n",
mMachineState));
- return autoVMCaller.rc();
+ return ptrVM.rc();
}
if (aError != NULL)
@@ -4313,7 +4936,7 @@ HRESULT Console::onUSBDeviceAttach(IUSBDevice *aDevice, IVirtualBoxErrorInfo *aE
}
/* Don't proceed unless there's at least one USB hub. */
- if (!PDMR3USBHasHub(mpVM))
+ if (!PDMR3USBHasHub(ptrVM))
{
LogFlowThisFunc(("Attach request ignored (no USB controller).\n"));
return E_FAIL;
@@ -4442,12 +5065,9 @@ HRESULT Console::onBandwidthGroupChange(IBandwidthGroup *aBandwidthGroup)
HRESULT rc = S_OK;
/* don't trigger the CPU priority change if the VM isn't running */
- if (mpVM)
+ SafeVMPtrQuiet ptrVM(this);
+ if (ptrVM.isOk())
{
- /* protect mpVM */
- AutoVMCaller autoVMCaller(this);
- if (FAILED(autoVMCaller.rc())) return autoVMCaller.rc();
-
if ( mMachineState == MachineState_Running
|| mMachineState == MachineState_Teleporting
|| mMachineState == MachineState_LiveSnapshotting
@@ -4463,13 +5083,14 @@ HRESULT Console::onBandwidthGroupChange(IBandwidthGroup *aBandwidthGroup)
if (SUCCEEDED(rc))
{
int vrc;
- vrc = PDMR3AsyncCompletionBwMgrSetMaxForFile(mpVM, Utf8Str(strName).c_str(),
+ vrc = PDMR3AsyncCompletionBwMgrSetMaxForFile(ptrVM, Utf8Str(strName).c_str(),
cMax * _1M);
AssertRC(vrc);
}
}
else
rc = setInvalidMachineStateError();
+ ptrVM.release();
}
/* notify console callbacks on success */
@@ -4481,6 +5102,41 @@ HRESULT Console::onBandwidthGroupChange(IBandwidthGroup *aBandwidthGroup)
}
/**
+ * Called by IInternalSessionControl::OnStorageDeviceChange().
+ *
+ * @note Locks this object for writing.
+ */
+HRESULT Console::onStorageDeviceChange(IMediumAttachment *aMediumAttachment, BOOL aRemove)
+{
+ LogFlowThisFunc(("\n"));
+
+ AutoCaller autoCaller(this);
+ AssertComRCReturnRC(autoCaller.rc());
+
+ AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ HRESULT rc = S_OK;
+
+ /* don't trigger medium change if the VM isn't running */
+ SafeVMPtrQuiet ptrVM(this);
+ if (ptrVM.isOk())
+ {
+ if (aRemove)
+ rc = doStorageDeviceDetach(aMediumAttachment, ptrVM);
+ else
+ rc = doStorageDeviceAttach(aMediumAttachment, ptrVM);
+ ptrVM.release();
+ }
+
+ /* notify console callbacks on success */
+ if (SUCCEEDED(rc))
+ fireStorageDeviceChangedEvent(mEventSource, aMediumAttachment, aRemove);
+
+ LogFlowThisFunc(("Leaving rc=%#x\n", rc));
+ return rc;
+}
+
+/**
* @note Temporarily locks this object for writing.
*/
HRESULT Console::getGuestProperty(IN_BSTR aName, BSTR *aValue,
@@ -4688,7 +5344,7 @@ static int onlineMergeMediumProgress(void *pvUser, unsigned uPercentage)
}
/**
- * @note Temporarily locks this object for writing.
+ * @note Temporarily locks this object for writing. bird: And/or reading?
*/
HRESULT Console::onlineMergeMedium(IMediumAttachment *aMediumAttachment,
ULONG aSourceIdx, ULONG aTargetIdx,
@@ -4703,7 +5359,11 @@ HRESULT Console::onlineMergeMedium(IMediumAttachment *aMediumAttachment,
HRESULT rc = S_OK;
int vrc = VINF_SUCCESS;
- PVM pVM = mpVM;
+
+ /* Get the VM - must be done before the read-locking. */
+ SafeVMPtr ptrVM(this);
+ if (!ptrVM.isOk())
+ return ptrVM.rc();
/* We will need to release the lock before doing the actual merge */
AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
@@ -4719,6 +5379,8 @@ HRESULT Console::onlineMergeMedium(IMediumAttachment *aMediumAttachment,
return setInvalidMachineStateError();
}
+ /** @todo AssertComRC -> AssertComRCReturn! Could potentially end up
+ * using uninitialized variables here. */
BOOL fBuiltinIoCache;
rc = mMachine->COMGETTER(IoCacheEnabled)(&fBuiltinIoCache);
AssertComRC(rc);
@@ -4783,23 +5445,23 @@ HRESULT Console::onlineMergeMedium(IMediumAttachment *aMediumAttachment,
alock.release();
/* Pause the VM, as it might have pending IO on this drive */
- VMSTATE enmVMState = VMR3GetState(pVM);
+ VMSTATE enmVMState = VMR3GetState(ptrVM);
if (mMachineState == MachineState_DeletingSnapshotOnline)
{
LogFlowFunc(("Suspending the VM...\n"));
/* disable the callback to prevent Console-level state change */
mVMStateChangeCallbackDisabled = true;
- int vrc2 = VMR3Suspend(pVM);
+ int vrc2 = VMR3Suspend(ptrVM);
mVMStateChangeCallbackDisabled = false;
AssertRCReturn(vrc2, E_FAIL);
}
- vrc = VMR3ReqCallWait(pVM,
+ vrc = VMR3ReqCallWait(ptrVM,
VMCPUID_ANY,
(PFNRT)reconfigureMediumAttachment,
13,
this,
- pVM,
+ ptrVM.raw(),
pcszDevice,
uInstance,
enmBus,
@@ -4818,13 +5480,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(pVM);
+ int vrc2 = VMR3Resume(ptrVM);
mVMStateChangeCallbackDisabled = false;
if (RT_FAILURE(vrc2))
{
/* too bad, we failed. try to sync the console state with the VMM state */
AssertLogRelRC(vrc2);
- vmstateChangeCallback(pVM, VMSTATE_SUSPENDED, enmVMState, this);
+ vmstateChangeCallback(ptrVM, VMSTATE_SUSPENDED, enmVMState, this);
}
}
@@ -4835,7 +5497,7 @@ HRESULT Console::onlineMergeMedium(IMediumAttachment *aMediumAttachment,
PPDMIBASE pIBase = NULL;
PPDMIMEDIA pIMedium = NULL;
- vrc = PDMR3QueryDriverOnLun(pVM, pcszDevice, uInstance, uLUN, "VD", &pIBase);
+ vrc = PDMR3QueryDriverOnLun(ptrVM, pcszDevice, uInstance, uLUN, "VD", &pIBase);
if (RT_SUCCESS(vrc))
{
if (pIBase)
@@ -4854,13 +5516,13 @@ 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(pVM);
+ enmVMState = VMR3GetState(ptrVM);
if (mMachineState == MachineState_DeletingSnapshotOnline)
{
LogFlowFunc(("Suspending the VM...\n"));
/* disable the callback to prevent Console-level state change */
mVMStateChangeCallbackDisabled = true;
- int vrc2 = VMR3Suspend(pVM);
+ int vrc2 = VMR3Suspend(ptrVM);
mVMStateChangeCallbackDisabled = false;
AssertRCReturn(vrc2, E_FAIL);
}
@@ -4870,12 +5532,12 @@ HRESULT Console::onlineMergeMedium(IMediumAttachment *aMediumAttachment,
aMergeForward, aParentForTarget,
ComSafeArrayInArg(aChildrenToReparent));
- vrc = VMR3ReqCallWait(pVM,
+ vrc = VMR3ReqCallWait(ptrVM,
VMCPUID_ANY,
(PFNRT)reconfigureMediumAttachment,
13,
this,
- pVM,
+ ptrVM.raw(),
pcszDevice,
uInstance,
enmBus,
@@ -4894,13 +5556,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(pVM);
+ int vrc2 = VMR3Resume(ptrVM);
mVMStateChangeCallbackDisabled = false;
AssertRC(vrc2);
if (RT_FAILURE(vrc2))
{
/* too bad, we failed. try to sync the console state with the VMM state */
- vmstateChangeCallback(pVM, VMSTATE_SUSPENDED, enmVMState, this);
+ vmstateChangeCallback(ptrVM, VMSTATE_SUSPENDED, enmVMState, this);
}
}
@@ -5202,7 +5864,7 @@ HRESULT Console::addVMCaller(bool aQuiet /* = false */,
tr("The virtual machine is being powered down"));
}
- if (mpVM == NULL)
+ if (mpUVM == NULL)
{
Assert(aAllowNullVM == true);
@@ -5229,7 +5891,7 @@ void Console::releaseVMCaller()
AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
- AssertReturnVoid(mpVM != NULL);
+ AssertReturnVoid(mpUVM != NULL);
Assert(mVMCallers > 0);
--mVMCallers;
@@ -5241,6 +5903,62 @@ void Console::releaseVMCaller()
}
}
+
+HRESULT Console::safeVMPtrRetainer(PVM *a_ppVM, PUVM *a_ppUVM, bool a_Quiet)
+{
+ *a_ppVM = NULL;
+ *a_ppUVM = NULL;
+
+ AutoCaller autoCaller(this);
+ AssertComRCReturnRC(autoCaller.rc());
+ AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ /*
+ * Repeat the checks done by addVMCaller.
+ */
+ 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"));
+ PUVM pUVM = mpUVM;
+ if (!pUVM)
+ return a_Quiet
+ ? E_ACCESSDENIED
+ : setError(E_ACCESSDENIED, tr("The virtual machine is was powered off"));
+
+ /*
+ * Retain a reference to the user mode VM handle and get the global handle.
+ */
+ uint32_t cRefs = VMR3RetainUVM(pUVM);
+ 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"));
+ }
+
+ /* done */
+ *a_ppVM = pVM;
+ *a_ppUVM = pUVM;
+ return S_OK;
+}
+
+void Console::safeVMPtrReleaser(PVM *a_ppVM, PUVM *a_ppUVM)
+{
+ if (*a_ppVM && *a_ppUVM)
+ VMR3ReleaseUVM(*a_ppUVM);
+ *a_ppVM = NULL;
+ *a_ppUVM = NULL;
+}
+
+
/**
* Initialize the release logging facility. In case something
* goes wrong, there will be no release logging. Maybe in the future
@@ -5302,24 +6020,26 @@ HRESULT Console::consoleInitReleaseLog(const ComPtr<IMachine> aMachine)
}
}
- PRTLOGGER loggerRelease;
- static const char * const s_apszGroups[] = VBOX_LOGGROUP_NAMES;
- RTUINT fFlags = RTLOGFLAGS_PREFIX_TIME_PROG;
+ static const char * const s_apszGroups[] = VBOX_LOGGROUP_NAMES;
+ char szError[RTPATH_MAX + 128] = "";
+ PRTLOGGER pReleaseLogger;
+ uint32_t fFlags = RTLOGFLAGS_PREFIX_TIME_PROG | RTLOGFLAGS_RESTRICT_GROUPS;
#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
fFlags |= RTLOGFLAGS_USECRLF;
#endif
- char szError[RTPATH_MAX + 128] = "";
- int vrc = RTLogCreateEx(&loggerRelease, fFlags, "all",
+ int vrc = RTLogCreateEx(&pReleaseLogger, fFlags, "all all.restrict default.unrestricted",
"VBOX_RELEASE_LOG", RT_ELEMENTS(s_apszGroups), s_apszGroups, RTLOGDEST_FILE,
NULL /* pfnBeginEnd */, 0 /* cHistory */, 0 /* cbHistoryFileMax */, 0 /* uHistoryTimeMax */,
szError, sizeof(szError), logFile.c_str());
if (RT_SUCCESS(vrc))
{
+ RTLogSetGroupLimit(pReleaseLogger, 32768);
+
/* some introductory information */
RTTIMESPEC timeSpec;
char szTmp[256];
RTTimeSpecToString(RTTimeNow(&timeSpec), szTmp, sizeof(szTmp));
- RTLogRelLogger(loggerRelease, 0, ~0U,
+ RTLogRelLogger(pReleaseLogger, 0, ~0U,
"VirtualBox %s r%u %s (%s %s) release log\n"
#ifdef VBOX_BLEEDING_EDGE
"EXPERIMENTAL build " VBOX_BLEEDING_EDGE "\n"
@@ -5330,22 +6050,22 @@ HRESULT Console::consoleInitReleaseLog(const ComPtr<IMachine> aMachine)
vrc = RTSystemQueryOSInfo(RTSYSOSINFO_PRODUCT, szTmp, sizeof(szTmp));
if (RT_SUCCESS(vrc) || vrc == VERR_BUFFER_OVERFLOW)
- RTLogRelLogger(loggerRelease, 0, ~0U, "OS Product: %s\n", szTmp);
+ RTLogRelLogger(pReleaseLogger, 0, ~0U, "OS Product: %s\n", szTmp);
vrc = RTSystemQueryOSInfo(RTSYSOSINFO_RELEASE, szTmp, sizeof(szTmp));
if (RT_SUCCESS(vrc) || vrc == VERR_BUFFER_OVERFLOW)
- RTLogRelLogger(loggerRelease, 0, ~0U, "OS Release: %s\n", szTmp);
+ RTLogRelLogger(pReleaseLogger, 0, ~0U, "OS Release: %s\n", szTmp);
vrc = RTSystemQueryOSInfo(RTSYSOSINFO_VERSION, szTmp, sizeof(szTmp));
if (RT_SUCCESS(vrc) || vrc == VERR_BUFFER_OVERFLOW)
- RTLogRelLogger(loggerRelease, 0, ~0U, "OS Version: %s\n", szTmp);
+ RTLogRelLogger(pReleaseLogger, 0, ~0U, "OS Version: %s\n", szTmp);
vrc = RTSystemQueryOSInfo(RTSYSOSINFO_SERVICE_PACK, szTmp, sizeof(szTmp));
if (RT_SUCCESS(vrc) || vrc == VERR_BUFFER_OVERFLOW)
- RTLogRelLogger(loggerRelease, 0, ~0U, "OS Service Pack: %s\n", szTmp);
+ RTLogRelLogger(pReleaseLogger, 0, ~0U, "OS Service Pack: %s\n", szTmp);
vrc = RTSystemQueryDmiString(RTSYSDMISTR_PRODUCT_NAME, szTmp, sizeof(szTmp));
if (RT_SUCCESS(vrc) || vrc == VERR_BUFFER_OVERFLOW)
- RTLogRelLogger(loggerRelease, 0, ~0U, "DMI Product Name: %s\n", szTmp);
+ RTLogRelLogger(pReleaseLogger, 0, ~0U, "DMI Product Name: %s\n", szTmp);
vrc = RTSystemQueryDmiString(RTSYSDMISTR_PRODUCT_VERSION, szTmp, sizeof(szTmp));
if (RT_SUCCESS(vrc) || vrc == VERR_BUFFER_OVERFLOW)
- RTLogRelLogger(loggerRelease, 0, ~0U, "DMI Product Version: %s\n", szTmp);
+ RTLogRelLogger(pReleaseLogger, 0, ~0U, "DMI Product Version: %s\n", szTmp);
ComPtr<IHost> pHost;
pVirtualBox->COMGETTER(Host)(pHost.asOutParam());
@@ -5353,13 +6073,13 @@ HRESULT Console::consoleInitReleaseLog(const ComPtr<IMachine> aMachine)
ULONG cMbHostRamAvail = 0;
pHost->COMGETTER(MemorySize)(&cMbHostRam);
pHost->COMGETTER(MemoryAvailable)(&cMbHostRamAvail);
- RTLogRelLogger(loggerRelease, 0, ~0U, "Host RAM: %uMB RAM, available: %uMB\n",
+ RTLogRelLogger(pReleaseLogger, 0, ~0U, "Host RAM: %uMB RAM, available: %uMB\n",
cMbHostRam, cMbHostRamAvail);
/* the package type is interesting for Linux distributions */
char szExecName[RTPATH_MAX];
char *pszExecName = RTProcGetExecutablePath(szExecName, sizeof(szExecName));
- RTLogRelLogger(loggerRelease, 0, ~0U,
+ RTLogRelLogger(pReleaseLogger, 0, ~0U,
"Executable: %s\n"
"Process ID: %u\n"
"Package type: %s"
@@ -5372,11 +6092,11 @@ HRESULT Console::consoleInitReleaseLog(const ComPtr<IMachine> aMachine)
VBOX_PACKAGE_STRING);
/* register this logger as the release logger */
- RTLogRelSetDefaultInstance(loggerRelease);
+ RTLogRelSetDefaultInstance(pReleaseLogger);
hrc = S_OK;
/* Explicitly flush the log in case of VBOX_RELEASE_LOG=buffered. */
- RTLogFlush(loggerRelease);
+ RTLogFlush(pReleaseLogger);
}
else
hrc = setError(E_FAIL,
@@ -5562,8 +6282,6 @@ HRESULT Console::powerUp(IProgress **aProgress, bool aPaused)
/* Check all types of shared folders and compose a single list */
SharedFolderDataMap sharedFolders;
{
- // @todo umoeller
-
/* first, insert global folders */
for (SharedFolderDataMap::const_iterator it = m_mapGlobalSharedFolders.begin();
it != m_mapGlobalSharedFolders.end();
@@ -5709,6 +6427,7 @@ HRESULT Console::powerUp(IProgress **aProgress, bool aPaused)
rc = consoleInitReleaseLog(mMachine);
if (FAILED(rc))
throw rc;
+ mptrExtPackManager->dumpAllToReleaseLog();
#ifdef RT_OS_SOLARIS
/* setup host core dumper for the VM */
@@ -5878,7 +6597,8 @@ HRESULT Console::powerDown(IProgress *aProgress /*= NULL*/)
/* sanity */
Assert(mVMDestroying == false);
- Assert(mpVM != NULL);
+ PUVM pUVM = mpUVM; Assert(pUVM != NULL);
+ uint32_t cRefs = VMR3RetainUVM(pUVM); Assert(cRefs != UINT32_MAX);
AssertMsg( mMachineState == MachineState_Running
|| mMachineState == MachineState_Paused
@@ -5994,9 +6714,9 @@ HRESULT Console::powerDown(IProgress *aProgress /*= NULL*/)
{
LogFlowThisFunc(("Powering off the VM...\n"));
alock.leave();
- vrc = VMR3PowerOff(mpVM);
+ vrc = VMR3PowerOff(VMR3GetVM(pUVM));
#ifdef VBOX_WITH_EXTPACK
- mptrExtPackManager->callAllVmPowerOffHooks(this, mpVM);
+ mptrExtPackManager->callAllVmPowerOffHooks(this, VMR3GetVM(pUVM));
#endif
alock.enter();
}
@@ -6036,7 +6756,7 @@ HRESULT Console::powerDown(IProgress *aProgress /*= NULL*/)
bool fHasUSBController = false;
{
PPDMIBASE pBase;
- vrc = PDMR3QueryLun(mpVM, "usb-ohci", 0, 0, &pBase);
+ vrc = PDMR3QueryLun(VMR3GetVM(pUVM), "usb-ohci", 0, 0, &pBase);
if (RT_SUCCESS(vrc))
{
fHasUSBController = true;
@@ -6051,16 +6771,16 @@ HRESULT Console::powerDown(IProgress *aProgress /*= NULL*/)
* instantiating SafeVMPtr to access mpVM). It's safe here because
* mVMDestroying is set which should prevent any activity. */
- /* Set mpVM to NULL early just in case if some old code is not using
- * addVMCaller()/releaseVMCaller(). */
- PVM pVM = mpVM;
- mpVM = NULL;
+ /* Set mpUVM to NULL early just in case if some old code is not using
+ * addVMCaller()/releaseVMCaller(). (We have our own ref on pUVM.) */
+ VMR3ReleaseUVM(mpUVM);
+ mpUVM = NULL;
LogFlowThisFunc(("Destroying the VM...\n"));
alock.leave();
- vrc = VMR3Destroy(pVM);
+ vrc = VMR3Destroy(VMR3GetVM(pUVM));
/* take the lock again */
alock.enter();
@@ -6083,8 +6803,9 @@ HRESULT Console::powerDown(IProgress *aProgress /*= NULL*/)
}
else
{
- /* bad bad bad, but what to do? */
- mpVM = pVM;
+ /* bad bad bad, but what to do? (Give Console our UVM ref.) */
+ mpUVM = pUVM;
+ pUVM = NULL;
rc = setError(VBOX_E_VM_ERROR,
tr("Could not destroy the machine. (Error: %Rrc)"),
vrc);
@@ -6105,11 +6826,17 @@ HRESULT Console::powerDown(IProgress *aProgress /*= NULL*/)
vrc);
}
- /* Finished with destruction. Note that if something impossible happened and
- * we've failed to destroy the VM, mVMDestroying will remain true and
- * mMachineState will be something like Stopping, so most Console methods
- * will return an error to the caller. */
- if (mpVM == NULL)
+ /*
+ * Finished with the destruction.
+ *
+ * Note that if something impossible happened and we've failed to destroy
+ * the VM, mVMDestroying will remain true and mMachineState will be
+ * something like Stopping, so most Console methods will return an error
+ * to the caller.
+ */
+ if (mpUVM != NULL)
+ VMR3ReleaseUVM(pUVM);
+ else
mVMDestroying = false;
if (SUCCEEDED(rc))
@@ -6223,16 +6950,15 @@ HRESULT Console::fetchSharedFolders(BOOL aGlobal)
LogFlowThisFunc(("Entering\n"));
- /* protect mpVM (if not NULL) */
+ /* Check if we're online and keep it that way. */
+ SafeVMPtrQuiet ptrVM(this);
AutoVMCallerQuietWeak autoVMCaller(this);
+ bool const online = ptrVM.isOk()
+ && m_pVMMDev
+ && m_pVMMDev->isShFlActive();
HRESULT rc = S_OK;
- bool online = mpVM
- && autoVMCaller.isOk()
- && m_pVMMDev
- && m_pVMMDev->isShFlActive();
-
try
{
if (aGlobal)
@@ -6278,7 +7004,6 @@ HRESULT Console::fetchSharedFolders(BOOL aGlobal)
SharedFolderData(strHostPath, writable, autoMount)));
/* send changes to HGCM if the VM is running */
- /// @todo umoeller report errors as runtime warnings through VMSetError
if (online)
{
SharedFolderDataMap::iterator it = oldFolders.find(strName);
@@ -6345,7 +7070,7 @@ HRESULT Console::fetchSharedFolders(BOOL aGlobal)
catch (HRESULT rc2)
{
if (online)
- setVMRuntimeErrorCallbackF(mpVM, this, 0, "BrokenSharedFolder",
+ setVMRuntimeErrorCallbackF(ptrVM, this, 0, "BrokenSharedFolder",
N_("Broken shared folder!"));
}
@@ -6398,7 +7123,7 @@ HRESULT Console::createSharedFolder(const Utf8Str &strName, const SharedFolderDa
ComAssertRet(aData.m_strHostPath.isNotEmpty(), E_FAIL);
/* sanity checks */
- AssertReturn(mpVM, E_FAIL);
+ AssertReturn(mpUVM, E_FAIL);
AssertReturn(m_pVMMDev && m_pVMMDev->isShFlActive(), E_FAIL);
VBOXHGCMSVCPARM parms[SHFL_CPARMS_ADD_MAPPING2];
@@ -6503,7 +7228,7 @@ HRESULT Console::removeSharedFolder(const Utf8Str &strName)
ComAssertRet(strName.isNotEmpty(), E_FAIL);
/* sanity checks */
- AssertReturn(mpVM, E_FAIL);
+ AssertReturn(mpUVM, E_FAIL);
AssertReturn(m_pVMMDev && m_pVMMDev->isShFlActive(), E_FAIL);
VBOXHGCMSVCPARM parms;
@@ -6715,10 +7440,10 @@ DECLCALLBACK(void) Console::vmstateChangeCallback(PVM aVM,
case VMSTATE_RESETTING:
{
- #ifdef VBOX_WITH_GUEST_PROPS
+#ifdef VBOX_WITH_GUEST_PROPS
/* Do not take any read/write locks here! */
that->guestPropertiesHandleVMReset();
- #endif
+#endif
break;
}
@@ -6907,9 +7632,10 @@ HRESULT Console::attachUSBDevice(IUSBDevice *aHostDevice, ULONG aMaskedIfs)
hrc = aHostDevice->COMGETTER(Remote)(&fRemote);
ComAssertComRCRetRC(hrc);
- /* protect mpVM */
- AutoVMCaller autoVMCaller(this);
- if (FAILED(autoVMCaller.rc())) return autoVMCaller.rc();
+ /* Get the VM handle. */
+ SafeVMPtr ptrVM(this);
+ if (!ptrVM.isOk())
+ return ptrVM.rc();
LogFlowThisFunc(("Proxying USB device '%s' {%RTuuid}...\n",
Address.c_str(), uuid.raw()));
@@ -6918,8 +7644,9 @@ HRESULT Console::attachUSBDevice(IUSBDevice *aHostDevice, ULONG aMaskedIfs)
alock.leave();
/** @todo just do everything here and only wrap the PDMR3Usb call. That'll offload some notification stuff from the EMT thread. */
- int vrc = VMR3ReqCallWait(mpVM, VMCPUID_ANY,
- (PFNRT)usbAttachCallback, 6, this, aHostDevice, uuid.raw(), fRemote, Address.c_str(), aMaskedIfs);
+ int vrc = VMR3ReqCallWait(ptrVM, VMCPUID_ANY,
+ (PFNRT)usbAttachCallback, 7,
+ this, ptrVM.raw(), aHostDevice, uuid.raw(), fRemote, Address.c_str(), aMaskedIfs);
/* restore the lock */
alock.enter();
@@ -6929,7 +7656,7 @@ HRESULT Console::attachUSBDevice(IUSBDevice *aHostDevice, ULONG aMaskedIfs)
if (RT_FAILURE(vrc))
{
LogWarningThisFunc(("Failed to create proxy device for '%s' {%RTuuid} (%Rrc)\n",
- Address.c_str(), uuid.raw(), vrc));
+ Address.c_str(), uuid.raw(), vrc));
switch (vrc)
{
@@ -6963,7 +7690,7 @@ HRESULT Console::attachUSBDevice(IUSBDevice *aHostDevice, ULONG aMaskedIfs)
*/
//static
DECLCALLBACK(int)
-Console::usbAttachCallback(Console *that, IUSBDevice *aHostDevice, PCRTUUID aUuid, bool aRemote, const char *aAddress, ULONG aMaskedIfs)
+Console::usbAttachCallback(Console *that, PVM pVM, IUSBDevice *aHostDevice, PCRTUUID aUuid, bool aRemote, const char *aAddress, ULONG aMaskedIfs)
{
LogFlowFuncEnter();
LogFlowFunc(("that={%p}\n", that));
@@ -6986,7 +7713,7 @@ Console::usbAttachCallback(Console *that, IUSBDevice *aHostDevice, PCRTUUID aUui
AssertComRCReturn(hrc, VERR_GENERAL_FAILURE);
Assert(portVersion == 1 || portVersion == 2);
- int vrc = PDMR3USBCreateProxyDevice(that->mpVM, aUuid, aRemote, aAddress, pvRemoteBackend,
+ int vrc = PDMR3USBCreateProxyDevice(pVM, aUuid, aRemote, aAddress, pvRemoteBackend,
portVersion == 1 ? VUSB_STDVER_11 : VUSB_STDVER_20, aMaskedIfs);
if (RT_SUCCESS(vrc))
{
@@ -7026,22 +7753,24 @@ HRESULT Console::detachUSBDevice(USBDeviceList::iterator &aIt)
/* still want a lock object because we need to leave it */
AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
- /* protect mpVM */
- AutoVMCaller autoVMCaller(this);
- if (FAILED(autoVMCaller.rc())) return autoVMCaller.rc();
+ /* Get the VM handle. */
+ SafeVMPtr ptrVM(this);
+ if (!ptrVM.isOk())
+ return ptrVM.rc();
/* if the device is attached, then there must at least one USB hub. */
- AssertReturn(PDMR3USBHasHub(mpVM), E_FAIL);
+ AssertReturn(PDMR3USBHasHub(ptrVM), E_FAIL);
LogFlowThisFunc(("Detaching USB proxy device {%RTuuid}...\n",
- (*aIt)->id().raw()));
+ (*aIt)->id().raw()));
/* leave the lock before a VMR3* call (EMT will call us back)! */
alock.leave();
/** @todo just do everything here and only wrap the PDMR3Usb call. That'll offload some notification stuff from the EMT thread. */
- int vrc = VMR3ReqCallWait(mpVM, VMCPUID_ANY,
- (PFNRT) usbDetachCallback, 4, this, &aIt, (*aIt)->id().raw());
+ int vrc = VMR3ReqCallWait(ptrVM, VMCPUID_ANY,
+ (PFNRT)usbDetachCallback, 5,
+ this, ptrVM.raw(), &aIt, (*aIt)->id().raw());
ComAssertRCRet(vrc, E_FAIL);
return S_OK;
@@ -7058,7 +7787,7 @@ HRESULT Console::detachUSBDevice(USBDeviceList::iterator &aIt)
*/
//static
DECLCALLBACK(int)
-Console::usbDetachCallback(Console *that, USBDeviceList::iterator *aIt, PCRTUUID aUuid)
+Console::usbDetachCallback(Console *that, PVM pVM, USBDeviceList::iterator *aIt, PCRTUUID aUuid)
{
LogFlowFuncEnter();
LogFlowFunc(("that={%p}\n", that));
@@ -7082,7 +7811,7 @@ Console::usbDetachCallback(Console *that, USBDeviceList::iterator *aIt, PCRTUUID
that->consoleVRDPServer()->USBBackendReleasePointer(&guid);
}
- int vrc = PDMR3USBDetachDevice(that->mpVM, aUuid);
+ int vrc = PDMR3USBDetachDevice(pVM, aUuid);
if (RT_SUCCESS(vrc))
{
@@ -7148,7 +7877,7 @@ HRESULT Console::attachToTapInterface(INetworkAdapter *networkAdapter)
memset(&IfReq, 0, sizeof(IfReq));
/* The name of the TAP interface we are using */
Bstr tapDeviceName;
- rc = networkAdapter->COMGETTER(HostInterface)(tapDeviceName.asOutParam());
+ rc = networkAdapter->COMGETTER(BridgedInterface)(tapDeviceName.asOutParam());
if (FAILED(rc))
tapDeviceName.setNull(); /* Is this necessary? */
if (tapDeviceName.isEmpty())
@@ -7226,7 +7955,7 @@ HRESULT Console::attachToTapInterface(INetworkAdapter *networkAdapter)
*/
/* The name of the TAP interface we are using */
Bstr tapDeviceName;
- rc = networkAdapter->COMGETTER(HostInterface)(tapDeviceName.asOutParam());
+ rc = networkAdapter->COMGETTER(BridgedInterface)(tapDeviceName.asOutParam());
if (FAILED(rc))
tapDeviceName.setNull(); /* Is this necessary? */
if (tapDeviceName.isEmpty())
@@ -7313,7 +8042,7 @@ HRESULT Console::detachFromTapInterface(INetworkAdapter *networkAdapter)
*/
Bstr tapDeviceName, tapTerminateApplication;
bool isStatic = true;
- rc = networkAdapter->COMGETTER(HostInterface)(tapDeviceName.asOutParam());
+ rc = networkAdapter->COMGETTER(BridgedInterface)(tapDeviceName.asOutParam());
if (FAILED(rc) || tapDeviceName.isEmpty())
{
/* If the name is empty, this is a dynamic TAP device, so close it now,
@@ -7749,7 +8478,7 @@ DECLCALLBACK(int) Console::powerUpThread(RTTHREAD Thread, void *pvUser)
AutoWriteLock alock(pConsole COMMA_LOCKVAL_SRC_POS);
/* sanity */
- Assert(pConsole->mpVM == NULL);
+ Assert(pConsole->mpUVM == NULL);
try
{
@@ -7972,7 +8701,7 @@ DECLCALLBACK(int) Console::powerUpThread(RTTHREAD Thread, void *pvUser)
{
/* -> ConsoleImplTeleporter.cpp */
bool fPowerOffOnFailure;
- rc = pConsole->teleporterTrg(pVM, pMachine, &task->mErrorMsg, task->mStartPaused,
+ rc = pConsole->teleporterTrg(VMR3GetUVM(pVM), pMachine, &task->mErrorMsg, task->mStartPaused,
task->mProgress, &fPowerOffOnFailure);
if (FAILED(rc) && fPowerOffOnFailure)
{
@@ -8076,7 +8805,8 @@ DECLCALLBACK(int) Console::powerUpThread(RTTHREAD Thread, void *pvUser)
/*
* If VMR3Create() failed it has released the VM memory.
*/
- pConsole->mpVM = NULL;
+ VMR3ReleaseUVM(pConsole->mpUVM);
+ pConsole->mpUVM = NULL;
}
if (SUCCEEDED(rc) && RT_FAILURE(vrc))
@@ -8123,7 +8853,7 @@ DECLCALLBACK(int) Console::powerUpThread(RTTHREAD Thread, void *pvUser)
/* preserve existing error info */
ErrorInfoKeeper eik;
- Assert(pConsole->mpVM == NULL);
+ Assert(pConsole->mpUVM == NULL);
vmstateChangeCallback(NULL, VMSTATE_TERMINATED, VMSTATE_CREATING,
pConsole);
}
@@ -8229,6 +8959,7 @@ DECLCALLBACK(int) Console::reconfigureMediumAttachment(Console *pConsole,
phrc,
true /* fAttachDetach */,
false /* fForceUnmount */,
+ false /* fHotplug */,
pVM,
NULL /* paLedDevType */);
/** @todo this dumps everything attached to this device instance, which
@@ -8248,8 +8979,8 @@ DECLCALLBACK(int) Console::reconfigureMediumAttachment(Console *pConsole,
*/
static void takesnapshotProgressCancelCallback(void *pvUser)
{
- PVM pVM = (PVM)pvUser;
- SSMR3Cancel(pVM);
+ PUVM pUVM = (PUVM)pvUser;
+ SSMR3Cancel(VMR3GetVM(pUVM));
}
/**
@@ -8324,13 +9055,17 @@ DECLCALLBACK(int) Console::fntTakeSnapshotWorker(RTTHREAD Thread, void *pvUser)
{
Utf8Str strSavedStateFile(pTask->bstrSavedStateFile);
+ 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, that->mpVM);
+ pTask->mProgress->setCancelCallback(takesnapshotProgressCancelCallback, ptrVM.rawUVM());
alock.leave();
LogFlowFunc(("VMR3Save...\n"));
- int vrc = VMR3Save(that->mpVM,
+ int vrc = VMR3Save(ptrVM,
strSavedStateFile.c_str(),
true /*fContinueAfterwards*/,
Console::stateProgressCallback,
@@ -8407,12 +9142,12 @@ DECLCALLBACK(int) Console::fntTakeSnapshotWorker(RTTHREAD Thread, void *pvUser)
* don't leave the lock since reconfigureMediumAttachment
* isn't going to need the Console lock.
*/
- vrc = VMR3ReqCallWait(that->mpVM,
+ vrc = VMR3ReqCallWait(ptrVM,
VMCPUID_ANY,
(PFNRT)reconfigureMediumAttachment,
13,
that,
- that->mpVM,
+ ptrVM.raw(),
pcszDevice,
lInstance,
enmBus,
@@ -8478,8 +9213,9 @@ DECLCALLBACK(int) Console::fntTakeSnapshotWorker(RTTHREAD Thread, void *pvUser)
if (pTask->lastMachineState == MachineState_Running)
{
LogFlowFunc(("VMR3Resume...\n"));
+ SafeVMPtr ptrVM(that);
alock.leave();
- int vrc = VMR3Resume(that->mpVM);
+ int vrc = VMR3Resume(ptrVM);
alock.enter();
if (RT_FAILURE(vrc))
{
@@ -8496,7 +9232,7 @@ DECLCALLBACK(int) Console::fntTakeSnapshotWorker(RTTHREAD Thread, void *pvUser)
{
/** @todo this could probably be made more generic and reused elsewhere. */
/* paranoid cleanup on for a failed online snapshot. */
- VMSTATE enmVMState = VMR3GetState(that->mpVM);
+ VMSTATE enmVMState = VMR3GetStateU(that->mpUVM);
switch (enmVMState)
{
case VMSTATE_RUNNING:
@@ -8535,8 +9271,9 @@ DECLCALLBACK(int) Console::fntTakeSnapshotWorker(RTTHREAD Thread, void *pvUser)
{
Assert(pTask->lastMachineState == MachineState_Running);
LogFlowFunc(("VMR3Resume (on failure)...\n"));
+ SafeVMPtr ptrVM(that);
alock.leave();
- int vrc = VMR3Resume(that->mpVM); AssertLogRelRC(vrc);
+ int vrc = VMR3Resume(ptrVM); AssertLogRelRC(vrc);
alock.enter();
if (RT_FAILURE(vrc))
that->setMachineState(MachineState_Paused);
@@ -8596,7 +9333,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(that->mpVM,
+ int vrc = VMR3Save(task->mpVM,
task->mSavedStateFile.c_str(),
false, /*fContinueAfterwards*/
Console::stateProgressCallback,
@@ -8757,6 +9494,17 @@ typedef struct DRVMAINSTATUS
/** The unit number corresponding to the last entry in the LED array.
* (The size of the LED array is iLastLUN - iFirstLUN + 1.) */
RTUINT iLastLUN;
+ /** Pointer to the driver instance. */
+ PPDMDRVINS pDrvIns;
+ /** The Media Notify interface. */
+ PDMIMEDIANOTIFY IMediaNotify;
+ /** Map for translating PDM storage controller/LUN information to
+ * IMediumAttachment references. */
+ Console::MediumAttachmentMap *pmapMediumAttachments;
+ /** Device name+instance for mapping */
+ char *pszDeviceInstance;
+ /** Pointer to the Console object, for driver triggered activities. */
+ Console *pConsole;
} DRVMAINSTATUS, *PDRVMAINSTATUS;
@@ -8771,7 +9519,7 @@ typedef struct DRVMAINSTATUS
*/
DECLCALLBACK(void) Console::drvStatus_UnitChanged(PPDMILEDCONNECTORS pInterface, unsigned iLUN)
{
- PDRVMAINSTATUS pData = (PDRVMAINSTATUS)(void *)pInterface;
+ PDRVMAINSTATUS pData = (PDRVMAINSTATUS)((uintptr_t)pInterface - RT_OFFSETOF(DRVMAINSTATUS, ILedConnectors));
if (iLUN >= pData->iFirstLUN && iLUN <= pData->iLastLUN)
{
PPDMLED pLed;
@@ -8785,6 +9533,59 @@ DECLCALLBACK(void) Console::drvStatus_UnitChanged(PPDMILEDCONNECTORS pInterface,
/**
+ * Notification about a medium eject.
+ *
+ * @returns VBox status.
+ * @param pInterface Pointer to the interface structure containing the called function pointer.
+ * @param uLUN The unit number.
+ */
+DECLCALLBACK(int) Console::drvStatus_MediumEjected(PPDMIMEDIANOTIFY pInterface, unsigned uLUN)
+{
+ PDRVMAINSTATUS pData = (PDRVMAINSTATUS)((uintptr_t)pInterface - RT_OFFSETOF(DRVMAINSTATUS, IMediaNotify));
+ PPDMDRVINS pDrvIns = pData->pDrvIns;
+ LogFunc(("uLUN=%d\n", uLUN));
+ if (pData->pmapMediumAttachments)
+ {
+ AutoWriteLock alock(pData->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);
+ if (it != end)
+ pMediumAtt = it->second;
+ Assert(!pMediumAtt.isNull());
+ if (!pMediumAtt.isNull())
+ {
+ IMedium *pMedium;
+ HRESULT rc = pMediumAtt->COMGETTER(Medium)(&pMedium);
+ AssertComRC(rc);
+ BOOL fHostDrive = FALSE;
+ rc = pMedium->COMGETTER(HostDrive)(&fHostDrive);
+ AssertComRC(rc);
+ if (!fHostDrive)
+ {
+ alock.release();
+
+ ComPtr<IMediumAttachment> pNewMediumAtt;
+ rc = pData->pConsole->mControl->EjectMedium(pMediumAtt, pNewMediumAtt.asOutParam());
+ if (SUCCEEDED(rc))
+ fireMediumChangedEvent(pData->pConsole->mEventSource, pNewMediumAtt);
+
+ alock.acquire();
+ if (pNewMediumAtt != pMediumAtt)
+ {
+ pData->pmapMediumAttachments->erase(devicePath);
+ pData->pmapMediumAttachments->insert(std::make_pair(devicePath, pNewMediumAtt));
+ }
+ }
+ }
+ }
+ return VINF_SUCCESS;
+}
+
+
+/**
* @interface_method_impl{PDMIBASE,pfnQueryInterface}
*/
DECLCALLBACK(void *) Console::drvStatus_QueryInterface(PPDMIBASE pInterface, const char *pszIID)
@@ -8793,6 +9594,7 @@ DECLCALLBACK(void *) Console::drvStatus_QueryInterface(PPDMIBASE pInterface, co
PDRVMAINSTATUS pThis = PDMINS_2_DATA(pDrvIns, PDRVMAINSTATUS);
PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
PDMIBASE_RETURN_INTERFACE(pszIID, PDMILEDCONNECTORS, &pThis->ILedConnectors);
+ PDMIBASE_RETURN_INTERFACE(pszIID, PDMIMEDIANOTIFY, &pThis->IMediaNotify);
return NULL;
}
@@ -8832,7 +9634,7 @@ DECLCALLBACK(int) Console::drvStatus_Construct(PPDMDRVINS pDrvIns, PCFGMNODE pCf
/*
* Validate configuration.
*/
- if (!CFGMR3AreValuesValid(pCfg, "papLeds\0First\0Last\0"))
+ if (!CFGMR3AreValuesValid(pCfg, "papLeds\0pmapMediumAttachments\0DeviceInstance\0pConsole\0First\0Last\0"))
return VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES;
AssertMsgReturn(PDMDrvHlpNoAttach(pDrvIns) == VERR_PDM_NO_ATTACHED_DRIVER,
("Configuration error: Not possible to attach anything to this driver!\n"),
@@ -8843,6 +9645,9 @@ DECLCALLBACK(int) Console::drvStatus_Construct(PPDMDRVINS pDrvIns, PCFGMNODE pCf
*/
pDrvIns->IBase.pfnQueryInterface = Console::drvStatus_QueryInterface;
pData->ILedConnectors.pfnUnitChanged = Console::drvStatus_UnitChanged;
+ pData->IMediaNotify.pfnEjected = Console::drvStatus_MediumEjected;
+ pData->pDrvIns = pDrvIns;
+ pData->pszDeviceInstance = NULL;
/*
* Read config.
@@ -8854,6 +9659,28 @@ DECLCALLBACK(int) Console::drvStatus_Construct(PPDMDRVINS pDrvIns, PCFGMNODE pCf
return rc;
}
+ rc = CFGMR3QueryPtrDef(pCfg, "pmapMediumAttachments", (void **)&pData->pmapMediumAttachments, NULL);
+ if (RT_FAILURE(rc))
+ {
+ AssertMsgFailed(("Configuration error: Failed to query the \"pmapMediumAttachments\" value! rc=%Rrc\n", rc));
+ return rc;
+ }
+ if (pData->pmapMediumAttachments)
+ {
+ rc = CFGMR3QueryStringAlloc(pCfg, "DeviceInstance", &pData->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);
+ if (RT_FAILURE(rc))
+ {
+ AssertMsgFailed(("Configuration error: Failed to query the \"pConsole\" value! rc=%Rrc\n", rc));
+ return rc;
+ }
+ }
+
rc = CFGMR3QueryU32(pCfg, "First", &pData->iFirstLUN);
if (rc == VERR_CFGM_VALUE_NOT_FOUND)
pData->iFirstLUN = 0;
@@ -8893,7 +9720,7 @@ DECLCALLBACK(int) Console::drvStatus_Construct(PPDMDRVINS pDrvIns, PCFGMNODE pCf
/**
- * Keyboard driver registration record.
+ * Console status driver (LED) registration record.
*/
const PDMDRVREG Console::DrvStatusReg =
{