Changeset 55214 in vbox for trunk/src/VBox/Main/src-server
- Timestamp:
- Apr 13, 2015 3:53:01 PM (10 years ago)
- Location:
- trunk/src/VBox/Main/src-server
- Files:
-
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Main/src-server/HostPower.cpp
r51498 r55214 5 5 6 6 /* 7 * Copyright (C) 2006-201 4Oracle Corporation7 * Copyright (C) 2006-2015 Oracle Corporation 8 8 * 9 9 * This file is part of VirtualBox Open Source Edition (OSE), as … … 139 139 140 140 /* 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) 145 144 { 146 ComPtr<SessionMachine> pMachine = *it 2;145 ComPtr<SessionMachine> pMachine = *it; 147 146 rc = pMachine->GetExtraData(Bstr("VBoxInternal2/SavestateOnBatteryLow").raw(), 148 147 value.asOutParam()); … … 160 159 if (fGlobal + fPerVM >= 0) 161 160 { 162 ComPtr<IInternalSessionControl> pControl = *it;163 161 ComPtr<IProgress> progress; 164 162 165 /* note that SaveStateWithReason() will simply return a failure166 * if the VM is in an inappropriate state */167 rc = p Control->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); 168 166 if (FAILED(rc)) 169 167 { -
trunk/src/VBox/Main/src-server/MachineImpl.cpp
r55168 r55214 131 131 132 132 mSession.mPID = NIL_RTPROCESS; 133 mSession.mLockType = LockType_Null; 133 134 mSession.mState = SessionState_Unlocked; 134 135 } … … 2694 2695 2695 2696 *aState = mData->mMachineState; 2697 Assert(mData->mMachineState != MachineState_Null); 2696 2698 2697 2699 return S_OK; … … 3248 3250 3249 3251 // 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); 3250 3253 ComPtr<IInternalSessionControl> pSessionW = mData->mSession.mDirectControl; 3251 3254 ComAssertRet(!pSessionW.isNull(), E_FAIL); … … 3263 3266 // get the console of the session holding the write lock (this is a remote call) 3264 3267 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 } 3274 3279 3275 3280 // share the session machine and W's console with the caller's session … … 3315 3320 RTPROCESS pid = NIL_RTPROCESS; 3316 3321 AssertCompile(sizeof(ULONG) == sizeof(RTPROCESS)); 3317 pSessionControl-> GetPID((ULONG*)&pid);3322 pSessionControl->COMGETTER(PID)((ULONG*)&pid); 3318 3323 Assert(pid != NIL_RTPROCESS); 3319 3324 … … 3432 3437 /* get the console from the direct session */ 3433 3438 ComPtr<IConsole> console; 3434 rc = pSessionControl-> GetRemoteConsole(console.asOutParam());3439 rc = pSessionControl->COMGETTER(RemoteConsole)(console.asOutParam()); 3435 3440 ComAssertComRC(rc); 3436 3441 … … 3505 3510 if (SUCCEEDED(rc)) 3506 3511 { 3512 mData->mSession.mLockType = aLockType; 3507 3513 /* memorize the direct session control and cache IUnknown for it */ 3508 3514 mData->mSession.mDirectControl = pSessionControl; … … 3525 3531 if (FAILED(rc)) 3526 3532 sessionMachine->uninit(); 3527 3528 3533 } 3529 3534 … … 5172 5177 } 5173 5178 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 */ 5182 struct 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; 5180 5202 }; 5181 5203 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 delete5197 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 references5209 * anymore. If it has it is attached to another VM and *must* not5210 * 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), // cOperations5223 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 5246 5204 /** 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 * 5277 5210 * @param task 5278 5211 * @return 5279 5212 */ 5280 HRESULT Machine::i_deleteTaskWorker(DeleteTask &task) 5281 { 5213 void Machine::i_deleteConfigHandler(DeleteConfigTask &task) 5214 { 5215 LogFlowThisFuncEnter(); 5216 5282 5217 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 } 5284 5229 5285 5230 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); … … 5303 5248 i_setMachineState(MachineState_SettingUp); 5304 5249 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)); 5308 5253 { 5309 5254 AutoCaller mac(pMedium); 5310 5255 if (FAILED(mac.rc())) throw mac.rc(); 5311 5256 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); 5313 5258 if (FAILED(rc)) throw rc; 5314 5259 LogFunc(("Deleting file %s\n", strLocation.c_str())); … … 5319 5264 rc = pMedium->DeleteStorage(pProgress2.asOutParam()); 5320 5265 if (FAILED(rc)) throw rc; 5321 rc = task. pProgress->WaitForAsyncProgressCompletion(pProgress2);5266 rc = task.m_pProgress->WaitForAsyncProgressCompletion(pProgress2); 5322 5267 if (FAILED(rc)) throw rc; 5323 5268 /* Check the result of the asynchronous process. */ … … 5347 5292 // medium storage files from the IMedium list passed in, and the 5348 5293 // 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()) 5351 5296 { 5352 5297 const Utf8Str &strFile = *it; … … 5358 5303 5359 5304 ++it; 5360 if (it == task. llFilesToDelete.end())5305 if (it == task.m_llFilesToDelete.end()) 5361 5306 { 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); 5363 5308 if (FAILED(rc)) throw rc; 5364 5309 break; 5365 5310 } 5366 5311 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); 5368 5313 if (FAILED(rc)) throw rc; 5369 5314 } … … 5438 5383 catch (HRESULT aRC) { rc = aRC; } 5439 5384 5440 return rc; 5385 task.m_pProgress->i_notifyComplete(rc); 5386 5387 LogFlowThisFuncLeave(); 5388 } 5389 5390 HRESULT 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; 5441 5446 } 5442 5447 … … 5534 5539 Global::stringifySessionState(mData->mSession.mState)); 5535 5540 5536 directControl = mData->mSession.mDirectControl; 5541 if (mData->mSession.mLockType == LockType_VM) 5542 directControl = mData->mSession.mDirectControl; 5537 5543 } 5538 5544 … … 5556 5562 Global::stringifySessionState(mData->mSession.mState)); 5557 5563 5558 directControl = mData->mSession.mDirectControl; 5564 if (mData->mSession.mLockType == LockType_VM) 5565 directControl = mData->mSession.mDirectControl; 5559 5566 } 5560 5567 … … 5609 5616 5610 5617 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 */ 5619 5625 if (!directControl) 5620 5626 rc = E_ACCESSDENIED; … … 5769 5775 try 5770 5776 { 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 } 5772 5783 5773 5784 BSTR dummy = NULL; /* will not be changed (setter) */ … … 5896 5907 HRESULT rc; 5897 5908 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 } 5900 5914 5901 5915 com::SafeArray<BSTR> bNames; … … 7086 7100 return rc; 7087 7101 7102 } 7103 7104 HRESULT 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 7116 HRESULT 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 7128 HRESULT 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); 7088 7138 } 7089 7139 … … 7718 7768 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); 7719 7769 7720 if ( mData->mSession.mState == SessionState_Locked 7770 if ( ( mData->mSession.mState == SessionState_Locked 7771 && mData->mSession.mLockType == LockType_VM) 7721 7772 || (aAllowClosing && mData->mSession.mState == SessionState_Unlocking) 7722 7773 ) … … 8419 8470 LogFlowThisFuncEnter(); 8420 8471 LogFlowThisFunc(("aMachineState=%s\n", Global::stringifyMachineState(aMachineState) )); 8472 Assert(aMachineState != MachineState_Null); 8421 8473 8422 8474 AutoCaller autoCaller(this); … … 10581 10633 10582 10634 /* 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 10584 10637 || mData->mMachineState == MachineState_LiveSnapshotting 10585 10638 || mData->mMachineState == MachineState_RestoringSnapshot … … 10670 10723 /* copy the attachment as is */ 10671 10724 10672 /** @todo the progress object created in Console::TakeSnaphot10725 /** @todo the progress object created in SessionMachine::TakeSnaphot 10673 10726 * only expects operations for hard disks. Later other 10674 10727 * device types need to show up in the progress as well. */ … … 10832 10885 /* will release the lock before the potentially lengthy operation, 10833 10886 * so protect with the special state (unless already protected) */ 10834 if ( oldState != MachineState_Saving 10887 if ( oldState != MachineState_Snapshotting 10888 && oldState != MachineState_OnlineSnapshotting 10835 10889 && oldState != MachineState_LiveSnapshotting 10836 10890 && oldState != MachineState_RestoringSnapshot … … 10969 11023 mrc = rc; 10970 11024 } 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(); 10971 11029 10972 11030 alock.acquire(); … … 12490 12548 } 12491 12549 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 attach12504 * 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't12509 // think it's still in use12510 Utf8Str strStateFile = mConsoleTaskData.mSnapshot->i_getStateFilePath();12511 mConsoleTaskData.mSnapshot->uninit();12512 i_releaseSavedStateFile(strStateFile, NULL /* pSnapshotToIgnore */ );12513 }12514 12515 12550 mData->mSession.mPID = NIL_RTPROCESS; 12516 12551 … … 12613 12648 12614 12649 /* reset the rest of session data */ 12650 mData->mSession.mLockType = LockType_Null; 12615 12651 mData->mSession.mMachine.setNull(); 12616 12652 mData->mSession.mState = SessionState_Unlocked; … … 12698 12734 } 12699 12735 12736 //////////////////////////////////////////////////////////////////////////////// 12737 // 12738 // SessionMachine task records 12739 // 12740 //////////////////////////////////////////////////////////////////////////////// 12741 12742 /** 12743 * Task record for saving the machine state. 12744 */ 12745 struct 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 */ 12776 void 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 12700 12843 /** 12701 12844 * @note Locks this object for writing. 12702 12845 */ 12703 HRESULT SessionMachine::setRemoveSavedStateFile(BOOL aRemove) 12846 HRESULT SessionMachine::saveState(ComPtr<IProgress> &aProgress) 12847 { 12848 return i_saveStateWithReason(Reason_Unspecified, aProgress); 12849 } 12850 12851 HRESULT SessionMachine::i_saveStateWithReason(Reason_T aReason, ComPtr<IProgress> &aProgress) 12704 12852 { 12705 12853 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); 12706 12854 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 */ 12896 HRESULT 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 */ 12930 HRESULT 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 12711 12952 12712 12953 /** … … 13087 13328 } 13088 13329 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_Paused13100 && mConsoleTaskData.mLastState == MachineState_Null13101 && 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_Null13143 && !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 associated13149 * task). On success the VM process already changed the state to13150 * 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_PoweredOff13168 || mData->mMachineState == MachineState_Teleported13169 || mData->mMachineState == MachineState_Aborted13170 , 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 will13183 * update the settings file */13184 13185 return i_setMachineState(MachineState_Saved);13186 }13187 13188 13330 HRESULT SessionMachine::pullGuestProperties(std::vector<com::Utf8Str> &aNames, 13189 13331 std::vector<com::Utf8Str> &aValues, … … 13263 13405 case MachineState_Teleporting: 13264 13406 case MachineState_TeleportingPausedVM: 13407 case MachineState_OnlineSnapshotting: 13265 13408 case MachineState_LiveSnapshotting: 13266 13409 case MachineState_DeletingSnapshotOnline: … … 13536 13679 { 13537 13680 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); 13538 directControl = mData->mSession.mDirectControl; 13681 if (mData->mSession.mLockType == LockType_VM) 13682 directControl = mData->mSession.mDirectControl; 13539 13683 } 13540 13684 … … 13561 13705 { 13562 13706 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); 13563 directControl = mData->mSession.mDirectControl; 13707 if (mData->mSession.mLockType == LockType_VM) 13708 directControl = mData->mSession.mDirectControl; 13564 13709 } 13565 13710 … … 13589 13734 { 13590 13735 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); 13591 directControl = mData->mSession.mDirectControl; 13736 if (mData->mSession.mLockType == LockType_VM) 13737 directControl = mData->mSession.mDirectControl; 13592 13738 } 13593 13739 … … 13612 13758 { 13613 13759 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); 13614 directControl = mData->mSession.mDirectControl; 13760 if (mData->mSession.mLockType == LockType_VM) 13761 directControl = mData->mSession.mDirectControl; 13615 13762 } 13616 13763 … … 13635 13782 { 13636 13783 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); 13637 directControl = mData->mSession.mDirectControl; 13784 if (mData->mSession.mLockType == LockType_VM) 13785 directControl = mData->mSession.mDirectControl; 13638 13786 } 13639 13787 … … 13658 13806 { 13659 13807 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); 13660 directControl = mData->mSession.mDirectControl; 13808 if (mData->mSession.mLockType == LockType_VM) 13809 directControl = mData->mSession.mDirectControl; 13661 13810 } 13662 13811 … … 13681 13830 { 13682 13831 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); 13683 directControl = mData->mSession.mDirectControl; 13832 if (mData->mSession.mLockType == LockType_VM) 13833 directControl = mData->mSession.mDirectControl; 13684 13834 } 13685 13835 … … 13701 13851 { 13702 13852 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); 13703 directControl = mData->mSession.mDirectControl; 13853 if (mData->mSession.mLockType == LockType_VM) 13854 directControl = mData->mSession.mDirectControl; 13704 13855 } 13705 13856 … … 13724 13875 { 13725 13876 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); 13726 directControl = mData->mSession.mDirectControl; 13877 if (mData->mSession.mLockType == LockType_VM) 13878 directControl = mData->mSession.mDirectControl; 13727 13879 } 13728 13880 … … 13747 13899 { 13748 13900 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); 13749 directControl = mData->mSession.mDirectControl; 13901 if (mData->mSession.mLockType == LockType_VM) 13902 directControl = mData->mSession.mDirectControl; 13750 13903 } 13751 13904 … … 13770 13923 { 13771 13924 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); 13772 directControl = mData->mSession.mDirectControl; 13925 if (mData->mSession.mLockType == LockType_VM) 13926 directControl = mData->mSession.mDirectControl; 13773 13927 } 13774 13928 … … 13793 13947 { 13794 13948 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); 13795 directControl = mData->mSession.mDirectControl; 13949 if (mData->mSession.mLockType == LockType_VM) 13950 directControl = mData->mSession.mDirectControl; 13796 13951 } 13797 13952 … … 13816 13971 { 13817 13972 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); 13818 directControl = mData->mSession.mDirectControl; 13973 if (mData->mSession.mLockType == LockType_VM) 13974 directControl = mData->mSession.mDirectControl; 13819 13975 } 13820 13976 … … 13839 13995 { 13840 13996 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); 13841 directControl = mData->mSession.mDirectControl; 13997 if (mData->mSession.mLockType == LockType_VM) 13998 directControl = mData->mSession.mDirectControl; 13842 13999 } 13843 14000 … … 13862 14019 { 13863 14020 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); 13864 directControl = mData->mSession.mDirectControl; 14021 if (mData->mSession.mLockType == LockType_VM) 14022 directControl = mData->mSession.mDirectControl; 13865 14023 } 13866 14024 … … 13885 14043 { 13886 14044 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); 13887 directControl = mData->mSession.mDirectControl; 14045 if (mData->mSession.mLockType == LockType_VM) 14046 directControl = mData->mSession.mDirectControl; 13888 14047 } 13889 14048 … … 13951 14110 { 13952 14111 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); 13953 directControl = mData->mSession.mDirectControl; 14112 if (mData->mSession.mLockType == LockType_VM) 14113 directControl = mData->mSession.mDirectControl; 13954 14114 } 13955 14115 … … 13983 14143 { 13984 14144 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); 13985 directControl = mData->mSession.mDirectControl; 14145 if (mData->mSession.mLockType == LockType_VM) 14146 directControl = mData->mSession.mDirectControl; 13986 14147 } 13987 14148 … … 14000 14161 // protected methods 14001 14162 ///////////////////////////////////////////////////////////////////////////// 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 successfully14009 * @param aErrMsg human readable error message for failure14010 *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 since14031 // we can't have a name change pending at this point14032 }14033 else14034 {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 because14037 // we certainly created this saved state file here anew14038 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 else14046 {14047 if (aErrMsg.length())14048 mConsoleTaskData.mProgress->i_notifyComplete(aRc,14049 COM_IIDOF(ISession),14050 getComponentName(),14051 aErrMsg.c_str());14052 else14053 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 }14064 14163 14065 14164 /** … … 14259 14358 || oldMachineState == MachineState_Paused 14260 14359 || oldMachineState == MachineState_Teleporting 14360 || oldMachineState == MachineState_OnlineSnapshotting 14261 14361 || oldMachineState == MachineState_LiveSnapshotting 14262 14362 || oldMachineState == MachineState_Stuck … … 14273 14373 || aMachineState == MachineState_Aborted 14274 14374 ) 14275 /* ignore PoweredOff->Saving->PoweredOff transition when taking a14276 * snapshot */14277 && ( mConsoleTaskData.mSnapshot.isNull()14278 || mConsoleTaskData.mLastState >= MachineState_Running /** @todo Live Migration: clean up (lazy bird) */14279 )14280 14375 ) 14281 14376 { … … 14310 14405 { 14311 14406 /* 14312 * delete the saved state after Console::ForgetSavedState() is called14407 * delete the saved state after SessionMachine::ForgetSavedState() is called 14313 14408 * or if the VM process (owning a direct VM session) crashed while the 14314 14409 * VM was Saved … … 14456 14551 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); 14457 14552 AssertReturn(!!mData, E_FAIL); 14458 directControl = mData->mSession.mDirectControl; 14553 if (mData->mSession.mLockType == LockType_VM) 14554 directControl = mData->mSession.mDirectControl; 14459 14555 14460 14556 /* directControl may be already set to NULL here in #OnSessionEnd() … … 14469 14565 if (mData->mSession.mState == SessionState_Unlocking) 14470 14566 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; 14474 14572 14475 14573 return directControl->UpdateMachineState(mData->mMachineState); 14476 14574 } 14477 14575 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*/ 14596 HRESULT 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 14483 14610 14484 14611 HRESULT Machine::updateState(MachineState_T aState) … … 14558 14685 } 14559 14686 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 14620 14687 HRESULT Machine::finishOnlineMergeMedium() 14621 14688 { 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);14634 14689 ReturnComNotImplemented(); 14635 14690 } -
trunk/src/VBox/Main/src-server/Performance.cpp
r51498 r55214 5 5 6 6 /* 7 * Copyright (C) 2008-201 4Oracle Corporation7 * Copyright (C) 2008-2015 Oracle Corporation 8 8 * 9 9 * This file is part of VirtualBox Open Source Edition (OSE), as … … 311 311 312 312 /* get the associated console; this is a remote call (!) */ 313 ret = directControl-> GetRemoteConsole(mConsole.asOutParam());313 ret = directControl->COMGETTER(RemoteConsole)(mConsole.asOutParam()); 314 314 if (ret != S_OK) 315 315 return ret; -
trunk/src/VBox/Main/src-server/SnapshotImpl.cpp
r54948 r55214 412 412 } 413 413 414 HRESULT Snapshot::getChildrenCount(ULONG *count)414 HRESULT Snapshot::getChildrenCount(ULONG *count) 415 415 { 416 416 *count = i_getChildrenCount(); … … 1305 1305 1306 1306 /** 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. 1313 1309 */ 1314 1310 struct SessionMachine::SnapshotTask 1311 : public SessionMachine::Task 1315 1312 { 1316 1313 SnapshotTask(SessionMachine *m, 1317 1314 Progress *p, 1315 const Utf8Str &t, 1318 1316 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) 1323 1319 {} 1324 1320 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; 1336 1322 }; 1337 1323 1338 /** Restore snapshot state task */ 1324 /** Take snapshot task */ 1325 struct 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 */ 1339 1363 struct SessionMachine::RestoreSnapshotTask 1340 1364 : public SessionMachine::SnapshotTask … … 1342 1366 RestoreSnapshotTask(SessionMachine *m, 1343 1367 Progress *p, 1368 const Utf8Str &t, 1344 1369 Snapshot *s) 1345 : SnapshotTask(m, p, s)1370 : SnapshotTask(m, p, t, s) 1346 1371 {} 1347 1372 1348 1373 void handler() 1349 1374 { 1350 pMachine->i_restoreSnapshotHandler(*this);1375 ((SessionMachine *)(Machine *)m_pMachine)->i_restoreSnapshotHandler(*this); 1351 1376 } 1352 1377 }; … … 1358 1383 DeleteSnapshotTask(SessionMachine *m, 1359 1384 Progress *p, 1385 const Utf8Str &t, 1360 1386 bool fDeleteOnline, 1361 1387 Snapshot *s) 1362 : SnapshotTask(m, p, s),1388 : SnapshotTask(m, p, t, s), 1363 1389 m_fDeleteOnline(fDeleteOnline) 1364 1390 {} … … 1366 1392 void handler() 1367 1393 { 1368 pMachine->i_deleteSnapshotHandler(*this);1394 ((SessionMachine *)(Machine *)m_pMachine)->i_deleteSnapshotHandler(*this); 1369 1395 } 1370 1396 … … 1372 1398 }; 1373 1399 1374 /**1375 * Static SessionMachine method that can get passed to RTThreadCreate to1376 * 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 task1389 delete task;1390 1391 return 0;1392 }1393 1400 1394 1401 //////////////////////////////////////////////////////////////////////////////// 1395 1402 // 1396 // TakeSnapshot methods ( SessionMachine and related tasks)1403 // TakeSnapshot methods (Machine and related tasks) 1397 1404 // 1398 1405 //////////////////////////////////////////////////////////////////////////////// 1399 1406 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. 1407 HRESULT 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 1419 HRESULT 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 1430 1517 * @return 1431 1518 */ 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); 1519 void SessionMachine::i_takeSnapshotHandler(TakeSnapshotTask &task) 1520 { 1440 1521 LogFlowThisFuncEnter(); 1441 1522 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 } 1443 1546 1444 1547 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); 1445 1548 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); 1468 1576 // no need to check for whether VirtualBox.xml needs changing since 1469 1577 // 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 */ 1528 1630 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() 1533 1635 i_setModified(IsModified_Storage); 1534 1636 mMediaData.backup(); 1535 1637 1536 /* Console::fntTakeSnapshotWorker and friends expects this. */1537 if (mConsoleTaskData.mLastState == MachineState_Running)1538 i_setMachineState(MachineState_LiveSnapshotting);1539 else1540 i_setMachineState(MachineState_Saving); /** @todo Confusing! Saving is used for both online and offline snapshots. */1541 1542 1638 alock.release(); 1543 1639 /* 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); 1547 1643 if (FAILED(rc)) 1548 1644 throw rc; 1645 alock.acquire(); 1549 1646 1550 1647 // MUST NOT save the settings or the media registry here, because 1551 1648 // this causes trouble with rolling back settings if the user cancels 1552 1649 // 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*/ 1810 void 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 /** 1584 1820 * Called by the Console when it's done saving the VM state into the snapshot 1585 1821 * (if online) and reconfiguring the hard disks. See BeginTakingSnapshot() above. … … 1593 1829 * @return 1594 1830 */ 1595 HRESULT SessionMachine:: endTakingSnapshot(BOOLaSuccess)1831 HRESULT SessionMachine::i_finishTakingSnapshot(TakeSnapshotTask &task, AutoWriteLock &alock, bool aSuccess) 1596 1832 { 1597 1833 LogFlowThisFunc(("\n")); 1598 1834 1599 A utoWriteLock machineLock(this COMMA_LOCKVAL_SRC_POS);1835 Assert(alock.isWriteLockOnCurrentThread()); 1600 1836 1601 1837 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); 1619 1841 1620 1842 ComObjPtr<Snapshot> pOldFirstSnap = mData->mFirstSnapshot; 1621 1843 ComObjPtr<Snapshot> pOldCurrentSnap = mData->mCurrentSnapshot; 1622 1844 1623 bool fOnline = Global::IsOnline( mConsoleTaskData.mLastState);1845 bool fOnline = Global::IsOnline(task.m_machineStateBackup); 1624 1846 1625 1847 HRESULT rc = S_OK; … … 1628 1850 { 1629 1851 // new snapshot becomes the current one 1630 mData->mCurrentSnapshot = mConsoleTaskData.mSnapshot;1852 mData->mCurrentSnapshot = task.m_pSnapshot; 1631 1853 1632 1854 /* memorize the first snapshot if necessary */ … … 1651 1873 /* inform callbacks */ 1652 1874 mParent->i_onSnapshotTaken(mData->mUuid, 1653 mConsoleTaskData.mSnapshot->i_getId());1654 machineLock.release();1875 task.m_pSnapshot->i_getId()); 1876 alock.release(); 1655 1877 } 1656 1878 else … … 1658 1880 /* delete all differencing hard disks created (this will also attach 1659 1881 * their parents back by rolling back mMediaData) */ 1660 machineLock.release();1882 alock.release(); 1661 1883 1662 1884 i_rollbackMedia(); … … 1670 1892 // snapshot means that a new saved state file was created, which we must 1671 1893 // 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(); 1678 1900 1679 1901 } 1680 1902 1681 1903 /* 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 */ 1687 1907 mParent->i_saveModifiedRegistries(); 1908 1909 alock.acquire(); 1688 1910 1689 1911 return rc; … … 1692 1914 //////////////////////////////////////////////////////////////////////////////// 1693 1915 // 1694 // RestoreSnapshot methods ( SessionMachine and related tasks)1916 // RestoreSnapshot methods (Machine and related tasks) 1695 1917 // 1696 1918 //////////////////////////////////////////////////////////////////////////////// 1697 1919 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 * 1920 HRESULT 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. 1709 1932 * Actual work then takes place in RestoreSnapshotTask::handler(). 1710 1933 * 1711 1934 * @note Locks this + children objects for writing! 1712 1935 * 1713 * @param aInitiator in: rhe console on which Console::RestoreSnapshot was called.1714 1936 * @param aSnapshot in: the snapshot to restore. 1715 * @param aMachineState in: client-side machine state.1716 1937 * @param aProgress out: progress object to monitor restore thread. 1717 1938 * @return 1718 1939 */ 1719 HRESULT SessionMachine::restoreSnapshot(const ComPtr<IConsole> &aInitiator, 1720 const ComPtr<ISnapshot> &aSnapshot, 1721 MachineState_T *aMachineState, 1940 HRESULT SessionMachine::restoreSnapshot(const ComPtr<ISnapshot> &aSnapshot, 1722 1941 ComPtr<IProgress> &aProgress) 1723 1942 { … … 1727 1946 1728 1947 // 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)); 1731 1952 1732 1953 ISnapshot* iSnapshot = aSnapshot; 1733 1954 ComObjPtr<Snapshot> pSnapshot(static_cast<Snapshot*>(iSnapshot)); 1734 1955 ComObjPtr<SnapshotMachine> pSnapMachine = pSnapshot->i_getSnapshotMachine(); 1956 1957 HRESULT rc = S_OK; 1735 1958 1736 1959 // create a progress object. The number of operations is: … … 1758 1981 ComObjPtr<Progress> pProgress; 1759 1982 pProgress.createObject(); 1760 pProgress->init(mParent, aInitiator,1983 pProgress->init(mParent, static_cast<IMachine*>(this), 1761 1984 BstrFmt(tr("Restoring snapshot '%s'"), pSnapshot->i_getName().c_str()).raw(), 1762 1985 FALSE /* aCancelable */, … … 1768 1991 /* create and start the task on a separate thread (note that it will not 1769 1992 * 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; 1785 2000 1786 2001 /* set the proper machine state (note: after creating a Task instance) */ … … 1789 2004 /* return the progress to the caller */ 1790 2005 pProgress.queryInterfaceTo(aProgress.asOutParam()); 1791 1792 /* return the new state to the caller */1793 *aMachineState = mData->mMachineState;1794 2006 1795 2007 LogFlowThisFuncLeave(); … … 1808 2020 * @note Locks mParent + this object for writing. 1809 2021 * 1810 * @param aTask Task data.1811 */ 1812 void SessionMachine::i_restoreSnapshotHandler(RestoreSnapshotTask & aTask)2022 * @param pTask Task data. 2023 */ 2024 void SessionMachine::i_restoreSnapshotHandler(RestoreSnapshotTask &task) 1813 2025 { 1814 2026 LogFlowThisFuncEnter(); … … 1821 2033 /* we might have been uninitialized because the session was accidentally 1822 2034 * 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")); 1827 2039 1828 2040 LogFlowThisFuncLeave(); … … 1846 2058 /* Delete the saved state file if the machine was Saved prior to this 1847 2059 * operation */ 1848 if ( aTask.machineStateBackup == MachineState_Saved)2060 if (task.m_machineStateBackup == MachineState_Saved) 1849 2061 { 1850 2062 Assert(!mSSData->strStateFilePath.isEmpty()); … … 1856 2068 i_releaseSavedStateFile(strStateFile, NULL /* pSnapshotToIgnore */ ); 1857 2069 1858 aTask.modifyBackedUpState(MachineState_PoweredOff);2070 task.modifyBackedUpState(MachineState_PoweredOff); 1859 2071 1860 2072 rc = i_saveStateSettings(SaveSTS_StateFilePath); … … 1867 2079 1868 2080 { 1869 AutoReadLock snapshotLock( aTask.pSnapshot COMMA_LOCKVAL_SRC_POS);2081 AutoReadLock snapshotLock(task.m_pSnapshot COMMA_LOCKVAL_SRC_POS); 1870 2082 1871 2083 /* 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()); 1875 2087 1876 2088 /* copy all hardware data from the snapshot */ … … 1897 2109 alock.release(); 1898 2110 1899 rc = i_createImplicitDiffs( aTask.pProgress,2111 rc = i_createImplicitDiffs(task.m_pProgress, 1900 2112 1, 1901 2113 false /* aOnline */); … … 1907 2119 1908 2120 /* Note: on success, current (old) hard disks will be 1909 * deassociated/deleted on #commit() called from # saveSettings() at2121 * deassociated/deleted on #commit() called from #i_saveSettings() at 1910 2122 * the end. On failure, newly created implicit diffs will be 1911 2123 * deleted by #rollback() at the end. */ … … 1914 2126 Assert(mSSData->strStateFilePath.isEmpty()); 1915 2127 1916 const Utf8Str &strSnapshotStateFile = aTask.pSnapshot->i_getStateFilePath();2128 const Utf8Str &strSnapshotStateFile = task.m_pSnapshot->i_getStateFilePath(); 1917 2129 1918 2130 if (strSnapshotStateFile.isNotEmpty()) … … 1920 2132 mSSData->strStateFilePath = strSnapshotStateFile; 1921 2133 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())); 1923 2135 /* make the snapshot we restored from the current snapshot */ 1924 mData->mCurrentSnapshot = aTask.pSnapshot;2136 mData->mCurrentSnapshot = task.m_pSnapshot; 1925 2137 } 1926 2138 … … 1969 2181 1970 2182 // 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() 1972 2184 1973 2185 MediaList llDiffsToDelete; … … 1985 2197 1986 2198 // Normally we "detach" the medium by removing the attachment object 1987 // from the current machine data; saveSettings() below would then2199 // from the current machine data; i_saveSettings() below would then 1988 2200 // compare the current machine data with the one in the backup 1989 2201 // and actually call Medium::removeBackReference(). But that works only half … … 1991 2203 // remove from machine data 1992 2204 mMediaData->mAttachments.remove(pAttach); 1993 // Remove it from the backup or else saveSettings will try to detach2205 // Remove it from the backup or else i_saveSettings will try to detach 1994 2206 // it again and assert. The paranoia check avoids crashes (see 1995 2207 // assert above) if this code is buggy and saves settings in the … … 2009 2221 if (FAILED(rc)) 2010 2222 throw rc; 2011 // unconditionally add the parent registry. We do similar in SessionMachine::EndTakingSnapshot2012 // (mParent->saveSettings())2013 2223 2014 2224 // release the locks before updating registry and deleting image files 2015 2225 alock.release(); 2016 2226 2227 // unconditionally add the parent registry. 2017 2228 mParent->i_markRegistryModified(mParent->i_getGlobalRegistryId()); 2018 2229 … … 2028 2239 HRESULT rc2 = pMedium->i_deleteStorage(NULL /* aProgress */, 2029 2240 true /* aWait */); 2030 // ignore errors here because we cannot roll back after saveSettings() above2241 // ignore errors here because we cannot roll back after i_saveSettings() above 2031 2242 if (SUCCEEDED(rc2)) 2032 2243 pMedium->uninit(); … … 2049 2260 { 2050 2261 /* restore the machine state */ 2051 i_setMachineState( aTask.machineStateBackup);2262 i_setMachineState(task.m_machineStateBackup); 2052 2263 i_updateMachineStateOnClient(); 2053 2264 } … … 2057 2268 2058 2269 /* 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); 2060 2271 2061 2272 if (SUCCEEDED(rc)) … … 2073 2284 //////////////////////////////////////////////////////////////////////////////// 2074 2285 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. 2286 HRESULT Machine::deleteSnapshot(const com::Guid &aId, ComPtr<IProgress> &aProgress) 2287 { 2288 NOREF(aId); 2289 NOREF(aProgress); 2290 ReturnComNotImplemented(); 2291 } 2292 2293 HRESULT SessionMachine::deleteSnapshot(const com::Guid &aId, ComPtr<IProgress> &aProgress) 2294 { 2295 return i_deleteSnapshot(aId, aId, 2296 FALSE /* fDeleteAllChildren */, 2297 aProgress); 2298 } 2299 2300 HRESULT Machine::deleteSnapshotAndAllChildren(const com::Guid &aId, ComPtr<IProgress> &aProgress) 2301 { 2302 NOREF(aId); 2303 NOREF(aProgress); 2304 ReturnComNotImplemented(); 2305 } 2306 2307 HRESULT SessionMachine::deleteSnapshotAndAllChildren(const com::Guid &aId, ComPtr<IProgress> &aProgress) 2308 { 2309 return i_deleteSnapshot(aId, aId, 2310 TRUE /* fDeleteAllChildren */, 2311 aProgress); 2312 } 2313 2314 HRESULT 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 2322 HRESULT 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. 2082 2336 * 2083 2337 * 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(). 2088 2341 * 2089 2342 * @note Locks mParent + this + children objects for writing! 2090 2343 */ 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) 2344 HRESULT SessionMachine::i_deleteSnapshot(const com::Guid &aStartId, 2345 const com::Guid &aEndId, 2346 BOOL aDeleteAllChildren, 2347 ComPtr<IProgress> &aProgress) 2097 2348 { 2098 2349 LogFlowThisFuncEnter(); 2099 2350 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); 2101 2352 2102 2353 … … 2106 2357 2107 2358 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)); 2108 2364 2109 2365 // be very picky about machine states … … 2200 2456 ComObjPtr<Progress> pProgress; 2201 2457 pProgress.createObject(); 2202 pProgress->init(mParent, aInitiator,2458 pProgress->init(mParent, static_cast<IMachine*>(this), 2203 2459 BstrFmt(tr("Deleting snapshot '%s'"), pSnapshot->i_getName().c_str()).raw(), 2204 2460 FALSE /* aCancelable */, … … 2212 2468 2213 2469 /* 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; 2228 2477 2229 2478 // the task might start running but will block on acquiring the machine's write lock … … 2236 2485 else 2237 2486 i_setMachineState(MachineState_DeletingSnapshot); 2487 i_updateMachineStateOnClient(); 2238 2488 2239 2489 /* return the progress to the caller */ 2240 2490 pProgress.queryInterfaceTo(aProgress.asOutParam()); 2241 2242 /* return the new state to the caller */2243 *aMachineState = mData->mMachineState;2244 2491 2245 2492 LogFlowThisFuncLeave(); … … 2341 2588 * @note Locks the machine + the snapshot + the media tree for writing! 2342 2589 * 2343 * @param aTask Task data. 2344 */ 2345 2346 void SessionMachine::i_deleteSnapshotHandler(DeleteSnapshotTask &aTask) 2590 * @param pTask Task data. 2591 */ 2592 void SessionMachine::i_deleteSnapshotHandler(DeleteSnapshotTask &task) 2347 2593 { 2348 2594 LogFlowThisFuncEnter(); 2349 2595 2596 HRESULT rc = S_OK; 2350 2597 AutoCaller autoCaller(this); 2351 2352 2598 LogFlowThisFunc(("state=%d\n", getObjectState().getState())); 2353 if ( !autoCaller.isOk())2599 if (FAILED(autoCaller.rc())) 2354 2600 { 2355 2601 /* we might have been uninitialized because the session was accidentally 2356 2602 * 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); 2361 2606 LogFlowThisFuncLeave(); 2362 2607 return; 2363 2608 } 2364 2609 2365 HRESULT rc = S_OK;2366 2610 MediumDeleteRecList toDelete; 2367 2611 Guid snapshotId; … … 2371 2615 /* Locking order: */ 2372 2616 AutoMultiWriteLock2 multiLock(this->lockHandle(), // machine 2373 aTask.pSnapshot->lockHandle()// snapshot2617 task.m_pSnapshot->lockHandle() // snapshot 2374 2618 COMMA_LOCKVAL_SRC_POS); 2375 2619 // once we have this lock, we know that SessionMachine::DeleteSnapshot() … … 2379 2623 COMMA_LOCKVAL_SRC_POS); 2380 2624 2381 ComObjPtr<SnapshotMachine> pSnapMachine = aTask.pSnapshot->i_getSnapshotMachine();2625 ComObjPtr<SnapshotMachine> pSnapMachine = task.m_pSnapshot->i_getSnapshotMachine(); 2382 2626 // no need to lock the snapshot machine since it is const by definition 2383 2627 Guid machineId = pSnapMachine->i_getId(); 2384 2628 2385 2629 // save the snapshot ID (for callbacks) 2386 snapshotId = aTask.pSnapshot->i_getId();2630 snapshotId = task.m_pSnapshot->i_getId(); 2387 2631 2388 2632 // first pass: … … 2428 2672 MediumLockList *pChildrenToReparent = NULL; 2429 2673 bool fNeedsOnlineMerge = false; 2430 bool fOnlineMergePossible = aTask.m_fDeleteOnline;2674 bool fOnlineMergePossible = task.m_fDeleteOnline; 2431 2675 MediumLockList *pMediumLockList = NULL; 2432 2676 MediumLockList *pVMMALockList = NULL; … … 2666 2910 AutoWriteLock machineLock(this COMMA_LOCKVAL_SRC_POS); 2667 2911 2668 Utf8Str stateFilePath = aTask.pSnapshot->i_getStateFilePath();2912 Utf8Str stateFilePath = task.m_pSnapshot->i_getStateFilePath(); 2669 2913 if (!stateFilePath.isEmpty()) 2670 2914 { 2671 aTask.pProgress->SetNextOperation(Bstr(tr("Deleting the execution state")).raw(),2672 1); // weight2673 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 */); 2675 2919 2676 2920 // machine will need saving now … … 2697 2941 } 2698 2942 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); 2702 2946 2703 2947 bool fNeedSourceUninit = false; … … 2722 2966 /* No need to hold the lock any longer. */ 2723 2967 mLock.release(); 2724 rc = pMedium->i_deleteStorage(& aTask.pProgress,2968 rc = pMedium->i_deleteStorage(&task.m_pProgress, 2725 2969 true /* aWait */); 2726 2970 if (FAILED(rc)) … … 2740 2984 // This callback will arrive while onlineMergeMedium is 2741 2985 // 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. 2742 2987 mConsoleTaskData.mDeleteSnapshotInfo = (void *)&(*it); 2743 2988 // online medium merge, in the direction decided earlier … … 2749 2994 it->mpChildrenToReparent, 2750 2995 it->mpMediumLockList, 2751 aTask.pProgress,2996 task.m_pProgress, 2752 2997 &fNeedsSave); 2753 2998 mConsoleTaskData.mDeleteSnapshotInfo = NULL; … … 2761 3006 it->mpChildrenToReparent, 2762 3007 it->mpMediumLockList, 2763 & aTask.pProgress,3008 &task.m_pProgress, 2764 3009 true /* aWait */); 2765 3010 } … … 2826 3071 ComObjPtr<Machine> pMachine = this; 2827 3072 Guid childSnapshotId; 2828 ComObjPtr<Snapshot> pChildSnapshot = aTask.pSnapshot->i_getFirstChild();3073 ComObjPtr<Snapshot> pChildSnapshot = task.m_pSnapshot->i_getFirstChild(); 2829 3074 if (pChildSnapshot) 2830 3075 { … … 2871 3116 AutoWriteLock machineLock(this COMMA_LOCKVAL_SRC_POS); 2872 3117 2873 aTask.pSnapshot->i_beginSnapshotDelete();2874 aTask.pSnapshot->uninit();3118 task.m_pSnapshot->i_beginSnapshotDelete(); 3119 task.m_pSnapshot->uninit(); 2875 3120 2876 3121 machineLock.release(); … … 2912 3157 // restore the machine state that was saved when the 2913 3158 // task was started 2914 i_setMachineState( aTask.machineStateBackup);3159 i_setMachineState(task.m_machineStateBackup); 2915 3160 i_updateMachineStateOnClient(); 2916 3161 … … 2919 3164 2920 3165 // 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); 2922 3167 2923 3168 if (SUCCEEDED(rc)) … … 3061 3306 aSource = aHD; 3062 3307 aTarget = pChild; 3063 LogFlow Func(("Forward merging selected\n"));3308 LogFlowThisFunc(("Forward merging selected\n")); 3064 3309 } 3065 3310 else … … 3067 3312 aSource = pChild; 3068 3313 aTarget = aHD; 3069 LogFlow Func(("Backward merging selected\n"));3314 LogFlowThisFunc(("Backward merging selected\n")); 3070 3315 } 3071 3316 } … … 3580 3825 AssertComRC(rc); 3581 3826 3827 treeLock.release(); 3582 3828 pMedium->uninit(); 3829 treeLock.acquire(); 3583 3830 } 3584 3831
Note:
See TracChangeset
for help on using the changeset viewer.