VirtualBox

Changeset 55214 in vbox for trunk/src/VBox/Main/src-server


Ignore:
Timestamp:
Apr 13, 2015 3:53:01 PM (10 years ago)
Author:
vboxsync
Message:

Main/Console+Machine+Session+Snapshot: move the save state and snapshot related methods from IConsole to IMachine, with lots of unavoidable code restructuring and cleanup. Also define two new machine states (so that the "Saving" one is specifically for saving state now) which requires more changes everywhere
Frontends: necessary adjustments
doc/SDK: document the changes

Location:
trunk/src/VBox/Main/src-server
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Main/src-server/HostPower.cpp

    r51498 r55214  
    55
    66/*
    7  * Copyright (C) 2006-2014 Oracle Corporation
     7 * Copyright (C) 2006-2015 Oracle Corporation
    88 *
    99 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    139139
    140140            /* save running VMs */
    141             SessionMachinesList::const_iterator it2 = machines.begin();
    142             for (VirtualBox::InternalControlList::const_iterator it = controls.begin();
    143                  it != controls.end() && it2 != machines.end();
    144                  ++it, ++it2)
     141            for (SessionMachinesList::const_iterator it = machines.begin();
     142                 it != machines.end();
     143                 ++it)
    145144            {
    146                 ComPtr<SessionMachine> pMachine = *it2;
     145                ComPtr<SessionMachine> pMachine = *it;
    147146                rc = pMachine->GetExtraData(Bstr("VBoxInternal2/SavestateOnBatteryLow").raw(),
    148147                                            value.asOutParam());
     
    160159                if (fGlobal + fPerVM >= 0)
    161160                {
    162                     ComPtr<IInternalSessionControl> pControl = *it;
    163161                    ComPtr<IProgress> progress;
    164162
    165                     /* note that SaveStateWithReason() will simply return a failure
    166                      * if the VM is in an inappropriate state */
    167                     rc = pControl->SaveStateWithReason(Reason_HostBatteryLow, progress.asOutParam());
     163                    /* SessionMachine::i_saveStateWithReason() will return
     164                     * a failure if the VM is in an inappropriate state */
     165                    rc = pMachine->i_saveStateWithReason(Reason_HostBatteryLow, progress);
    168166                    if (FAILED(rc))
    169167                    {
  • trunk/src/VBox/Main/src-server/MachineImpl.cpp

    r55168 r55214  
    131131
    132132    mSession.mPID              = NIL_RTPROCESS;
     133    mSession.mLockType         = LockType_Null;
    133134    mSession.mState            = SessionState_Unlocked;
    134135}
     
    26942695
    26952696    *aState = mData->mMachineState;
     2697    Assert(mData->mMachineState != MachineState_Null);
    26962698
    26972699    return S_OK;
     
    32483250
    32493251        // copy pointers to W (the write-locking session) before leaving lock (these must not be NULL)
     3252        ComAssertRet(mData->mSession.mLockType == LockType_Write || mData->mSession.mLockType == LockType_VM, E_FAIL);
    32503253        ComPtr<IInternalSessionControl> pSessionW = mData->mSession.mDirectControl;
    32513254        ComAssertRet(!pSessionW.isNull(), E_FAIL);
     
    32633266        // get the console of the session holding the write lock (this is a remote call)
    32643267        ComPtr<IConsole> pConsoleW;
    3265         LogFlowThisFunc(("Calling GetRemoteConsole()...\n"));
    3266         rc = pSessionW->GetRemoteConsole(pConsoleW.asOutParam());
    3267         LogFlowThisFunc(("GetRemoteConsole() returned %08X\n", rc));
    3268         if (FAILED(rc))
    3269             // the failure may occur w/o any error info (from RPC), so provide one
    3270             return setError(VBOX_E_VM_ERROR,
    3271                             tr("Failed to get a console object from the direct session (%Rhrc)"), rc);
    3272 
    3273         ComAssertRet(!pConsoleW.isNull(), E_FAIL);
     3268        if (mData->mSession.mLockType == LockType_VM)
     3269        {
     3270            LogFlowThisFunc(("Calling GetRemoteConsole()...\n"));
     3271            rc = pSessionW->COMGETTER(RemoteConsole)(pConsoleW.asOutParam());
     3272            LogFlowThisFunc(("GetRemoteConsole() returned %08X\n", rc));
     3273            if (FAILED(rc))
     3274                // the failure may occur w/o any error info (from RPC), so provide one
     3275                return setError(VBOX_E_VM_ERROR,
     3276                                tr("Failed to get a console object from the direct session (%Rhrc)"), rc);
     3277            ComAssertRet(!pConsoleW.isNull(), E_FAIL);
     3278        }
    32743279
    32753280        // share the session machine and W's console with the caller's session
     
    33153320        RTPROCESS pid = NIL_RTPROCESS;
    33163321        AssertCompile(sizeof(ULONG) == sizeof(RTPROCESS));
    3317         pSessionControl->GetPID((ULONG*)&pid);
     3322        pSessionControl->COMGETTER(PID)((ULONG*)&pid);
    33183323        Assert(pid != NIL_RTPROCESS);
    33193324
     
    34323437                /* get the console from the direct session */
    34333438                ComPtr<IConsole> console;
    3434                 rc = pSessionControl->GetRemoteConsole(console.asOutParam());
     3439                rc = pSessionControl->COMGETTER(RemoteConsole)(console.asOutParam());
    34353440                ComAssertComRC(rc);
    34363441
     
    35053510        if (SUCCEEDED(rc))
    35063511        {
     3512            mData->mSession.mLockType = aLockType;
    35073513            /* memorize the direct session control and cache IUnknown for it */
    35083514            mData->mSession.mDirectControl = pSessionControl;
     
    35253531        if (FAILED(rc))
    35263532            sessionMachine->uninit();
    3527 
    35283533    }
    35293534
     
    51725177}
    51735178
    5174 struct Machine::DeleteTask
    5175 {
    5176     ComObjPtr<Machine>          pMachine;
    5177     RTCList<ComPtr<IMedium> >   llMediums;
    5178     StringsList                 llFilesToDelete;
    5179     ComObjPtr<Progress>         pProgress;
     5179/**
     5180 * Task record for deleting a machine config.
     5181 */
     5182struct Machine::DeleteConfigTask
     5183    : public Machine::Task
     5184{
     5185    DeleteConfigTask(Machine *m,
     5186                     Progress *p,
     5187                     const Utf8Str &t,
     5188                     const RTCList<ComPtr<IMedium> > &llMediums,
     5189                     const StringsList &llFilesToDelete)
     5190        : Task(m, p, t),
     5191          m_llMediums(llMediums),
     5192          m_llFilesToDelete(llFilesToDelete)
     5193    {}
     5194
     5195    void handler()
     5196    {
     5197        m_pMachine->i_deleteConfigHandler(*this);
     5198    }
     5199
     5200    RTCList<ComPtr<IMedium> >   m_llMediums;
     5201    StringsList                 m_llFilesToDelete;
    51805202};
    51815203
    5182 HRESULT Machine::deleteConfig(const std::vector<ComPtr<IMedium> > &aMedia, ComPtr<IProgress> &aProgress)
    5183 {
    5184     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    5185 
    5186     HRESULT rc = i_checkStateDependency(MutableStateDep);
    5187     if (FAILED(rc)) return rc;
    5188 
    5189     if (mData->mRegistered)
    5190         return setError(VBOX_E_INVALID_VM_STATE,
    5191                         tr("Cannot delete settings of a registered machine"));
    5192 
    5193     DeleteTask *pTask = new DeleteTask;
    5194     pTask->pMachine = this;
    5195 
    5196     // collect files to delete
    5197     pTask->llFilesToDelete = mData->llFilesToDelete;            // saved states pushed here by Unregister()
    5198 
    5199     for (size_t i = 0; i < aMedia.size(); ++i)
    5200     {
    5201         IMedium *pIMedium(aMedia[i]);
    5202         ComObjPtr<Medium> pMedium = static_cast<Medium*>(pIMedium);
    5203         if (pMedium.isNull())
    5204             return setError(E_INVALIDARG, "The given medium pointer with index %d is invalid", i);
    5205         SafeArray<BSTR> ids;
    5206         rc = pMedium->COMGETTER(MachineIds)(ComSafeArrayAsOutParam(ids));
    5207         if (FAILED(rc)) return rc;
    5208         /* At this point the medium should not have any back references
    5209          * anymore. If it has it is attached to another VM and *must* not
    5210          * deleted. */
    5211         if (ids.size() < 1)
    5212             pTask->llMediums.append(pMedium);
    5213     }
    5214     if (mData->pMachineConfigFile->fileExists())
    5215         pTask->llFilesToDelete.push_back(mData->m_strConfigFileFull);
    5216 
    5217     pTask->pProgress.createObject();
    5218     pTask->pProgress->init(i_getVirtualBox(),
    5219                            static_cast<IMachine*>(this) /* aInitiator */,
    5220                            Bstr(tr("Deleting files")).raw(),
    5221                            true /* fCancellable */,
    5222                            (ULONG)(pTask->llFilesToDelete.size() + pTask->llMediums.size() + 1),   // cOperations
    5223                            BstrFmt(tr("Deleting '%s'"), pTask->llFilesToDelete.front().c_str()).raw());
    5224 
    5225     int vrc = RTThreadCreate(NULL,
    5226                              Machine::deleteThread,
    5227                              (void*)pTask,
    5228                              0,
    5229                              RTTHREADTYPE_MAIN_WORKER,
    5230                              0,
    5231                              "MachineDelete");
    5232 
    5233     pTask->pProgress.queryInterfaceTo(aProgress.asOutParam());
    5234 
    5235     if (RT_FAILURE(vrc))
    5236     {
    5237         delete pTask;
    5238         return setError(E_FAIL, "Could not create MachineDelete thread (%Rrc)", vrc);
    5239     }
    5240 
    5241     LogFlowFuncLeave();
    5242 
    5243     return S_OK;
    5244 }
    5245 
    52465204/**
    5247  * Static task wrapper passed to RTThreadCreate() in Machine::Delete() which then
    5248  * calls Machine::deleteTaskWorker() on the actual machine object.
    5249  * @param Thread
    5250  * @param pvUser
    5251  * @return
    5252  */
    5253 /*static*/
    5254 DECLCALLBACK(int) Machine::deleteThread(RTTHREAD Thread, void *pvUser)
    5255 {
    5256     LogFlowFuncEnter();
    5257 
    5258     DeleteTask *pTask = (DeleteTask*)pvUser;
    5259     Assert(pTask);
    5260     Assert(pTask->pMachine);
    5261     Assert(pTask->pProgress);
    5262 
    5263     HRESULT rc = pTask->pMachine->i_deleteTaskWorker(*pTask);
    5264     pTask->pProgress->i_notifyComplete(rc);
    5265 
    5266     delete pTask;
    5267 
    5268     LogFlowFuncLeave();
    5269 
    5270     NOREF(Thread);
    5271 
    5272     return VINF_SUCCESS;
    5273 }
    5274 
    5275 /**
    5276  * Task thread implementation for Machine::Delete(), called from Machine::deleteThread().
     5205 * Task thread implementation for SessionMachine::DeleteConfig(), called from
     5206 * SessionMachine::taskHandler().
     5207 *
     5208 * @note Locks this object for writing.
     5209 *
    52775210 * @param task
    52785211 * @return
    52795212 */
    5280 HRESULT Machine::i_deleteTaskWorker(DeleteTask &task)
    5281 {
     5213void Machine::i_deleteConfigHandler(DeleteConfigTask &task)
     5214{
     5215    LogFlowThisFuncEnter();
     5216
    52825217    AutoCaller autoCaller(this);
    5283     if (FAILED(autoCaller.rc())) return autoCaller.rc();
     5218    LogFlowThisFunc(("state=%d\n", getObjectState().getState()));
     5219    if (FAILED(autoCaller.rc()))
     5220    {
     5221        /* we might have been uninitialized because the session was accidentally
     5222         * closed by the client, so don't assert */
     5223        HRESULT rc = setError(E_FAIL,
     5224                              tr("The session has been accidentally closed"));
     5225        task.m_pProgress->i_notifyComplete(rc);
     5226        LogFlowThisFuncLeave();
     5227        return;
     5228    }
    52845229
    52855230    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
     
    53035248        i_setMachineState(MachineState_SettingUp);
    53045249        alock.release();
    5305         for (size_t i = 0; i < task.llMediums.size(); ++i)
    5306         {
    5307             ComObjPtr<Medium> pMedium = (Medium*)(IMedium*)task.llMediums.at(i);
     5250        for (size_t i = 0; i < task.m_llMediums.size(); ++i)
     5251        {
     5252            ComObjPtr<Medium> pMedium = (Medium*)(IMedium*)(task.m_llMediums.at(i));
    53085253            {
    53095254                AutoCaller mac(pMedium);
    53105255                if (FAILED(mac.rc())) throw mac.rc();
    53115256                Utf8Str strLocation = pMedium->i_getLocationFull();
    5312                 rc = task.pProgress->SetNextOperation(BstrFmt(tr("Deleting '%s'"), strLocation.c_str()).raw(), 1);
     5257                rc = task.m_pProgress->SetNextOperation(BstrFmt(tr("Deleting '%s'"), strLocation.c_str()).raw(), 1);
    53135258                if (FAILED(rc)) throw rc;
    53145259                LogFunc(("Deleting file %s\n", strLocation.c_str()));
     
    53195264                rc = pMedium->DeleteStorage(pProgress2.asOutParam());
    53205265                if (FAILED(rc)) throw rc;
    5321                 rc = task.pProgress->WaitForAsyncProgressCompletion(pProgress2);
     5266                rc = task.m_pProgress->WaitForAsyncProgressCompletion(pProgress2);
    53225267                if (FAILED(rc)) throw rc;
    53235268                /* Check the result of the asynchronous process. */
     
    53475292        // medium storage files from the IMedium list passed in, and the
    53485293        // machine XML file)
    5349         StringsList::const_iterator it = task.llFilesToDelete.begin();
    5350         while (it != task.llFilesToDelete.end())
     5294        StringsList::const_iterator it = task.m_llFilesToDelete.begin();
     5295        while (it != task.m_llFilesToDelete.end())
    53515296        {
    53525297            const Utf8Str &strFile = *it;
     
    53585303
    53595304            ++it;
    5360             if (it == task.llFilesToDelete.end())
     5305            if (it == task.m_llFilesToDelete.end())
    53615306            {
    5362                 rc = task.pProgress->SetNextOperation(Bstr(tr("Cleaning up machine directory")).raw(), 1);
     5307                rc = task.m_pProgress->SetNextOperation(Bstr(tr("Cleaning up machine directory")).raw(), 1);
    53635308                if (FAILED(rc)) throw rc;
    53645309                break;
    53655310            }
    53665311
    5367             rc = task.pProgress->SetNextOperation(BstrFmt(tr("Deleting '%s'"), it->c_str()).raw(), 1);
     5312            rc = task.m_pProgress->SetNextOperation(BstrFmt(tr("Deleting '%s'"), it->c_str()).raw(), 1);
    53685313            if (FAILED(rc)) throw rc;
    53695314        }
     
    54385383    catch (HRESULT aRC) { rc = aRC; }
    54395384
    5440     return rc;
     5385    task.m_pProgress->i_notifyComplete(rc);
     5386
     5387    LogFlowThisFuncLeave();
     5388}
     5389
     5390HRESULT Machine::deleteConfig(const std::vector<ComPtr<IMedium> > &aMedia, ComPtr<IProgress> &aProgress)
     5391{
     5392    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
     5393
     5394    HRESULT rc = i_checkStateDependency(MutableStateDep);
     5395    if (FAILED(rc)) return rc;
     5396
     5397    if (mData->mRegistered)
     5398        return setError(VBOX_E_INVALID_VM_STATE,
     5399                        tr("Cannot delete settings of a registered machine"));
     5400
     5401    // collect files to delete
     5402    StringsList llFilesToDelete(mData->llFilesToDelete);    // saved states pushed here by Unregister()
     5403    if (mData->pMachineConfigFile->fileExists())
     5404        llFilesToDelete.push_back(mData->m_strConfigFileFull);
     5405
     5406    RTCList<ComPtr<IMedium> > llMediums;
     5407    for (size_t i = 0; i < aMedia.size(); ++i)
     5408    {
     5409        IMedium *pIMedium(aMedia[i]);
     5410        ComObjPtr<Medium> pMedium = static_cast<Medium*>(pIMedium);
     5411        if (pMedium.isNull())
     5412            return setError(E_INVALIDARG, "The given medium pointer with index %d is invalid", i);
     5413        SafeArray<BSTR> ids;
     5414        rc = pMedium->COMGETTER(MachineIds)(ComSafeArrayAsOutParam(ids));
     5415        if (FAILED(rc)) return rc;
     5416        /* At this point the medium should not have any back references
     5417         * anymore. If it has it is attached to another VM and *must* not
     5418         * deleted. */
     5419        if (ids.size() < 1)
     5420            llMediums.append(pMedium);
     5421    }
     5422
     5423    ComObjPtr<Progress> pProgress;
     5424    pProgress.createObject();
     5425    rc = pProgress->init(i_getVirtualBox(),
     5426                         static_cast<IMachine*>(this) /* aInitiator */,
     5427                         Bstr(tr("Deleting files")).raw(),
     5428                         true /* fCancellable */,
     5429                         (ULONG)(llFilesToDelete.size() + llMediums.size() + 1),   // cOperations
     5430                         BstrFmt(tr("Deleting '%s'"), llFilesToDelete.front().c_str()).raw());
     5431    if (FAILED(rc))
     5432        return rc;
     5433
     5434    /* create and start the task on a separate thread (note that it will not
     5435     * start working until we release alock) */
     5436    DeleteConfigTask *pTask = new DeleteConfigTask(this, pProgress, "DeleteVM", llMediums, llFilesToDelete);
     5437    rc = pTask->createThread();
     5438    if (FAILED(rc))
     5439        return rc;
     5440
     5441    pProgress.queryInterfaceTo(aProgress.asOutParam());
     5442
     5443    LogFlowFuncLeave();
     5444
     5445    return S_OK;
    54415446}
    54425447
     
    55345539                            Global::stringifySessionState(mData->mSession.mState));
    55355540
    5536         directControl = mData->mSession.mDirectControl;
     5541        if (mData->mSession.mLockType == LockType_VM)
     5542            directControl = mData->mSession.mDirectControl;
    55375543    }
    55385544
     
    55565562                            Global::stringifySessionState(mData->mSession.mState));
    55575563
    5558         directControl = mData->mSession.mDirectControl;
     5564        if (mData->mSession.mLockType == LockType_VM)
     5565            directControl = mData->mSession.mDirectControl;
    55595566    }
    55605567
     
    56095616
    56105617    ComPtr<IInternalSessionControl> directControl;
    5611     directControl = mData->mSession.mDirectControl;
    5612 
    5613     /* fail if we were called after #OnSessionEnd() is called.  This is a
    5614      * silly race condition. */
    5615 
    5616     /** @todo This code is bothering API clients (like python script clients) with
    5617      *        the AccessGuestProperty call, creating unncessary IPC.  Need to
    5618      *        have a way of figuring out which kind of direct session it is... */
     5618    {
     5619        AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
     5620        if (mData->mSession.mLockType == LockType_VM)
     5621            directControl = mData->mSession.mDirectControl;
     5622    }
     5623
     5624    /* ignore calls made after #OnSessionEnd() is called */
    56195625    if (!directControl)
    56205626        rc = E_ACCESSDENIED;
     
    57695775    try
    57705776    {
    5771         ComPtr<IInternalSessionControl> directControl = mData->mSession.mDirectControl;
     5777        ComPtr<IInternalSessionControl> directControl;
     5778        {
     5779            AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
     5780            if (mData->mSession.mLockType == LockType_VM)
     5781                directControl = mData->mSession.mDirectControl;
     5782        }
    57725783
    57735784        BSTR dummy = NULL; /* will not be changed (setter) */
     
    58965907    HRESULT rc;
    58975908    ComPtr<IInternalSessionControl> directControl;
    5898     directControl = mData->mSession.mDirectControl;
    5899 
     5909    {
     5910        AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
     5911        if (mData->mSession.mLockType == LockType_VM)
     5912            directControl = mData->mSession.mDirectControl;
     5913    }
    59005914
    59015915    com::SafeArray<BSTR> bNames;
     
    70867100    return rc;
    70877101
     7102}
     7103
     7104HRESULT Machine::saveState(ComPtr<IProgress> &aProgress)
     7105{
     7106    NOREF(aProgress);
     7107    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
     7108
     7109    // This check should always fail.
     7110    HRESULT rc = i_checkStateDependency(MutableStateDep);
     7111    if (FAILED(rc)) return rc;
     7112
     7113    AssertFailedReturn(E_NOTIMPL);
     7114}
     7115
     7116HRESULT Machine::adoptSavedState(const com::Utf8Str &aSavedStateFile)
     7117{
     7118    NOREF(aSavedStateFile);
     7119    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
     7120
     7121    // This check should always fail.
     7122    HRESULT rc = i_checkStateDependency(MutableStateDep);
     7123    if (FAILED(rc)) return rc;
     7124
     7125    AssertFailedReturn(E_NOTIMPL);
     7126}
     7127
     7128HRESULT Machine::discardSavedState(BOOL aFRemoveFile)
     7129{
     7130    NOREF(aFRemoveFile);
     7131    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
     7132
     7133    // This check should always fail.
     7134    HRESULT rc = i_checkStateDependency(MutableStateDep);
     7135    if (FAILED(rc)) return rc;
     7136
     7137    AssertFailedReturn(E_NOTIMPL);
    70887138}
    70897139
     
    77187768    AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    77197769
    7720     if (    mData->mSession.mState == SessionState_Locked
     7770    if (    (   mData->mSession.mState == SessionState_Locked
     7771             && mData->mSession.mLockType == LockType_VM)
    77217772         || (aAllowClosing && mData->mSession.mState == SessionState_Unlocking)
    77227773       )
     
    84198470    LogFlowThisFuncEnter();
    84208471    LogFlowThisFunc(("aMachineState=%s\n", Global::stringifyMachineState(aMachineState) ));
     8472    Assert(aMachineState != MachineState_Null);
    84218473
    84228474    AutoCaller autoCaller(this);
     
    1058110633
    1058210634    /* must be in a protective state because we release the lock below */
    10583     AssertReturn(   mData->mMachineState == MachineState_Saving
     10635    AssertReturn(   mData->mMachineState == MachineState_Snapshotting
     10636                 || mData->mMachineState == MachineState_OnlineSnapshotting
    1058410637                 || mData->mMachineState == MachineState_LiveSnapshotting
    1058510638                 || mData->mMachineState == MachineState_RestoringSnapshot
     
    1067010723                /* copy the attachment as is */
    1067110724
    10672                 /** @todo the progress object created in Console::TakeSnaphot
     10725                /** @todo the progress object created in SessionMachine::TakeSnaphot
    1067310726                 * only expects operations for hard disks. Later other
    1067410727                 * device types need to show up in the progress as well. */
     
    1083210885    /* will release the lock before the potentially lengthy operation,
    1083310886     * so protect with the special state (unless already protected) */
    10834     if (   oldState != MachineState_Saving
     10887    if (   oldState != MachineState_Snapshotting
     10888        && oldState != MachineState_OnlineSnapshotting
    1083510889        && oldState != MachineState_LiveSnapshotting
    1083610890        && oldState != MachineState_RestoringSnapshot
     
    1096911023                mrc = rc;
    1097011024            }
     11025            // Clear the list of deleted implicit attachments now, while not
     11026            // holding the lock, as it will ultimately trigger Medium::uninit()
     11027            // calls which assume that the media tree lock isn't held.
     11028            implicitAtts.clear();
    1097111029
    1097211030            alock.acquire();
     
    1249012548    }
    1249112549
    12492     Assert(    mConsoleTaskData.strStateFilePath.isEmpty()
    12493             || !mConsoleTaskData.mSnapshot);
    12494     if (!mConsoleTaskData.strStateFilePath.isEmpty())
    12495     {
    12496         LogWarningThisFunc(("canceling failed save state request!\n"));
    12497         endSavingState(E_FAIL, tr("Machine terminated with pending save state!"));
    12498     }
    12499     else if (!mConsoleTaskData.mSnapshot.isNull())
    12500     {
    12501         LogWarningThisFunc(("canceling untaken snapshot!\n"));
    12502 
    12503         /* delete all differencing hard disks created (this will also attach
    12504          * their parents back by rolling back mMediaData) */
    12505         i_rollbackMedia();
    12506 
    12507         // delete the saved state file (it might have been already created)
    12508         // AFTER killing the snapshot so that releaseSavedStateFile() won't
    12509         // think it's still in use
    12510         Utf8Str strStateFile = mConsoleTaskData.mSnapshot->i_getStateFilePath();
    12511         mConsoleTaskData.mSnapshot->uninit();
    12512         i_releaseSavedStateFile(strStateFile, NULL /* pSnapshotToIgnore */ );
    12513     }
    12514 
    1251512550    mData->mSession.mPID = NIL_RTPROCESS;
    1251612551
     
    1261312648
    1261412649    /* reset the rest of session data */
     12650    mData->mSession.mLockType = LockType_Null;
    1261512651    mData->mSession.mMachine.setNull();
    1261612652    mData->mSession.mState = SessionState_Unlocked;
     
    1269812734}
    1269912735
     12736////////////////////////////////////////////////////////////////////////////////
     12737//
     12738// SessionMachine task records
     12739//
     12740////////////////////////////////////////////////////////////////////////////////
     12741
     12742/**
     12743 * Task record for saving the machine state.
     12744 */
     12745struct SessionMachine::SaveStateTask
     12746    : public Machine::Task
     12747{
     12748    SaveStateTask(SessionMachine *m,
     12749                  Progress *p,
     12750                  const Utf8Str &t,
     12751                  Reason_T enmReason,
     12752                  const Utf8Str &strStateFilePath)
     12753        : Task(m, p, t),
     12754          m_enmReason(enmReason),
     12755          m_strStateFilePath(strStateFilePath)
     12756    {}
     12757
     12758    void handler()
     12759    {
     12760        ((SessionMachine *)(Machine *)m_pMachine)->i_saveStateHandler(*this);
     12761    }
     12762
     12763    Reason_T m_enmReason;
     12764    Utf8Str m_strStateFilePath;
     12765};
     12766
     12767/**
     12768 * Task thread implementation for SessionMachine::SaveState(), called from
     12769 * SessionMachine::taskHandler().
     12770 *
     12771 * @note Locks this object for writing.
     12772 *
     12773 * @param task
     12774 * @return
     12775 */
     12776void SessionMachine::i_saveStateHandler(SaveStateTask &task)
     12777{
     12778    LogFlowThisFuncEnter();
     12779
     12780    AutoCaller autoCaller(this);
     12781    LogFlowThisFunc(("state=%d\n", getObjectState().getState()));
     12782    if (FAILED(autoCaller.rc()))
     12783    {
     12784        /* we might have been uninitialized because the session was accidentally
     12785         * closed by the client, so don't assert */
     12786        HRESULT rc = setError(E_FAIL,
     12787                              tr("The session has been accidentally closed"));
     12788        task.m_pProgress->i_notifyComplete(rc);
     12789        LogFlowThisFuncLeave();
     12790        return;
     12791    }
     12792
     12793    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
     12794
     12795    HRESULT rc = S_OK;
     12796
     12797    try
     12798    {
     12799        ComPtr<IInternalSessionControl> directControl;
     12800        if (mData->mSession.mLockType == LockType_VM)
     12801            directControl = mData->mSession.mDirectControl;
     12802        if (directControl.isNull())
     12803            throw setError(VBOX_E_INVALID_VM_STATE,
     12804                           tr("Trying to save state without a running VM"));
     12805        alock.release();
     12806        BOOL fSuspendedBySave;
     12807        rc = directControl->SaveStateWithReason(task.m_enmReason, task.m_pProgress, Bstr(task.m_strStateFilePath).raw(), task.m_machineStateBackup != MachineState_Paused, &fSuspendedBySave);
     12808        Assert(!fSuspendedBySave);
     12809        alock.acquire();
     12810
     12811        AssertStmt(   (SUCCEEDED(rc) && mData->mMachineState == MachineState_Saved)
     12812                   || (FAILED(rc) && mData->mMachineState == MachineState_Saving),
     12813                   throw E_FAIL);
     12814
     12815        if (SUCCEEDED(rc))
     12816        {
     12817            mSSData->strStateFilePath = task.m_strStateFilePath;
     12818
     12819            /* save all VM settings */
     12820            rc = i_saveSettings(NULL);
     12821                    // no need to check whether VirtualBox.xml needs saving also since
     12822                    // we can't have a name change pending at this point
     12823        }
     12824        else
     12825        {
     12826            // On failure, set the state to the state we had at the beginning.
     12827            i_setMachineState(task.m_machineStateBackup);
     12828            i_updateMachineStateOnClient();
     12829
     12830            // Delete the saved state file (might have been already created).
     12831            // No need to check whether this is shared with a snapshot here
     12832            // because we certainly created a fresh saved state file here.
     12833            RTFileDelete(task.m_strStateFilePath.c_str());
     12834        }
     12835    }
     12836    catch (HRESULT aRC) { rc = aRC; }
     12837
     12838    task.m_pProgress->i_notifyComplete(rc);
     12839
     12840    LogFlowThisFuncLeave();
     12841}
     12842
    1270012843/**
    1270112844 *  @note Locks this object for writing.
    1270212845 */
    12703 HRESULT SessionMachine::setRemoveSavedStateFile(BOOL aRemove)
     12846HRESULT SessionMachine::saveState(ComPtr<IProgress> &aProgress)
     12847{
     12848    return i_saveStateWithReason(Reason_Unspecified, aProgress);
     12849}
     12850
     12851HRESULT SessionMachine::i_saveStateWithReason(Reason_T aReason, ComPtr<IProgress> &aProgress)
    1270412852{
    1270512853    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    1270612854
    12707     mRemoveSavedState = RT_BOOL(aRemove);
    12708 
    12709     return S_OK;
    12710 }
     12855    HRESULT rc = i_checkStateDependency(MutableOrRunningStateDep);
     12856    if (FAILED(rc)) return rc;
     12857
     12858    if (   mData->mMachineState != MachineState_Running
     12859        && mData->mMachineState != MachineState_Paused
     12860       )
     12861        return setError(VBOX_E_INVALID_VM_STATE,
     12862            tr("Cannot save the execution state as the machine is not running or paused (machine state: %s)"),
     12863            Global::stringifyMachineState(mData->mMachineState));
     12864
     12865    ComObjPtr<Progress> pProgress;
     12866    pProgress.createObject();
     12867    rc = pProgress->init(i_getVirtualBox(),
     12868                         static_cast<IMachine *>(this) /* aInitiator */,
     12869                         Bstr(tr("Saving the execution state of the virtual machine")).raw(),
     12870                         FALSE /* aCancelable */);
     12871    if (FAILED(rc))
     12872        return rc;
     12873
     12874    Utf8Str strStateFilePath;
     12875    i_composeSavedStateFilename(strStateFilePath);
     12876
     12877    /* create and start the task on a separate thread (note that it will not
     12878     * start working until we release alock) */
     12879    SaveStateTask *pTask = new SaveStateTask(this, pProgress, "SaveState", aReason, strStateFilePath);
     12880    rc = pTask->createThread();
     12881    if (FAILED(rc))
     12882        return rc;
     12883
     12884    /* set the state to Saving (expected by Session::SaveStateWithReason()) */
     12885    i_setMachineState(MachineState_Saving);
     12886    i_updateMachineStateOnClient();
     12887
     12888    pProgress.queryInterfaceTo(aProgress.asOutParam());
     12889
     12890    return S_OK;
     12891}
     12892
     12893/**
     12894 *  @note Locks this object for writing.
     12895 */
     12896HRESULT SessionMachine::adoptSavedState(const com::Utf8Str &aSavedStateFile)
     12897{
     12898    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
     12899
     12900    HRESULT rc = i_checkStateDependency(MutableStateDep);
     12901    if (FAILED(rc)) return rc;
     12902
     12903    if (   mData->mMachineState != MachineState_PoweredOff
     12904        && mData->mMachineState != MachineState_Teleported
     12905        && mData->mMachineState != MachineState_Aborted
     12906       )
     12907        return setError(VBOX_E_INVALID_VM_STATE,
     12908            tr("Cannot adopt the saved machine state as the machine is not in Powered Off, Teleported or Aborted state (machine state: %s)"),
     12909            Global::stringifyMachineState(mData->mMachineState));
     12910
     12911    com::Utf8Str stateFilePathFull;
     12912    int vrc = i_calculateFullPath(aSavedStateFile, stateFilePathFull);
     12913    if (RT_FAILURE(vrc))
     12914        return setError(VBOX_E_FILE_ERROR,
     12915                        tr("Invalid saved state file path '%s' (%Rrc)"),
     12916                        aSavedStateFile.c_str(),
     12917                        vrc);
     12918
     12919    mSSData->strStateFilePath = stateFilePathFull;
     12920
     12921    /* The below i_setMachineState() will detect the state transition and will
     12922     * update the settings file */
     12923
     12924    return i_setMachineState(MachineState_Saved);
     12925}
     12926
     12927/**
     12928 *  @note Locks this object for writing.
     12929 */
     12930HRESULT SessionMachine::discardSavedState(BOOL aFRemoveFile)
     12931{
     12932    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
     12933
     12934    HRESULT rc = i_checkStateDependency(MutableStateDep);
     12935    if (FAILED(rc)) return rc;
     12936
     12937    if (mData->mMachineState != MachineState_Saved)
     12938        return setError(VBOX_E_INVALID_VM_STATE,
     12939            tr("Cannot delete the machine state as the machine is not in the saved state (machine state: %s)"),
     12940            Global::stringifyMachineState(mData->mMachineState));
     12941
     12942    mRemoveSavedState = RT_BOOL(aFRemoveFile);
     12943
     12944    /*
     12945     * Saved -> PoweredOff transition will be detected in the SessionMachine
     12946     * and properly handled.
     12947     */
     12948    rc = i_setMachineState(MachineState_PoweredOff);
     12949    return rc;
     12950}
     12951
    1271112952
    1271212953/**
     
    1308713328}
    1308813329
    13089 /**
    13090  *  @note Locks this object for writing.
    13091  */
    13092 HRESULT SessionMachine::beginSavingState(ComPtr<IProgress> &aProgress,
    13093                                          com::Utf8Str &aStateFilePath)
    13094 {
    13095     LogFlowThisFuncEnter();
    13096 
    13097     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    13098 
    13099     AssertReturn(    mData->mMachineState == MachineState_Paused
    13100                   && mConsoleTaskData.mLastState == MachineState_Null
    13101                   && mConsoleTaskData.strStateFilePath.isEmpty(),
    13102                  E_FAIL);
    13103 
    13104     /* create a progress object to track operation completion */
    13105     ComObjPtr<Progress> pProgress;
    13106     pProgress.createObject();
    13107     pProgress->init(i_getVirtualBox(),
    13108                     static_cast<IMachine *>(this) /* aInitiator */,
    13109                     Bstr(tr("Saving the execution state of the virtual machine")).raw(),
    13110                     FALSE /* aCancelable */);
    13111 
    13112     /* stateFilePath is null when the machine is not running */
    13113     if (mData->mMachineState == MachineState_Paused)
    13114         i_composeSavedStateFilename(aStateFilePath);
    13115 
    13116     /* fill in the console task data */
    13117     mConsoleTaskData.mLastState = mData->mMachineState;
    13118     mConsoleTaskData.strStateFilePath = aStateFilePath;
    13119     mConsoleTaskData.mProgress = pProgress;
    13120 
    13121     /* set the state to Saving (this is expected by Console::SaveState()) */
    13122     i_setMachineState(MachineState_Saving);
    13123 
    13124     pProgress.queryInterfaceTo(aProgress.asOutParam());
    13125 
    13126     return S_OK;
    13127 }
    13128 
    13129 /**
    13130  *  @note Locks mParent + this object for writing.
    13131  */
    13132 HRESULT SessionMachine::endSavingState(LONG aResult,
    13133                                        const com::Utf8Str &aErrMsg)
    13134 {
    13135     LogFlowThisFunc(("\n"));
    13136 
    13137     /* endSavingState() need mParent lock */
    13138     AutoMultiWriteLock2 alock(mParent, this COMMA_LOCKVAL_SRC_POS);
    13139 
    13140     AssertReturn(    (   (SUCCEEDED(aResult) && mData->mMachineState == MachineState_Saved)
    13141                       || (FAILED(aResult) && mData->mMachineState == MachineState_Saving))
    13142                   && mConsoleTaskData.mLastState != MachineState_Null
    13143                   && !mConsoleTaskData.strStateFilePath.isEmpty(),
    13144                  E_FAIL);
    13145 
    13146     /*
    13147      * On failure, set the state to the state we had when BeginSavingState()
    13148      * was called (this is expected by Console::SaveState() and the associated
    13149      * task). On success the VM process already changed the state to
    13150      * MachineState_Saved, so no need to do anything.
    13151      */
    13152     if (FAILED(aResult))
    13153         i_setMachineState(mConsoleTaskData.mLastState);
    13154 
    13155     return i_endSavingState(aResult, aErrMsg);
    13156 }
    13157 
    13158 /**
    13159  *  @note Locks this object for writing.
    13160  */
    13161 HRESULT SessionMachine::adoptSavedState(const com::Utf8Str &aSavedStateFile)
    13162 {
    13163     LogFlowThisFunc(("\n"));
    13164 
    13165     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    13166 
    13167     AssertReturn(   mData->mMachineState == MachineState_PoweredOff
    13168                  || mData->mMachineState == MachineState_Teleported
    13169                  || mData->mMachineState == MachineState_Aborted
    13170                  , E_FAIL); /** @todo setError. */
    13171 
    13172     com::Utf8Str stateFilePathFull;
    13173     int vrc = i_calculateFullPath(aSavedStateFile, stateFilePathFull);
    13174     if (RT_FAILURE(vrc))
    13175         return setError(VBOX_E_FILE_ERROR,
    13176                         tr("Invalid saved state file path '%s' (%Rrc)"),
    13177                         aSavedStateFile.c_str(),
    13178                         vrc);
    13179 
    13180     mSSData->strStateFilePath = stateFilePathFull;
    13181 
    13182     /* The below i_setMachineState() will detect the state transition and will
    13183      * update the settings file */
    13184 
    13185     return i_setMachineState(MachineState_Saved);
    13186 }
    13187 
    1318813330HRESULT SessionMachine::pullGuestProperties(std::vector<com::Utf8Str> &aNames,
    1318913331                                            std::vector<com::Utf8Str> &aValues,
     
    1326313405            case MachineState_Teleporting:
    1326413406            case MachineState_TeleportingPausedVM:
     13407            case MachineState_OnlineSnapshotting:
    1326513408            case MachineState_LiveSnapshotting:
    1326613409            case MachineState_DeletingSnapshotOnline:
     
    1353613679    {
    1353713680        AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    13538         directControl = mData->mSession.mDirectControl;
     13681        if (mData->mSession.mLockType == LockType_VM)
     13682            directControl = mData->mSession.mDirectControl;
    1353913683    }
    1354013684
     
    1356113705    {
    1356213706        AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    13563         directControl = mData->mSession.mDirectControl;
     13707        if (mData->mSession.mLockType == LockType_VM)
     13708            directControl = mData->mSession.mDirectControl;
    1356413709    }
    1356513710
     
    1358913734    {
    1359013735        AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    13591         directControl = mData->mSession.mDirectControl;
     13736        if (mData->mSession.mLockType == LockType_VM)
     13737            directControl = mData->mSession.mDirectControl;
    1359213738    }
    1359313739
     
    1361213758    {
    1361313759        AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    13614         directControl = mData->mSession.mDirectControl;
     13760        if (mData->mSession.mLockType == LockType_VM)
     13761            directControl = mData->mSession.mDirectControl;
    1361513762    }
    1361613763
     
    1363513782    {
    1363613783        AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    13637         directControl = mData->mSession.mDirectControl;
     13784        if (mData->mSession.mLockType == LockType_VM)
     13785            directControl = mData->mSession.mDirectControl;
    1363813786    }
    1363913787
     
    1365813806    {
    1365913807        AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    13660         directControl = mData->mSession.mDirectControl;
     13808        if (mData->mSession.mLockType == LockType_VM)
     13809            directControl = mData->mSession.mDirectControl;
    1366113810    }
    1366213811
     
    1368113830    {
    1368213831        AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    13683         directControl = mData->mSession.mDirectControl;
     13832        if (mData->mSession.mLockType == LockType_VM)
     13833            directControl = mData->mSession.mDirectControl;
    1368413834    }
    1368513835
     
    1370113851    {
    1370213852        AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    13703         directControl = mData->mSession.mDirectControl;
     13853        if (mData->mSession.mLockType == LockType_VM)
     13854            directControl = mData->mSession.mDirectControl;
    1370413855    }
    1370513856
     
    1372413875    {
    1372513876        AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    13726         directControl = mData->mSession.mDirectControl;
     13877        if (mData->mSession.mLockType == LockType_VM)
     13878            directControl = mData->mSession.mDirectControl;
    1372713879    }
    1372813880
     
    1374713899    {
    1374813900        AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    13749         directControl = mData->mSession.mDirectControl;
     13901        if (mData->mSession.mLockType == LockType_VM)
     13902            directControl = mData->mSession.mDirectControl;
    1375013903    }
    1375113904
     
    1377013923    {
    1377113924        AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    13772         directControl = mData->mSession.mDirectControl;
     13925        if (mData->mSession.mLockType == LockType_VM)
     13926            directControl = mData->mSession.mDirectControl;
    1377313927    }
    1377413928
     
    1379313947    {
    1379413948        AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    13795         directControl = mData->mSession.mDirectControl;
     13949        if (mData->mSession.mLockType == LockType_VM)
     13950            directControl = mData->mSession.mDirectControl;
    1379613951    }
    1379713952
     
    1381613971    {
    1381713972        AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    13818         directControl = mData->mSession.mDirectControl;
     13973        if (mData->mSession.mLockType == LockType_VM)
     13974            directControl = mData->mSession.mDirectControl;
    1381913975    }
    1382013976
     
    1383913995    {
    1384013996        AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    13841         directControl = mData->mSession.mDirectControl;
     13997        if (mData->mSession.mLockType == LockType_VM)
     13998            directControl = mData->mSession.mDirectControl;
    1384213999    }
    1384314000
     
    1386214019    {
    1386314020        AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    13864         directControl = mData->mSession.mDirectControl;
     14021        if (mData->mSession.mLockType == LockType_VM)
     14022            directControl = mData->mSession.mDirectControl;
    1386514023    }
    1386614024
     
    1388514043    {
    1388614044        AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    13887         directControl = mData->mSession.mDirectControl;
     14045        if (mData->mSession.mLockType == LockType_VM)
     14046            directControl = mData->mSession.mDirectControl;
    1388814047    }
    1388914048
     
    1395114110    {
    1395214111        AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    13953         directControl = mData->mSession.mDirectControl;
     14112        if (mData->mSession.mLockType == LockType_VM)
     14113            directControl = mData->mSession.mDirectControl;
    1395414114    }
    1395514115
     
    1398314143    {
    1398414144        AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    13985         directControl = mData->mSession.mDirectControl;
     14145        if (mData->mSession.mLockType == LockType_VM)
     14146            directControl = mData->mSession.mDirectControl;
    1398614147    }
    1398714148
     
    1400014161// protected methods
    1400114162/////////////////////////////////////////////////////////////////////////////
    14002 
    14003 /**
    14004  *  Helper method to finalize saving the state.
    14005  *
    14006  *  @note Must be called from under this object's lock.
    14007  *
    14008  *  @param aRc      S_OK if the snapshot has been taken successfully
    14009  *  @param aErrMsg  human readable error message for failure
    14010  *
    14011  *  @note Locks mParent + this objects for writing.
    14012  */
    14013 HRESULT SessionMachine::i_endSavingState(HRESULT aRc, const Utf8Str &aErrMsg)
    14014 {
    14015     LogFlowThisFuncEnter();
    14016 
    14017     AutoCaller autoCaller(this);
    14018     AssertComRCReturn(autoCaller.rc(), autoCaller.rc());
    14019 
    14020     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    14021 
    14022     HRESULT rc = S_OK;
    14023 
    14024     if (SUCCEEDED(aRc))
    14025     {
    14026         mSSData->strStateFilePath = mConsoleTaskData.strStateFilePath;
    14027 
    14028         /* save all VM settings */
    14029         rc = i_saveSettings(NULL);
    14030                 // no need to check whether VirtualBox.xml needs saving also since
    14031                 // we can't have a name change pending at this point
    14032     }
    14033     else
    14034     {
    14035         // delete the saved state file (it might have been already created);
    14036         // we need not check whether this is shared with a snapshot here because
    14037         // we certainly created this saved state file here anew
    14038         RTFileDelete(mConsoleTaskData.strStateFilePath.c_str());
    14039     }
    14040 
    14041     /* notify the progress object about operation completion */
    14042     Assert(mConsoleTaskData.mProgress);
    14043     if (SUCCEEDED(aRc))
    14044         mConsoleTaskData.mProgress->i_notifyComplete(S_OK);
    14045     else
    14046     {
    14047         if (aErrMsg.length())
    14048             mConsoleTaskData.mProgress->i_notifyComplete(aRc,
    14049                                                          COM_IIDOF(ISession),
    14050                                                          getComponentName(),
    14051                                                          aErrMsg.c_str());
    14052         else
    14053             mConsoleTaskData.mProgress->i_notifyComplete(aRc);
    14054     }
    14055 
    14056     /* clear out the temporary saved state data */
    14057     mConsoleTaskData.mLastState = MachineState_Null;
    14058     mConsoleTaskData.strStateFilePath.setNull();
    14059     mConsoleTaskData.mProgress.setNull();
    14060 
    14061     LogFlowThisFuncLeave();
    14062     return rc;
    14063 }
    1406414163
    1406514164/**
     
    1425914358                 || oldMachineState == MachineState_Paused
    1426014359                 || oldMachineState == MachineState_Teleporting
     14360                 || oldMachineState == MachineState_OnlineSnapshotting
    1426114361                 || oldMachineState == MachineState_LiveSnapshotting
    1426214362                 || oldMachineState == MachineState_Stuck
     
    1427314373                 || aMachineState == MachineState_Aborted
    1427414374                )
    14275              /* ignore PoweredOff->Saving->PoweredOff transition when taking a
    14276               * snapshot */
    14277              && (   mConsoleTaskData.mSnapshot.isNull()
    14278                  || mConsoleTaskData.mLastState >= MachineState_Running /** @todo Live Migration: clean up (lazy bird) */
    14279                 )
    1428014375            )
    1428114376    {
     
    1431014405    {
    1431114406        /*
    14312          *  delete the saved state after Console::ForgetSavedState() is called
     14407         *  delete the saved state after SessionMachine::ForgetSavedState() is called
    1431314408         *  or if the VM process (owning a direct VM session) crashed while the
    1431414409         *  VM was Saved
     
    1445614551        AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    1445714552        AssertReturn(!!mData, E_FAIL);
    14458         directControl = mData->mSession.mDirectControl;
     14553        if (mData->mSession.mLockType == LockType_VM)
     14554            directControl = mData->mSession.mDirectControl;
    1445914555
    1446014556        /* directControl may be already set to NULL here in #OnSessionEnd()
     
    1446914565        if (mData->mSession.mState == SessionState_Unlocking)
    1447014566            return S_OK;
    14471 
    14472         AssertReturn(!directControl.isNull(), E_FAIL);
    14473     }
     14567    }
     14568
     14569    /* ignore notifications sent after #OnSessionEnd() is called */
     14570    if (!directControl)
     14571        return S_OK;
    1447414572
    1447514573    return directControl->UpdateMachineState(mData->mMachineState);
    1447614574}
    1447714575
    14478 HRESULT Machine::setRemoveSavedStateFile(BOOL aRemove)
    14479 {
    14480     NOREF(aRemove);
    14481     ReturnComNotImplemented();
    14482 }
     14576
     14577/**
     14578 * Static Machine method that can get passed to RTThreadCreate to
     14579 * have a thread started for a Task. See Machine::Task.
     14580 */
     14581/* static */ DECLCALLBACK(int) Machine::taskHandler(RTTHREAD /* thread */, void *pvUser)
     14582{
     14583    AssertReturn(pvUser, VERR_INVALID_POINTER);
     14584
     14585    Task *pTask = static_cast<Task *>(pvUser);
     14586    pTask->handler();
     14587    /** @todo r=klaus it would be safer to update the progress object here,
     14588     * as it avoids possible races due to scoping issues/tricks in the handler */
     14589    // it's our responsibility to delete the task
     14590    delete pTask;
     14591
     14592    return 0;
     14593}
     14594
     14595/*static*/
     14596HRESULT Machine::i_setErrorStatic(HRESULT aResultCode, const char *pcszMsg, ...)
     14597{
     14598    va_list args;
     14599    va_start(args, pcszMsg);
     14600    HRESULT rc = setErrorInternal(aResultCode,
     14601                                  getStaticClassIID(),
     14602                                  getStaticComponentName(),
     14603                                  Utf8Str(pcszMsg, args),
     14604                                  false /* aWarning */,
     14605                                  true /* aLogIt */);
     14606    va_end(args);
     14607    return rc;
     14608}
     14609
    1448314610
    1448414611HRESULT Machine::updateState(MachineState_T aState)
     
    1455814685}
    1455914686
    14560 HRESULT Machine::beginSavingState(ComPtr<IProgress> &aProgress,
    14561                                   com::Utf8Str &aStateFilePath)
    14562 {
    14563     NOREF(aProgress);
    14564     NOREF(aStateFilePath);
    14565     ReturnComNotImplemented();
    14566 }
    14567 
    14568 HRESULT Machine::endSavingState(LONG aResult,
    14569                                 const com::Utf8Str &aErrMsg)
    14570 {
    14571     NOREF(aResult);
    14572     NOREF(aErrMsg);
    14573     ReturnComNotImplemented();
    14574 }
    14575 
    14576 HRESULT Machine::adoptSavedState(const com::Utf8Str &aSavedStateFile)
    14577 {
    14578     NOREF(aSavedStateFile);
    14579     ReturnComNotImplemented();
    14580 }
    14581 
    14582 HRESULT Machine::beginTakingSnapshot(const ComPtr<IConsole> &aInitiator,
    14583                                      const com::Utf8Str &aName,
    14584                                      const com::Utf8Str &aDescription,
    14585                                      const ComPtr<IProgress> &aConsoleProgress,
    14586                                      BOOL aFTakingSnapshotOnline,
    14587                                      com::Utf8Str &aStateFilePath)
    14588 {
    14589     NOREF(aInitiator);
    14590     NOREF(aName);
    14591     NOREF(aDescription);
    14592     NOREF(aConsoleProgress);
    14593     NOREF(aFTakingSnapshotOnline);
    14594     NOREF(aStateFilePath);
    14595     ReturnComNotImplemented();
    14596 }
    14597 
    14598 HRESULT Machine::endTakingSnapshot(BOOL aSuccess)
    14599 {
    14600     NOREF(aSuccess);
    14601     ReturnComNotImplemented();
    14602 }
    14603 
    14604 HRESULT Machine::deleteSnapshot(const ComPtr<IConsole> &aInitiator,
    14605                                 const com::Guid &aStartId,
    14606                                 const com::Guid &aEndId,
    14607                                 BOOL aDeleteAllChildren,
    14608                                 MachineState_T *aMachineState,
    14609                                 ComPtr<IProgress> &aProgress)
    14610 {
    14611     NOREF(aInitiator);
    14612     NOREF(aStartId);
    14613     NOREF(aEndId);
    14614     NOREF(aDeleteAllChildren);
    14615     NOREF(aMachineState);
    14616     NOREF(aProgress);
    14617     ReturnComNotImplemented();
    14618 }
    14619 
    1462014687HRESULT Machine::finishOnlineMergeMedium()
    1462114688{
    14622     ReturnComNotImplemented();
    14623 }
    14624 
    14625 HRESULT Machine::restoreSnapshot(const ComPtr<IConsole> &aInitiator,
    14626                                  const ComPtr<ISnapshot> &aSnapshot,
    14627                                  MachineState_T *aMachineState,
    14628                                  ComPtr<IProgress> &aProgress)
    14629 {
    14630     NOREF(aInitiator);
    14631     NOREF(aSnapshot);
    14632     NOREF(aMachineState);
    14633     NOREF(aProgress);
    1463414689    ReturnComNotImplemented();
    1463514690}
  • trunk/src/VBox/Main/src-server/Performance.cpp

    r51498 r55214  
    55
    66/*
    7  * Copyright (C) 2008-2014 Oracle Corporation
     7 * Copyright (C) 2008-2015 Oracle Corporation
    88 *
    99 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    311311
    312312        /* get the associated console; this is a remote call (!) */
    313         ret = directControl->GetRemoteConsole(mConsole.asOutParam());
     313        ret = directControl->COMGETTER(RemoteConsole)(mConsole.asOutParam());
    314314        if (ret != S_OK)
    315315            return ret;
  • trunk/src/VBox/Main/src-server/SnapshotImpl.cpp

    r54948 r55214  
    412412}
    413413
    414 HRESULT Snapshot::getChildrenCount(ULONG* count)
     414HRESULT Snapshot::getChildrenCount(ULONG *count)
    415415{
    416416    *count = i_getChildrenCount();
     
    13051305
    13061306/**
    1307  * Abstract base class for SessionMachine::RestoreSnapshotTask and
    1308  * SessionMachine::DeleteSnapshotTask. This is necessary since
    1309  * RTThreadCreate cannot call a method as its thread function, so
    1310  * instead we have it call the static SessionMachine::taskHandler,
    1311  * which can then call the handler() method in here (implemented
    1312  * by the children).
     1307 * Still abstract base class for SessionMachine::TakeSnapshotTask,
     1308 * SessionMachine::RestoreSnapshotTask and SessionMachine::DeleteSnapshotTask.
    13131309 */
    13141310struct SessionMachine::SnapshotTask
     1311    : public SessionMachine::Task
    13151312{
    13161313    SnapshotTask(SessionMachine *m,
    13171314                 Progress *p,
     1315                 const Utf8Str &t,
    13181316                 Snapshot *s)
    1319         : pMachine(m),
    1320           pProgress(p),
    1321           machineStateBackup(m->mData->mMachineState), // save the current machine state
    1322           pSnapshot(s)
     1317        : Task(m, p, t),
     1318          m_pSnapshot(s)
    13231319    {}
    13241320
    1325     void modifyBackedUpState(MachineState_T s)
    1326     {
    1327         *const_cast<MachineState_T*>(&machineStateBackup) = s;
    1328     }
    1329 
    1330     virtual void handler() = 0;
    1331 
    1332     ComObjPtr<SessionMachine>       pMachine;
    1333     ComObjPtr<Progress>             pProgress;
    1334     const MachineState_T            machineStateBackup;
    1335     ComObjPtr<Snapshot>             pSnapshot;
     1321    ComObjPtr<Snapshot> m_pSnapshot;
    13361322};
    13371323
    1338 /** Restore snapshot state task */
     1324/** Take snapshot task */
     1325struct SessionMachine::TakeSnapshotTask
     1326    : public SessionMachine::SnapshotTask
     1327{
     1328    TakeSnapshotTask(SessionMachine *m,
     1329                     Progress *p,
     1330                     const Utf8Str &t,
     1331                     Snapshot *s,
     1332                     const Utf8Str &strName,
     1333                     const Utf8Str &strDescription,
     1334                     bool fPause,
     1335                     uint32_t uMemSize,
     1336                     bool fTakingSnapshotOnline)
     1337        : SnapshotTask(m, p, t, s),
     1338          m_strName(strName),
     1339          m_strDescription(strDescription),
     1340          m_fPause(fPause),
     1341          m_uMemSize(uMemSize),
     1342          m_fTakingSnapshotOnline(fTakingSnapshotOnline)
     1343    {
     1344        if (fTakingSnapshotOnline)
     1345            m_pDirectControl = m->mData->mSession.mDirectControl;
     1346    }
     1347
     1348    void handler()
     1349    {
     1350        ((SessionMachine *)(Machine *)m_pMachine)->i_takeSnapshotHandler(*this);
     1351    }
     1352
     1353    Utf8Str m_strName;
     1354    Utf8Str m_strDescription;
     1355    Utf8Str m_strStateFilePath;
     1356    ComPtr<IInternalSessionControl> m_pDirectControl;
     1357    bool m_fPause;
     1358    uint32_t m_uMemSize;
     1359    bool m_fTakingSnapshotOnline;
     1360};
     1361
     1362/** Restore snapshot task */
    13391363struct SessionMachine::RestoreSnapshotTask
    13401364    : public SessionMachine::SnapshotTask
     
    13421366    RestoreSnapshotTask(SessionMachine *m,
    13431367                        Progress *p,
     1368                        const Utf8Str &t,
    13441369                        Snapshot *s)
    1345         : SnapshotTask(m, p, s)
     1370        : SnapshotTask(m, p, t, s)
    13461371    {}
    13471372
    13481373    void handler()
    13491374    {
    1350         pMachine->i_restoreSnapshotHandler(*this);
     1375        ((SessionMachine *)(Machine *)m_pMachine)->i_restoreSnapshotHandler(*this);
    13511376    }
    13521377};
     
    13581383    DeleteSnapshotTask(SessionMachine *m,
    13591384                       Progress *p,
     1385                       const Utf8Str &t,
    13601386                       bool fDeleteOnline,
    13611387                       Snapshot *s)
    1362         : SnapshotTask(m, p, s),
     1388        : SnapshotTask(m, p, t, s),
    13631389          m_fDeleteOnline(fDeleteOnline)
    13641390    {}
     
    13661392    void handler()
    13671393    {
    1368         pMachine->i_deleteSnapshotHandler(*this);
     1394        ((SessionMachine *)(Machine *)m_pMachine)->i_deleteSnapshotHandler(*this);
    13691395    }
    13701396
     
    13721398};
    13731399
    1374 /**
    1375  * Static SessionMachine method that can get passed to RTThreadCreate to
    1376  * have a thread started for a SnapshotTask. See SnapshotTask above.
    1377  *
    1378  * This calls either RestoreSnapshotTask::handler() or DeleteSnapshotTask::handler().
    1379  */
    1380 
    1381 /* static */ DECLCALLBACK(int) SessionMachine::taskHandler(RTTHREAD /* thread */, void *pvUser)
    1382 {
    1383     AssertReturn(pvUser, VERR_INVALID_POINTER);
    1384 
    1385     SnapshotTask *task = static_cast<SnapshotTask*>(pvUser);
    1386     task->handler();
    1387 
    1388     // it's our responsibility to delete the task
    1389     delete task;
    1390 
    1391     return 0;
    1392 }
    13931400
    13941401////////////////////////////////////////////////////////////////////////////////
    13951402//
    1396 // TakeSnapshot methods (SessionMachine and related tasks)
     1403// TakeSnapshot methods (Machine and related tasks)
    13971404//
    13981405////////////////////////////////////////////////////////////////////////////////
    13991406
    1400 /**
    1401  * Implementation for IInternalMachineControl::beginTakingSnapshot().
    1402  *
    1403  * Gets called indirectly from Console::TakeSnapshot, which creates a
    1404  * progress object in the client and then starts a thread
    1405  * (Console::fntTakeSnapshotWorker) which then calls this.
    1406  *
    1407  * In other words, the asynchronous work for taking snapshots takes place
    1408  * on the _client_ (in the Console). This is different from restoring
    1409  * or deleting snapshots, which start threads on the server.
    1410  *
    1411  * This does the server-side work of taking a snapshot: it creates differencing
    1412  * images for all hard disks attached to the machine and then creates a
    1413  * Snapshot object with a corresponding SnapshotMachine to save the VM settings.
    1414  *
    1415  * The client's fntTakeSnapshotWorker() blocks while this takes place.
    1416  * After this returns successfully, fntTakeSnapshotWorker() will begin
    1417  * saving the machine state to the snapshot object and reconfigure the
    1418  * hard disks.
    1419  *
    1420  * When the console is done, it calls SessionMachine::EndTakingSnapshot().
    1421  *
    1422  * @note Locks mParent + this object for writing.
    1423  *
    1424  * @param aInitiator in: The console on which Console::TakeSnapshot was called.
    1425  * @param aName  in: The name for the new snapshot.
    1426  * @param aDescription  in: A description for the new snapshot.
    1427  * @param aConsoleProgress  in: The console's (client's) progress object.
    1428  * @param fTakingSnapshotOnline  in: True if an online snapshot is being taken (i.e. machine is running).
    1429  * @param aStateFilePath out: name of file in snapshots folder to which the console should write the VM state.
     1407HRESULT Machine::takeSnapshot(const com::Utf8Str &aName,
     1408                              const com::Utf8Str &aDescription,
     1409                              BOOL fPause,
     1410                              ComPtr<IProgress> &aProgress)
     1411{
     1412    NOREF(aName);
     1413    NOREF(aDescription);
     1414    NOREF(fPause);
     1415    NOREF(aProgress);
     1416    ReturnComNotImplemented();
     1417}
     1418
     1419HRESULT SessionMachine::takeSnapshot(const com::Utf8Str &aName,
     1420                                     const com::Utf8Str &aDescription,
     1421                                     BOOL fPause,
     1422                                     ComPtr<IProgress> &aProgress)
     1423{
     1424    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
     1425    LogFlowThisFunc(("aName='%s' mMachineState=%d\n", aName.c_str(), mData->mMachineState));
     1426
     1427    if (Global::IsTransient(mData->mMachineState))
     1428        return setError(VBOX_E_INVALID_VM_STATE,
     1429                        tr("Cannot take a snapshot of the machine while it is changing the state (machine state: %s)"),
     1430                        Global::stringifyMachineState(mData->mMachineState));
     1431
     1432    HRESULT rc = S_OK;
     1433
     1434    // prepare the progress object:
     1435    // a) count the no. of hard disk attachments to get a matching no. of progress sub-operations
     1436    ULONG cOperations = 2;              // always at least setting up + finishing up
     1437    ULONG ulTotalOperationsWeight = 2;  // one each for setting up + finishing up
     1438
     1439    for (MediaData::AttachmentList::iterator it = mMediaData->mAttachments.begin();
     1440         it != mMediaData->mAttachments.end();
     1441         ++it)
     1442    {
     1443        const ComObjPtr<MediumAttachment> pAtt(*it);
     1444        AutoReadLock attlock(pAtt COMMA_LOCKVAL_SRC_POS);
     1445        AutoCaller attCaller(pAtt);
     1446        if (pAtt->i_getType() == DeviceType_HardDisk)
     1447        {
     1448            ++cOperations;
     1449
     1450            // assume that creating a diff image takes as long as saving a 1MB state
     1451            ulTotalOperationsWeight += 1;
     1452        }
     1453    }
     1454
     1455    // b) one extra sub-operations for online snapshots OR offline snapshots that have a saved state (needs to be copied)
     1456    const bool fTakingSnapshotOnline = Global::IsOnline(mData->mMachineState);
     1457    LogFlowThisFunc(("fTakingSnapshotOnline = %d\n", fTakingSnapshotOnline));
     1458    if (fTakingSnapshotOnline)
     1459    {
     1460        ++cOperations;
     1461        ulTotalOperationsWeight += mHWData->mMemorySize;
     1462    }
     1463
     1464    // finally, create the progress object
     1465    ComObjPtr<Progress> pProgress;
     1466    pProgress.createObject();
     1467    rc = pProgress->init(mParent,
     1468                         static_cast<IMachine *>(this),
     1469                         Bstr(tr("Taking a snapshot of the virtual machine")).raw(),
     1470                         fTakingSnapshotOnline /* aCancelable */,
     1471                         cOperations,
     1472                         ulTotalOperationsWeight,
     1473                         Bstr(tr("Setting up snapshot operation")).raw(),      // first sub-op description
     1474                         1);        // ulFirstOperationWeight
     1475    if (FAILED(rc))
     1476        return rc;
     1477
     1478    /* create and start the task on a separate thread (note that it will not
     1479     * start working until we release alock) */
     1480    TakeSnapshotTask *pTask = new TakeSnapshotTask(this,
     1481                                                   pProgress,
     1482                                                   "TakeSnap",
     1483                                                   NULL /* pSnapshot */,
     1484                                                   aName,
     1485                                                   aDescription,
     1486                                                   !!fPause,
     1487                                                   mHWData->mMemorySize,
     1488                                                   fTakingSnapshotOnline);
     1489    rc = pTask->createThread();
     1490    if (FAILED(rc))
     1491        return rc;
     1492
     1493    /* set the proper machine state (note: after creating a Task instance) */
     1494    if (fTakingSnapshotOnline)
     1495    {
     1496        if (pTask->m_machineStateBackup != MachineState_Paused && !fPause)
     1497            i_setMachineState(MachineState_LiveSnapshotting);
     1498        else
     1499            i_setMachineState(MachineState_OnlineSnapshotting);
     1500        i_updateMachineStateOnClient();
     1501    }
     1502    else
     1503        i_setMachineState(MachineState_Snapshotting);
     1504
     1505    pTask->m_pProgress.queryInterfaceTo(aProgress.asOutParam());
     1506
     1507    return rc;
     1508}
     1509
     1510/**
     1511 * Task thread implementation for SessionMachine::TakeSnapshot(), called from
     1512 * SessionMachine::taskHandler().
     1513 *
     1514 * @note Locks this object for writing.
     1515 *
     1516 * @param task
    14301517 * @return
    14311518 */
    1432 HRESULT SessionMachine::beginTakingSnapshot(const ComPtr<IConsole> &aInitiator,
    1433                                             const com::Utf8Str &aName,
    1434                                             const com::Utf8Str &aDescription,
    1435                                             const ComPtr<IProgress> &aConsoleProgress,
    1436                                             BOOL  aFTakingSnapshotOnline,
    1437                                             com::Utf8Str &aStateFilePath)
    1438 {
    1439     NOREF(aInitiator);
     1519void SessionMachine::i_takeSnapshotHandler(TakeSnapshotTask &task)
     1520{
    14401521    LogFlowThisFuncEnter();
    14411522
    1442     LogFlowThisFunc(("aName='%s' aFTakingSnapshotOnline=%RTbool\n", aName.c_str(), aFTakingSnapshotOnline));
     1523    // Taking a snapshot consists of the following:
     1524    // 1) creating a Snapshot object with the current state of the machine
     1525    //    (hardware + storage)
     1526    // 2) creating a diff image for each virtual hard disk, into which write
     1527    //    operations go after the snapshot has been created
     1528    // 3) if the machine is online: saving the state of the virtual machine
     1529    //    (in the VM process)
     1530    // 4) reattach the hard disks
     1531    // 5) update the various snapshot/machine objects, save settings
     1532
     1533    HRESULT rc = S_OK;
     1534    AutoCaller autoCaller(this);
     1535    LogFlowThisFunc(("state=%d\n", getObjectState().getState()));
     1536    if (FAILED(autoCaller.rc()))
     1537    {
     1538        /* we might have been uninitialized because the session was accidentally
     1539         * closed by the client, so don't assert */
     1540        rc = setError(E_FAIL,
     1541                      tr("The session has been accidentally closed"));
     1542        task.m_pProgress->i_notifyComplete(rc);
     1543        LogFlowThisFuncLeave();
     1544        return;
     1545    }
    14431546
    14441547    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    14451548
    1446     AssertReturn(    !Global::IsOnlineOrTransient(mData->mMachineState)
    1447                   || mData->mMachineState == MachineState_Running
    1448                   || mData->mMachineState == MachineState_Paused, E_FAIL);
    1449     AssertReturn(mConsoleTaskData.mLastState == MachineState_Null, E_FAIL);
    1450     AssertReturn(mConsoleTaskData.mSnapshot.isNull(), E_FAIL);
    1451 
    1452     if (   mData->mCurrentSnapshot
    1453         && mData->mCurrentSnapshot->i_getDepth() >= SETTINGS_SNAPSHOT_DEPTH_MAX)
    1454     {
    1455 
    1456         return setError(VBOX_E_INVALID_OBJECT_STATE,
    1457                         tr("Cannot take another snapshot for machine '%s', because it exceeds the maximum snapshot depth limit. Please delete some earlier snapshot which you no longer need"),
    1458                         mUserData->s.strName.c_str());
    1459     }
    1460 
    1461     if (    !aFTakingSnapshotOnline
    1462          && mData->mMachineState != MachineState_Saved
    1463        )
    1464     {
    1465         /* save all current settings to ensure current changes are committed and
    1466          * hard disks are fixed up */
    1467         HRESULT rc = i_saveSettings(NULL);
     1549    bool fBeganTakingSnapshot = false;
     1550    BOOL fSuspendedBySave     = FALSE;
     1551
     1552    try
     1553    {
     1554        // @todo: at this point we have to be in the right state!!!!
     1555        AssertStmt(   !Global::IsOnlineOrTransient(mData->mMachineState)
     1556                   || mData->mMachineState == MachineState_Snapshotting
     1557                   || mData->mMachineState == MachineState_OnlineSnapshotting
     1558                   || mData->mMachineState == MachineState_LiveSnapshotting, throw E_FAIL);
     1559        AssertStmt(task.m_machineStateBackup != mData->mMachineState, throw E_FAIL);
     1560        AssertStmt(task.m_pSnapshot.isNull(), throw E_FAIL);
     1561
     1562        if (   mData->mCurrentSnapshot
     1563            && mData->mCurrentSnapshot->i_getDepth() >= SETTINGS_SNAPSHOT_DEPTH_MAX)
     1564        {
     1565            throw setError(VBOX_E_INVALID_OBJECT_STATE,
     1566                           tr("Cannot take another snapshot for machine '%s', because it exceeds the maximum snapshot depth limit. Please delete some earlier snapshot which you no longer need"),
     1567                           mUserData->s.strName.c_str());
     1568        }
     1569
     1570        if (    !task.m_fTakingSnapshotOnline
     1571             && mData->mMachineState != MachineState_Saved)
     1572        {
     1573            /* save settings to ensure current changes are committed and
     1574             * hard disks are fixed up */
     1575            rc = i_saveSettings(NULL);
    14681576                // no need to check for whether VirtualBox.xml needs changing since
    14691577                // we can't have a machine XML rename pending at this point
    1470         if (FAILED(rc)) return rc;
    1471     }
    1472 
    1473     /* create an ID for the snapshot */
    1474     Guid snapshotId;
    1475     snapshotId.create();
    1476 
    1477     /* stateFilePath is null when the machine is not online nor saved */
    1478     if (aFTakingSnapshotOnline)
    1479     {
    1480         Bstr value;
    1481         HRESULT rc = GetExtraData(Bstr("VBoxInternal2/ForceTakeSnapshotWithoutState").raw(),
    1482                                   value.asOutParam());
    1483         if (FAILED(rc) || value != "1")
    1484             // creating a new online snapshot: we need a fresh saved state file
    1485             i_composeSavedStateFilename(aStateFilePath);
    1486     }
    1487     else if (mData->mMachineState == MachineState_Saved)
    1488         // taking an online snapshot from machine in "saved" state: then use existing state file
    1489         aStateFilePath = mSSData->strStateFilePath;
    1490 
    1491     if (aStateFilePath.isNotEmpty())
    1492     {
    1493         // ensure the directory for the saved state file exists
    1494         HRESULT rc = VirtualBox::i_ensureFilePathExists(aStateFilePath, true /* fCreate */);
    1495         if (FAILED(rc)) return rc;
    1496     }
    1497 
    1498     /* create a snapshot machine object */
    1499     ComObjPtr<SnapshotMachine> snapshotMachine;
    1500     snapshotMachine.createObject();
    1501     HRESULT rc = snapshotMachine->init(this, snapshotId.ref(), aStateFilePath);
    1502     AssertComRCReturn(rc, rc);
    1503 
    1504     /* create a snapshot object */
    1505     RTTIMESPEC time;
    1506     ComObjPtr<Snapshot> pSnapshot;
    1507     pSnapshot.createObject();
    1508     rc = pSnapshot->init(mParent,
    1509                          snapshotId,
    1510                          aName,
    1511                          aDescription,
    1512                          *RTTimeNow(&time),
    1513                          snapshotMachine,
    1514                          mData->mCurrentSnapshot);
    1515     AssertComRCReturnRC(rc);
    1516 
    1517     /* fill in the snapshot data */
    1518     mConsoleTaskData.mLastState = mData->mMachineState;
    1519     mConsoleTaskData.mSnapshot = pSnapshot;
    1520 
    1521     /// @todo in the long run the progress object should be moved to
    1522     // VBoxSVC to avoid trouble with monitoring the progress object state
    1523     // when the process where it lives is terminating shortly after the
    1524     // operation completed.
    1525 
    1526     try
    1527     {
     1578            if (FAILED(rc))
     1579                throw rc;
     1580        }
     1581
     1582        /* task.m_strStateFilePath is "" when the machine is offline or saved */
     1583        if (task.m_fTakingSnapshotOnline)
     1584        {
     1585            Bstr value;
     1586            HRESULT rc = GetExtraData(Bstr("VBoxInternal2/ForceTakeSnapshotWithoutState").raw(),
     1587                                      value.asOutParam());
     1588            if (FAILED(rc) || value != "1")
     1589                // creating a new online snapshot: we need a fresh saved state file
     1590                i_composeSavedStateFilename(task.m_strStateFilePath);
     1591        }
     1592        else if (mData->mMachineState == MachineState_Saved)
     1593            // taking an offline snapshot from machine in "saved" state: use existing state file
     1594            task.m_strStateFilePath = mSSData->strStateFilePath;
     1595
     1596        if (task.m_strStateFilePath.isNotEmpty())
     1597        {
     1598            // ensure the directory for the saved state file exists
     1599            rc = VirtualBox::i_ensureFilePathExists(task.m_strStateFilePath, true /* fCreate */);
     1600            if (FAILED(rc))
     1601                throw rc;
     1602        }
     1603
     1604        /* STEP 1: create the snapshot object */
     1605
     1606        /* create an ID for the snapshot */
     1607        Guid snapshotId;
     1608        snapshotId.create();
     1609
     1610        /* create a snapshot machine object */
     1611        ComObjPtr<SnapshotMachine> pSnapshotMachine;
     1612        pSnapshotMachine.createObject();
     1613        rc = pSnapshotMachine->init(this, snapshotId.ref(), task.m_strStateFilePath);
     1614        AssertComRCThrowRC(rc);
     1615
     1616        /* create a snapshot object */
     1617        RTTIMESPEC time;
     1618        RTTimeNow(&time);
     1619        task.m_pSnapshot.createObject();
     1620        rc = task.m_pSnapshot->init(mParent,
     1621                                    snapshotId,
     1622                                    task.m_strName,
     1623                                    task.m_strDescription,
     1624                                    time,
     1625                                    pSnapshotMachine,
     1626                                    mData->mCurrentSnapshot);
     1627        AssertComRCThrowRC(rc);
     1628
     1629        /* STEP 2: create the diff images */
    15281630        LogFlowThisFunc(("Creating differencing hard disks (online=%d)...\n",
    1529                          aFTakingSnapshotOnline));
    1530 
    1531         // backup the media data so we can recover if things goes wrong along the day;
    1532         // the matching commit() is in fixupMedia() during endSnapshot()
     1631                         task.m_fTakingSnapshotOnline));
     1632
     1633        // Backup the media data so we can recover if something goes wrong.
     1634        // The matching commit() is in fixupMedia() during SessionMachine::i_finishTakingSnapshot()
    15331635        i_setModified(IsModified_Storage);
    15341636        mMediaData.backup();
    15351637
    1536         /* Console::fntTakeSnapshotWorker and friends expects this. */
    1537         if (mConsoleTaskData.mLastState == MachineState_Running)
    1538             i_setMachineState(MachineState_LiveSnapshotting);
    1539         else
    1540             i_setMachineState(MachineState_Saving); /** @todo Confusing! Saving is used for both online and offline snapshots. */
    1541 
    15421638        alock.release();
    15431639        /* create new differencing hard disks and attach them to this machine */
    1544         rc = i_createImplicitDiffs(aConsoleProgress,
    1545                                    1,            // operation weight; must be the same as in Console::TakeSnapshot()
    1546                                    !!aFTakingSnapshotOnline);
     1640        rc = i_createImplicitDiffs(task.m_pProgress,
     1641                                   1,            // operation weight; must be the same as in Machine::TakeSnapshot()
     1642                                   task.m_fTakingSnapshotOnline);
    15471643        if (FAILED(rc))
    15481644            throw rc;
     1645        alock.acquire();
    15491646
    15501647        // MUST NOT save the settings or the media registry here, because
    15511648        // this causes trouble with rolling back settings if the user cancels
    15521649        // taking the snapshot after the diff images have been created.
    1553     }
    1554     catch (HRESULT hrc)
    1555     {
    1556         LogThisFunc(("Caught %Rhrc [%s]\n", hrc, Global::stringifyMachineState(mData->mMachineState) ));
    1557         if (    mConsoleTaskData.mLastState != mData->mMachineState
    1558              && (   mConsoleTaskData.mLastState == MachineState_Running
    1559                   ? mData->mMachineState == MachineState_LiveSnapshotting
    1560                   : mData->mMachineState == MachineState_Saving)
    1561            )
    1562                i_setMachineState(mConsoleTaskData.mLastState);
    1563 
    1564         pSnapshot->uninit();
    1565         pSnapshot.setNull();
    1566         mConsoleTaskData.mLastState = MachineState_Null;
    1567         mConsoleTaskData.mSnapshot.setNull();
    1568 
    1569         rc = hrc;
    1570 
    1571         // @todo r=dj what with the implicit diff that we created above? this is never cleaned up
    1572     }
    1573 
    1574     if (!(aFTakingSnapshotOnline && SUCCEEDED(rc)))
    1575         aStateFilePath = "";
    1576 
    1577     LogFlowThisFunc(("LEAVE - %Rhrc [%s]\n", rc, Global::stringifyMachineState(mData->mMachineState) ));
    1578     return rc;
    1579 }
    1580 
    1581 /**
    1582  * Implementation for IInternalMachineControl::endTakingSnapshot().
    1583  *
     1650
     1651        fBeganTakingSnapshot = true;
     1652
     1653        /* Check sanity: for offline snapshots there must not be a saved state
     1654         * file name. All other combinations are valid (though online snapshots
     1655         * without saved state file seems inconsistent - there are exotic use
     1656         * cases, which need to be explicitly enabled, see the code above. */
     1657        if (   !task.m_fTakingSnapshotOnline
     1658            && !task.m_strStateFilePath.isEmpty())
     1659            throw setError(E_FAIL, "Invalid state of saved state file");
     1660
     1661        // STEP 3: save the VM state (if online)
     1662        if (task.m_fTakingSnapshotOnline)
     1663        {
     1664            task.m_pProgress->SetNextOperation(Bstr(tr("Saving the machine state")).raw(),
     1665                                               mHWData->mMemorySize);   // operation weight, same as computed
     1666                                                                        // when setting up progress object
     1667
     1668            if (task.m_strStateFilePath.isNotEmpty())
     1669            {
     1670                alock.release();
     1671                task.m_pProgress->i_setCancelCallback(i_takeSnapshotProgressCancelCallback, &task);
     1672                rc = task.m_pDirectControl->SaveStateWithReason(Reason_Snapshot,
     1673                                                                task.m_pProgress,
     1674                                                                Bstr(task.m_strStateFilePath).raw(),
     1675                                                                task.m_fPause,
     1676                                                                &fSuspendedBySave);
     1677                task.m_pProgress->i_setCancelCallback(NULL, NULL);
     1678                alock.acquire();
     1679                if (FAILED(rc))
     1680                    throw rc;
     1681            }
     1682            else
     1683                LogRel(("Machine: skipped saving state as part of online snapshot\n"));
     1684
     1685            if (!task.m_pProgress->i_notifyPointOfNoReturn())
     1686                throw setError(E_FAIL, tr("Canceled"));
     1687
     1688            // STEP 4: reattach hard disks
     1689            LogFlowThisFunc(("Reattaching new differencing hard disks...\n"));
     1690
     1691            task.m_pProgress->SetNextOperation(Bstr(tr("Reconfiguring medium attachments")).raw(),
     1692                                               1);       // operation weight, same as computed when setting up progress object
     1693
     1694            com::SafeIfaceArray<IMediumAttachment> atts;
     1695            rc = COMGETTER(MediumAttachments)(ComSafeArrayAsOutParam(atts));
     1696            if (FAILED(rc))
     1697                throw rc;
     1698
     1699            alock.release();
     1700            rc = task.m_pDirectControl->ReconfigureMediumAttachments(ComSafeArrayAsInParam(atts));
     1701            alock.acquire();
     1702            if (FAILED(rc))
     1703                throw rc;
     1704        }
     1705
     1706        /*
     1707         * Finalize the requested snapshot object. This will reset the
     1708         * machine state to the state it had at the beginning.
     1709         */
     1710        rc = i_finishTakingSnapshot(task, alock, true /*aSuccess*/);
     1711        // do not throw rc here because we can't call i_finishTakingSnapshot() twice
     1712        LogFlowThisFunc(("i_finishTakingSnapshot -> %Rhrc [mMachineState=%s]\n", rc, Global::stringifyMachineState(mData->mMachineState)));
     1713    }
     1714    catch (HRESULT rcThrown)
     1715    {
     1716        rc = rcThrown;
     1717        LogThisFunc(("Caught %Rhrc [mMachineState=%s]\n", rc, Global::stringifyMachineState(mData->mMachineState)));
     1718
     1719        // @todo r=klaus check that the implicit diffs created above are cleaned up im the relevant error cases
     1720
     1721        /* preserve existing error info */
     1722        ErrorInfoKeeper eik;
     1723
     1724        if (fBeganTakingSnapshot)
     1725            i_finishTakingSnapshot(task, alock, false /*aSuccess*/);
     1726
     1727        // have to postpone this to the end as i_finishTakingSnapshot() needs
     1728        // it for various cleanup steps
     1729        task.m_pSnapshot->uninit();
     1730        task.m_pSnapshot.setNull();
     1731    }
     1732    Assert(alock.isWriteLockOnCurrentThread());
     1733
     1734    {
     1735        // Keep all error information over the cleanup steps
     1736        ErrorInfoKeeper eik;
     1737
     1738        /*
     1739         * Fix up the machine state.
     1740         *
     1741         * For offline snapshots we just update the local copy, for the other
     1742         * variants do the entire work. This ensures that the state is in sync
     1743         * with the VM process (in particular the VM execution state).
     1744         */
     1745        bool fNeedClientMachineStateUpdate = false;
     1746        if (   mData->mMachineState == MachineState_LiveSnapshotting
     1747            || mData->mMachineState == MachineState_OnlineSnapshotting
     1748            || mData->mMachineState == MachineState_Snapshotting)
     1749        {
     1750            if (!task.m_fTakingSnapshotOnline)
     1751                i_setMachineState(task.m_machineStateBackup);
     1752            else
     1753            {
     1754                MachineState_T enmMachineState = MachineState_Null;
     1755                HRESULT rc2 = task.m_pDirectControl->COMGETTER(NominalState)(&enmMachineState);
     1756                if (FAILED(rc2) || enmMachineState == MachineState_Null)
     1757                {
     1758                    AssertMsgFailed(("state=%s\n", Global::stringifyMachineState(enmMachineState)));
     1759                    // pure nonsense, try to continue somehow
     1760                    enmMachineState = MachineState_Aborted;
     1761                }
     1762                if (enmMachineState == MachineState_Paused)
     1763                {
     1764                    if (fSuspendedBySave)
     1765                    {
     1766                        alock.release();
     1767                        rc2 = task.m_pDirectControl->ResumeWithReason(Reason_Snapshot);
     1768                        alock.acquire();
     1769                        if (SUCCEEDED(rc2))
     1770                            enmMachineState = task.m_machineStateBackup;
     1771                    }
     1772                    else
     1773                        enmMachineState = task.m_machineStateBackup;
     1774                }
     1775                if (enmMachineState != mData->mMachineState)
     1776                {
     1777                    fNeedClientMachineStateUpdate = true;
     1778                    i_setMachineState(enmMachineState);
     1779                }
     1780            }
     1781        }
     1782
     1783        /* check the remote state to see that we got it right. */
     1784        MachineState_T enmMachineState = MachineState_Null;
     1785        if (!task.m_pDirectControl.isNull())
     1786        {
     1787            ComPtr<IConsole> pConsole;
     1788            task.m_pDirectControl->COMGETTER(RemoteConsole)(pConsole.asOutParam());
     1789            if (!pConsole.isNull())
     1790                pConsole->COMGETTER(State)(&enmMachineState);
     1791        }
     1792        LogFlowThisFunc(("local mMachineState=%s remote mMachineState=%s\n",
     1793                         Global::stringifyMachineState(mData->mMachineState),
     1794                         Global::stringifyMachineState(enmMachineState)));
     1795
     1796        if (fNeedClientMachineStateUpdate)
     1797            i_updateMachineStateOnClient();
     1798    }
     1799
     1800    task.m_pProgress->i_notifyComplete(rc);
     1801
     1802    LogFlowThisFuncLeave();
     1803}
     1804
     1805
     1806/**
     1807 * Progress cancelation callback employed by SessionMachine::i_takeSnapshotHandler.
     1808 */
     1809/*static*/
     1810void SessionMachine::i_takeSnapshotProgressCancelCallback(void *pvUser)
     1811{
     1812    TakeSnapshotTask *pTask = (TakeSnapshotTask *)pvUser;
     1813    AssertPtrReturnVoid(pTask);
     1814    AssertReturnVoid(!pTask->m_pDirectControl.isNull());
     1815    pTask->m_pDirectControl->CancelSaveStateWithReason();
     1816}
     1817
     1818
     1819/**
    15841820 * Called by the Console when it's done saving the VM state into the snapshot
    15851821 * (if online) and reconfiguring the hard disks. See BeginTakingSnapshot() above.
     
    15931829 * @return
    15941830 */
    1595 HRESULT SessionMachine::endTakingSnapshot(BOOL aSuccess)
     1831HRESULT SessionMachine::i_finishTakingSnapshot(TakeSnapshotTask &task, AutoWriteLock &alock, bool aSuccess)
    15961832{
    15971833    LogFlowThisFunc(("\n"));
    15981834
    1599     AutoWriteLock machineLock(this COMMA_LOCKVAL_SRC_POS);
     1835    Assert(alock.isWriteLockOnCurrentThread());
    16001836
    16011837    AssertReturn(   !aSuccess
    1602                  || (    (    mData->mMachineState == MachineState_Saving
    1603                            || mData->mMachineState == MachineState_LiveSnapshotting)
    1604                       && mConsoleTaskData.mLastState != MachineState_Null
    1605                       && !mConsoleTaskData.mSnapshot.isNull()
    1606                     )
    1607                  , E_FAIL);
    1608 
    1609     /*
    1610      * Restore the state we had when BeginTakingSnapshot() was called,
    1611      * Console::fntTakeSnapshotWorker restores its local copy when we return.
    1612      * If the state was Running, then let Console::fntTakeSnapshotWorker do it
    1613      * all to avoid races.
    1614      */
    1615     if (    mData->mMachineState != mConsoleTaskData.mLastState
    1616          && mConsoleTaskData.mLastState != MachineState_Running
    1617        )
    1618            i_setMachineState(mConsoleTaskData.mLastState);
     1838                 || mData->mMachineState == MachineState_Snapshotting
     1839                 || mData->mMachineState == MachineState_OnlineSnapshotting
     1840                 || mData->mMachineState == MachineState_LiveSnapshotting, E_FAIL);
    16191841
    16201842    ComObjPtr<Snapshot> pOldFirstSnap = mData->mFirstSnapshot;
    16211843    ComObjPtr<Snapshot> pOldCurrentSnap = mData->mCurrentSnapshot;
    16221844
    1623     bool fOnline = Global::IsOnline(mConsoleTaskData.mLastState);
     1845    bool fOnline = Global::IsOnline(task.m_machineStateBackup);
    16241846
    16251847    HRESULT rc = S_OK;
     
    16281850    {
    16291851        // new snapshot becomes the current one
    1630         mData->mCurrentSnapshot = mConsoleTaskData.mSnapshot;
     1852        mData->mCurrentSnapshot = task.m_pSnapshot;
    16311853
    16321854        /* memorize the first snapshot if necessary */
     
    16511873        /* inform callbacks */
    16521874        mParent->i_onSnapshotTaken(mData->mUuid,
    1653                                    mConsoleTaskData.mSnapshot->i_getId());
    1654         machineLock.release();
     1875                                   task.m_pSnapshot->i_getId());
     1876        alock.release();
    16551877    }
    16561878    else
     
    16581880        /* delete all differencing hard disks created (this will also attach
    16591881         * their parents back by rolling back mMediaData) */
    1660         machineLock.release();
     1882        alock.release();
    16611883
    16621884        i_rollbackMedia();
     
    16701892            // snapshot means that a new saved state file was created, which we must
    16711893            // clean up now
    1672             RTFileDelete(mConsoleTaskData.mSnapshot->i_getStateFilePath().c_str());
    1673             machineLock.acquire();
    1674 
    1675 
    1676         mConsoleTaskData.mSnapshot->uninit();
    1677         machineLock.release();
     1894            RTFileDelete(task.m_pSnapshot->i_getStateFilePath().c_str());
     1895
     1896        alock.acquire();
     1897
     1898        task.m_pSnapshot->uninit();
     1899        alock.release();
    16781900
    16791901    }
    16801902
    16811903    /* clear out the snapshot data */
    1682     mConsoleTaskData.mLastState = MachineState_Null;
    1683     mConsoleTaskData.mSnapshot.setNull();
    1684 
    1685     /* machineLock has been released already */
    1686 
     1904    task.m_pSnapshot.setNull();
     1905
     1906    /* alock has been released already */
    16871907    mParent->i_saveModifiedRegistries();
     1908
     1909    alock.acquire();
    16881910
    16891911    return rc;
     
    16921914////////////////////////////////////////////////////////////////////////////////
    16931915//
    1694 // RestoreSnapshot methods (SessionMachine and related tasks)
     1916// RestoreSnapshot methods (Machine and related tasks)
    16951917//
    16961918////////////////////////////////////////////////////////////////////////////////
    16971919
    1698 /**
    1699  * Implementation for IInternalMachineControl::restoreSnapshot().
    1700  *
    1701  * Gets called from Console::RestoreSnapshot(), and that's basically the
    1702  * only thing Console does. Restoring a snapshot happens entirely on the
    1703  * server side since the machine cannot be running.
    1704  *
    1705  * This creates a new thread that does the work and returns a progress
    1706  * object to the client which is then returned to the caller of
    1707  * Console::RestoreSnapshot().
    1708  *
     1920HRESULT Machine::restoreSnapshot(const ComPtr<ISnapshot> &aSnapshot,
     1921                                 ComPtr<IProgress> &aProgress)
     1922{
     1923    NOREF(aSnapshot);
     1924    NOREF(aProgress);
     1925    ReturnComNotImplemented();
     1926}
     1927
     1928/**
     1929 * Restoring a snapshot happens entirely on the server side, the machine cannot be running.
     1930 *
     1931 * This creates a new thread that does the work and returns a progress object to the client.
    17091932 * Actual work then takes place in RestoreSnapshotTask::handler().
    17101933 *
    17111934 * @note Locks this + children objects for writing!
    17121935 *
    1713  * @param aInitiator in: rhe console on which Console::RestoreSnapshot was called.
    17141936 * @param aSnapshot in: the snapshot to restore.
    1715  * @param aMachineState in: client-side machine state.
    17161937 * @param aProgress out: progress object to monitor restore thread.
    17171938 * @return
    17181939 */
    1719 HRESULT SessionMachine::restoreSnapshot(const ComPtr<IConsole> &aInitiator,
    1720                                         const ComPtr<ISnapshot> &aSnapshot,
    1721                                         MachineState_T *aMachineState,
     1940HRESULT SessionMachine::restoreSnapshot(const ComPtr<ISnapshot> &aSnapshot,
    17221941                                        ComPtr<IProgress> &aProgress)
    17231942{
     
    17271946
    17281947    // machine must not be running
    1729     ComAssertRet(!Global::IsOnlineOrTransient(mData->mMachineState),
    1730                  E_FAIL);
     1948    if (Global::IsOnlineOrTransient(mData->mMachineState))
     1949        return setError(VBOX_E_INVALID_VM_STATE,
     1950                        tr("Cannot delete the current state of the running machine (machine state: %s)"),
     1951                        Global::stringifyMachineState(mData->mMachineState));
    17311952
    17321953    ISnapshot* iSnapshot = aSnapshot;
    17331954    ComObjPtr<Snapshot> pSnapshot(static_cast<Snapshot*>(iSnapshot));
    17341955    ComObjPtr<SnapshotMachine> pSnapMachine = pSnapshot->i_getSnapshotMachine();
     1956
     1957    HRESULT rc = S_OK;
    17351958
    17361959    // create a progress object. The number of operations is:
     
    17581981    ComObjPtr<Progress> pProgress;
    17591982    pProgress.createObject();
    1760     pProgress->init(mParent, aInitiator,
     1983    pProgress->init(mParent, static_cast<IMachine*>(this),
    17611984                    BstrFmt(tr("Restoring snapshot '%s'"), pSnapshot->i_getName().c_str()).raw(),
    17621985                    FALSE /* aCancelable */,
     
    17681991    /* create and start the task on a separate thread (note that it will not
    17691992     * start working until we release alock) */
    1770     RestoreSnapshotTask *task = new RestoreSnapshotTask(this,
    1771                                                         pProgress,
    1772                                                         pSnapshot);
    1773     int vrc = RTThreadCreate(NULL,
    1774                              taskHandler,
    1775                              (void*)task,
    1776                              0,
    1777                              RTTHREADTYPE_MAIN_WORKER,
    1778                              0,
    1779                              "RestoreSnap");
    1780     if (RT_FAILURE(vrc))
    1781     {
    1782         delete task;
    1783         ComAssertRCRet(vrc, E_FAIL);
    1784     }
     1993    RestoreSnapshotTask *pTask = new RestoreSnapshotTask(this,
     1994                                                         pProgress,
     1995                                                         "RestoreSnap",
     1996                                                         pSnapshot);
     1997    rc = pTask->createThread();
     1998    if (FAILED(rc))
     1999        return rc;
    17852000
    17862001    /* set the proper machine state (note: after creating a Task instance) */
     
    17892004    /* return the progress to the caller */
    17902005    pProgress.queryInterfaceTo(aProgress.asOutParam());
    1791 
    1792     /* return the new state to the caller */
    1793     *aMachineState = mData->mMachineState;
    17942006
    17952007    LogFlowThisFuncLeave();
     
    18082020 * @note Locks mParent + this object for writing.
    18092021 *
    1810  * @param aTask Task data.
    1811  */
    1812 void SessionMachine::i_restoreSnapshotHandler(RestoreSnapshotTask &aTask)
     2022 * @param pTask Task data.
     2023 */
     2024void SessionMachine::i_restoreSnapshotHandler(RestoreSnapshotTask &task)
    18132025{
    18142026    LogFlowThisFuncEnter();
     
    18212033        /* we might have been uninitialized because the session was accidentally
    18222034         * closed by the client, so don't assert */
    1823         aTask.pProgress->i_notifyComplete(E_FAIL,
    1824                                           COM_IIDOF(IMachine),
    1825                                           getComponentName(),
    1826                                           tr("The session has been accidentally closed"));
     2035        task.m_pProgress->i_notifyComplete(E_FAIL,
     2036                                           COM_IIDOF(IMachine),
     2037                                           getComponentName(),
     2038                                           tr("The session has been accidentally closed"));
    18272039
    18282040        LogFlowThisFuncLeave();
     
    18462058        /* Delete the saved state file if the machine was Saved prior to this
    18472059         * operation */
    1848         if (aTask.machineStateBackup == MachineState_Saved)
     2060        if (task.m_machineStateBackup == MachineState_Saved)
    18492061        {
    18502062            Assert(!mSSData->strStateFilePath.isEmpty());
     
    18562068            i_releaseSavedStateFile(strStateFile, NULL /* pSnapshotToIgnore */ );
    18572069
    1858             aTask.modifyBackedUpState(MachineState_PoweredOff);
     2070            task.modifyBackedUpState(MachineState_PoweredOff);
    18592071
    18602072            rc = i_saveStateSettings(SaveSTS_StateFilePath);
     
    18672079
    18682080        {
    1869             AutoReadLock snapshotLock(aTask.pSnapshot COMMA_LOCKVAL_SRC_POS);
     2081            AutoReadLock snapshotLock(task.m_pSnapshot COMMA_LOCKVAL_SRC_POS);
    18702082
    18712083            /* remember the timestamp of the snapshot we're restoring from */
    1872             snapshotTimeStamp = aTask.pSnapshot->i_getTimeStamp();
    1873 
    1874             ComPtr<SnapshotMachine> pSnapshotMachine(aTask.pSnapshot->i_getSnapshotMachine());
     2084            snapshotTimeStamp = task.m_pSnapshot->i_getTimeStamp();
     2085
     2086            ComPtr<SnapshotMachine> pSnapshotMachine(task.m_pSnapshot->i_getSnapshotMachine());
    18752087
    18762088            /* copy all hardware data from the snapshot */
     
    18972109            alock.release();
    18982110
    1899             rc = i_createImplicitDiffs(aTask.pProgress,
     2111            rc = i_createImplicitDiffs(task.m_pProgress,
    19002112                                       1,
    19012113                                       false /* aOnline */);
     
    19072119
    19082120            /* Note: on success, current (old) hard disks will be
    1909              * deassociated/deleted on #commit() called from #saveSettings() at
     2121             * deassociated/deleted on #commit() called from #i_saveSettings() at
    19102122             * the end. On failure, newly created implicit diffs will be
    19112123             * deleted by #rollback() at the end. */
     
    19142126            Assert(mSSData->strStateFilePath.isEmpty());
    19152127
    1916             const Utf8Str &strSnapshotStateFile = aTask.pSnapshot->i_getStateFilePath();
     2128            const Utf8Str &strSnapshotStateFile = task.m_pSnapshot->i_getStateFilePath();
    19172129
    19182130            if (strSnapshotStateFile.isNotEmpty())
     
    19202132                mSSData->strStateFilePath = strSnapshotStateFile;
    19212133
    1922             LogFlowThisFunc(("Setting new current snapshot {%RTuuid}\n", aTask.pSnapshot->i_getId().raw()));
     2134            LogFlowThisFunc(("Setting new current snapshot {%RTuuid}\n", task.m_pSnapshot->i_getId().raw()));
    19232135            /* make the snapshot we restored from the current snapshot */
    1924             mData->mCurrentSnapshot = aTask.pSnapshot;
     2136            mData->mCurrentSnapshot = task.m_pSnapshot;
    19252137        }
    19262138
     
    19692181
    19702182        // detach the current-state diffs that we detected above and build a list of
    1971         // image files to delete _after_ saveSettings()
     2183        // image files to delete _after_ i_saveSettings()
    19722184
    19732185        MediaList llDiffsToDelete;
     
    19852197
    19862198            // Normally we "detach" the medium by removing the attachment object
    1987             // from the current machine data; saveSettings() below would then
     2199            // from the current machine data; i_saveSettings() below would then
    19882200            // compare the current machine data with the one in the backup
    19892201            // and actually call Medium::removeBackReference(). But that works only half
     
    19912203            // remove from machine data
    19922204            mMediaData->mAttachments.remove(pAttach);
    1993             // Remove it from the backup or else saveSettings will try to detach
     2205            // Remove it from the backup or else i_saveSettings will try to detach
    19942206            // it again and assert. The paranoia check avoids crashes (see
    19952207            // assert above) if this code is buggy and saves settings in the
     
    20092221        if (FAILED(rc))
    20102222            throw rc;
    2011         // unconditionally add the parent registry. We do similar in SessionMachine::EndTakingSnapshot
    2012         // (mParent->saveSettings())
    20132223
    20142224        // release the locks before updating registry and deleting image files
    20152225        alock.release();
    20162226
     2227        // unconditionally add the parent registry.
    20172228        mParent->i_markRegistryModified(mParent->i_getGlobalRegistryId());
    20182229
     
    20282239            HRESULT rc2 = pMedium->i_deleteStorage(NULL /* aProgress */,
    20292240                                                   true /* aWait */);
    2030             // ignore errors here because we cannot roll back after saveSettings() above
     2241            // ignore errors here because we cannot roll back after i_saveSettings() above
    20312242            if (SUCCEEDED(rc2))
    20322243                pMedium->uninit();
     
    20492260        {
    20502261            /* restore the machine state */
    2051             i_setMachineState(aTask.machineStateBackup);
     2262            i_setMachineState(task.m_machineStateBackup);
    20522263            i_updateMachineStateOnClient();
    20532264        }
     
    20572268
    20582269    /* set the result (this will try to fetch current error info on failure) */
    2059     aTask.pProgress->i_notifyComplete(rc);
     2270    task.m_pProgress->i_notifyComplete(rc);
    20602271
    20612272    if (SUCCEEDED(rc))
     
    20732284////////////////////////////////////////////////////////////////////////////////
    20742285
    2075 /**
    2076  * Implementation for IInternalMachineControl::deleteSnapshot().
    2077  *
    2078  * Gets called from Console::DeleteSnapshot(), and that's basically the
    2079  * only thing Console does initially. Deleting a snapshot happens entirely on
    2080  * the server side if the machine is not running, and if it is running then
    2081  * the individual merges are done via internal session callbacks.
     2286HRESULT Machine::deleteSnapshot(const com::Guid &aId, ComPtr<IProgress> &aProgress)
     2287{
     2288    NOREF(aId);
     2289    NOREF(aProgress);
     2290    ReturnComNotImplemented();
     2291}
     2292
     2293HRESULT SessionMachine::deleteSnapshot(const com::Guid &aId, ComPtr<IProgress> &aProgress)
     2294{
     2295    return i_deleteSnapshot(aId, aId,
     2296                            FALSE /* fDeleteAllChildren */,
     2297                            aProgress);
     2298}
     2299
     2300HRESULT Machine::deleteSnapshotAndAllChildren(const com::Guid &aId, ComPtr<IProgress> &aProgress)
     2301{
     2302    NOREF(aId);
     2303    NOREF(aProgress);
     2304    ReturnComNotImplemented();
     2305}
     2306
     2307HRESULT SessionMachine::deleteSnapshotAndAllChildren(const com::Guid &aId, ComPtr<IProgress> &aProgress)
     2308{
     2309    return i_deleteSnapshot(aId, aId,
     2310                            TRUE /* fDeleteAllChildren */,
     2311                            aProgress);
     2312}
     2313
     2314HRESULT Machine::deleteSnapshotRange(const com::Guid &aStartId, const com::Guid &aEndId, ComPtr<IProgress> &aProgress)
     2315{
     2316    NOREF(aStartId);
     2317    NOREF(aEndId);
     2318    NOREF(aProgress);
     2319    ReturnComNotImplemented();
     2320}
     2321
     2322HRESULT SessionMachine::deleteSnapshotRange(const com::Guid &aStartId, const com::Guid &aEndId, ComPtr<IProgress> &aProgress)
     2323{
     2324    return i_deleteSnapshot(aStartId, aEndId,
     2325                            FALSE /* fDeleteAllChildren */,
     2326                            aProgress);
     2327}
     2328
     2329
     2330/**
     2331 * Implementation for SessionMachine::i_deleteSnapshot().
     2332 *
     2333 * Gets called from SessionMachine::DeleteSnapshot(). Deleting a snapshot
     2334 * happens entirely on the server side if the machine is not running, and
     2335 * if it is running then the merges are done via internal session callbacks.
    20822336 *
    20832337 * This creates a new thread that does the work and returns a progress
    2084  * object to the client which is then returned to the caller of
    2085  * Console::DeleteSnapshot().
    2086  *
    2087  * Actual work then takes place in DeleteSnapshotTask::handler().
     2338 * object to the client.
     2339 *
     2340 * Actual work then takes place in SessionMachine::i_deleteSnapshotHandler().
    20882341 *
    20892342 * @note Locks mParent + this + children objects for writing!
    20902343 */
    2091 HRESULT SessionMachine::deleteSnapshot(const ComPtr<IConsole> &aInitiator,
    2092                                        const com::Guid &aStartId,
    2093                                        const com::Guid &aEndId,
    2094                                        BOOL aDeleteAllChildren,
    2095                                        MachineState_T *aMachineState,
    2096                                        ComPtr<IProgress> &aProgress)
     2344HRESULT SessionMachine::i_deleteSnapshot(const com::Guid &aStartId,
     2345                                         const com::Guid &aEndId,
     2346                                         BOOL aDeleteAllChildren,
     2347                                         ComPtr<IProgress> &aProgress)
    20972348{
    20982349    LogFlowThisFuncEnter();
    20992350
    2100     AssertReturn(aInitiator && !aStartId.isZero() && !aEndId.isZero() && aStartId.isValid() && aEndId.isValid(), E_INVALIDARG);
     2351    AssertReturn(!aStartId.isZero() && !aEndId.isZero() && aStartId.isValid() && aEndId.isValid(), E_INVALIDARG);
    21012352
    21022353
     
    21062357
    21072358    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
     2359
     2360    if (Global::IsTransient(mData->mMachineState))
     2361        return setError(VBOX_E_INVALID_VM_STATE,
     2362                        tr("Cannot delete a snapshot of the machine while it is changing the state (machine state: %s)"),
     2363                        Global::stringifyMachineState(mData->mMachineState));
    21082364
    21092365    // be very picky about machine states
     
    22002456    ComObjPtr<Progress> pProgress;
    22012457    pProgress.createObject();
    2202     pProgress->init(mParent, aInitiator,
     2458    pProgress->init(mParent, static_cast<IMachine*>(this),
    22032459                    BstrFmt(tr("Deleting snapshot '%s'"), pSnapshot->i_getName().c_str()).raw(),
    22042460                    FALSE /* aCancelable */,
     
    22122468
    22132469    /* create and start the task on a separate thread */
    2214     DeleteSnapshotTask *task = new DeleteSnapshotTask(this, pProgress,
    2215                                                       fDeleteOnline, pSnapshot);
    2216     int vrc = RTThreadCreate(NULL,
    2217                              taskHandler,
    2218                              (void*)task,
    2219                              0,
    2220                              RTTHREADTYPE_MAIN_WORKER,
    2221                              0,
    2222                              "DeleteSnapshot");
    2223     if (RT_FAILURE(vrc))
    2224     {
    2225         delete task;
    2226         return E_FAIL;
    2227     }
     2470    DeleteSnapshotTask *pTask = new DeleteSnapshotTask(this, pProgress,
     2471                                                       "DeleteSnap",
     2472                                                       fDeleteOnline,
     2473                                                       pSnapshot);
     2474    rc = pTask->createThread();
     2475    if (FAILED(rc))
     2476        return rc;
    22282477
    22292478    // the task might start running but will block on acquiring the machine's write lock
     
    22362485    else
    22372486        i_setMachineState(MachineState_DeletingSnapshot);
     2487    i_updateMachineStateOnClient();
    22382488
    22392489    /* return the progress to the caller */
    22402490    pProgress.queryInterfaceTo(aProgress.asOutParam());
    2241 
    2242     /* return the new state to the caller */
    2243     *aMachineState = mData->mMachineState;
    22442491
    22452492    LogFlowThisFuncLeave();
     
    23412588 * @note Locks the machine + the snapshot + the media tree for writing!
    23422589 *
    2343  * @param aTask Task data.
    2344  */
    2345 
    2346 void SessionMachine::i_deleteSnapshotHandler(DeleteSnapshotTask &aTask)
     2590 * @param pTask Task data.
     2591 */
     2592void SessionMachine::i_deleteSnapshotHandler(DeleteSnapshotTask &task)
    23472593{
    23482594    LogFlowThisFuncEnter();
    23492595
     2596    HRESULT rc = S_OK;
    23502597    AutoCaller autoCaller(this);
    2351 
    23522598    LogFlowThisFunc(("state=%d\n", getObjectState().getState()));
    2353     if (!autoCaller.isOk())
     2599    if (FAILED(autoCaller.rc()))
    23542600    {
    23552601        /* we might have been uninitialized because the session was accidentally
    23562602         * closed by the client, so don't assert */
    2357         aTask.pProgress->i_notifyComplete(E_FAIL,
    2358                                           COM_IIDOF(IMachine),
    2359                                           getComponentName(),
    2360                                           tr("The session has been accidentally closed"));
     2603        rc = setError(E_FAIL,
     2604                      tr("The session has been accidentally closed"));
     2605        task.m_pProgress->i_notifyComplete(rc);
    23612606        LogFlowThisFuncLeave();
    23622607        return;
    23632608    }
    23642609
    2365     HRESULT rc = S_OK;
    23662610    MediumDeleteRecList toDelete;
    23672611    Guid snapshotId;
     
    23712615        /* Locking order:  */
    23722616        AutoMultiWriteLock2 multiLock(this->lockHandle(),                   // machine
    2373                                       aTask.pSnapshot->lockHandle()         // snapshot
     2617                                      task.m_pSnapshot->lockHandle()        // snapshot
    23742618                                      COMMA_LOCKVAL_SRC_POS);
    23752619        // once we have this lock, we know that SessionMachine::DeleteSnapshot()
     
    23792623                               COMMA_LOCKVAL_SRC_POS);
    23802624
    2381         ComObjPtr<SnapshotMachine> pSnapMachine = aTask.pSnapshot->i_getSnapshotMachine();
     2625        ComObjPtr<SnapshotMachine> pSnapMachine = task.m_pSnapshot->i_getSnapshotMachine();
    23822626        // no need to lock the snapshot machine since it is const by definition
    23832627        Guid machineId = pSnapMachine->i_getId();
    23842628
    23852629        // save the snapshot ID (for callbacks)
    2386         snapshotId = aTask.pSnapshot->i_getId();
     2630        snapshotId = task.m_pSnapshot->i_getId();
    23872631
    23882632        // first pass:
     
    24282672            MediumLockList *pChildrenToReparent = NULL;
    24292673            bool fNeedsOnlineMerge = false;
    2430             bool fOnlineMergePossible = aTask.m_fDeleteOnline;
     2674            bool fOnlineMergePossible = task.m_fDeleteOnline;
    24312675            MediumLockList *pMediumLockList = NULL;
    24322676            MediumLockList *pVMMALockList = NULL;
     
    26662910            AutoWriteLock machineLock(this COMMA_LOCKVAL_SRC_POS);
    26672911
    2668             Utf8Str stateFilePath = aTask.pSnapshot->i_getStateFilePath();
     2912            Utf8Str stateFilePath = task.m_pSnapshot->i_getStateFilePath();
    26692913            if (!stateFilePath.isEmpty())
    26702914            {
    2671                 aTask.pProgress->SetNextOperation(Bstr(tr("Deleting the execution state")).raw(),
    2672                                                   1);        // weight
    2673 
    2674                 i_releaseSavedStateFile(stateFilePath, aTask.pSnapshot /* pSnapshotToIgnore */);
     2915                task.m_pProgress->SetNextOperation(Bstr(tr("Deleting the execution state")).raw(),
     2916                                                   1);        // weight
     2917
     2918                i_releaseSavedStateFile(stateFilePath, task.m_pSnapshot /* pSnapshotToIgnore */);
    26752919
    26762920                // machine will need saving now
     
    26972941            }
    26982942
    2699             aTask.pProgress->SetNextOperation(BstrFmt(tr("Merging differencing image '%s'"),
    2700                                               pMedium->i_getName().c_str()).raw(),
    2701                                               ulWeight);
     2943            task.m_pProgress->SetNextOperation(BstrFmt(tr("Merging differencing image '%s'"),
     2944                                               pMedium->i_getName().c_str()).raw(),
     2945                                               ulWeight);
    27022946
    27032947            bool fNeedSourceUninit = false;
     
    27222966                    /* No need to hold the lock any longer. */
    27232967                    mLock.release();
    2724                     rc = pMedium->i_deleteStorage(&aTask.pProgress,
     2968                    rc = pMedium->i_deleteStorage(&task.m_pProgress,
    27252969                                                  true /* aWait */);
    27262970                    if (FAILED(rc))
     
    27402984                    // This callback will arrive while onlineMergeMedium is
    27412985                    // still executing, and there can't be two tasks.
     2986                    /// @todo r=klaus this hack needs to go, and the logic needs to be "unconvoluted", putting SessionMachine in charge of coordinating the reconfig/resume.
    27422987                    mConsoleTaskData.mDeleteSnapshotInfo = (void *)&(*it);
    27432988                    // online medium merge, in the direction decided earlier
     
    27492994                                             it->mpChildrenToReparent,
    27502995                                             it->mpMediumLockList,
    2751                                              aTask.pProgress,
     2996                                             task.m_pProgress,
    27522997                                             &fNeedsSave);
    27532998                    mConsoleTaskData.mDeleteSnapshotInfo = NULL;
     
    27613006                                                 it->mpChildrenToReparent,
    27623007                                                 it->mpMediumLockList,
    2763                                                  &aTask.pProgress,
     3008                                                 &task.m_pProgress,
    27643009                                                 true /* aWait */);
    27653010                }
     
    28263071                ComObjPtr<Machine> pMachine = this;
    28273072                Guid childSnapshotId;
    2828                 ComObjPtr<Snapshot> pChildSnapshot = aTask.pSnapshot->i_getFirstChild();
     3073                ComObjPtr<Snapshot> pChildSnapshot = task.m_pSnapshot->i_getFirstChild();
    28293074                if (pChildSnapshot)
    28303075                {
     
    28713116            AutoWriteLock machineLock(this COMMA_LOCKVAL_SRC_POS);
    28723117
    2873             aTask.pSnapshot->i_beginSnapshotDelete();
    2874             aTask.pSnapshot->uninit();
     3118            task.m_pSnapshot->i_beginSnapshotDelete();
     3119            task.m_pSnapshot->uninit();
    28753120
    28763121            machineLock.release();
     
    29123157        // restore the machine state that was saved when the
    29133158        // task was started
    2914         i_setMachineState(aTask.machineStateBackup);
     3159        i_setMachineState(task.m_machineStateBackup);
    29153160        i_updateMachineStateOnClient();
    29163161
     
    29193164
    29203165    // report the result (this will try to fetch current error info on failure)
    2921     aTask.pProgress->i_notifyComplete(rc);
     3166    task.m_pProgress->i_notifyComplete(rc);
    29223167
    29233168    if (SUCCEEDED(rc))
     
    30613306            aSource = aHD;
    30623307            aTarget = pChild;
    3063             LogFlowFunc(("Forward merging selected\n"));
     3308            LogFlowThisFunc(("Forward merging selected\n"));
    30643309        }
    30653310        else
     
    30673312            aSource = pChild;
    30683313            aTarget = aHD;
    3069             LogFlowFunc(("Backward merging selected\n"));
     3314            LogFlowThisFunc(("Backward merging selected\n"));
    30703315        }
    30713316    }
     
    35803825            AssertComRC(rc);
    35813826
     3827            treeLock.release();
    35823828            pMedium->uninit();
     3829            treeLock.acquire();
    35833830        }
    35843831
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette