- Timestamp:
- Oct 17, 2008 1:01:44 PM (16 years ago)
- Location:
- trunk/src/VBox
- Files:
-
- 9 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Frontends/VirtualBox/include/VBoxProblemReporter.h
r11228 r13374 170 170 void cannotTakeSnapshot (const CProgress &progress); 171 171 void cannotStopMachine (const CConsole &console); 172 void cannotStopMachine (const CProgress &progress); 172 173 void cannotDeleteMachine (const CVirtualBox &vbox, const CMachine &machine); 173 174 void cannotDiscardSavedState (const CConsole &console); -
trunk/src/VBox/Frontends/VirtualBox/src/VBoxConsoleWnd.cpp
r12424 r13374 1302 1302 if (dlg.rbPowerOff->isChecked()) 1303 1303 { 1304 cconsole.PowerDown(); 1305 if (!cconsole.isOk()) 1304 CProgress progress = cconsole.PowerDownAsync(); 1305 1306 if (cconsole.isOk()) 1306 1307 { 1307 /// @todo (dmik) add an option to close the GUI anyway 1308 // and handle it 1309 vboxProblem().cannotStopMachine (cconsole); 1308 /* show the power down progress dialog */ 1309 vboxProblem() 1310 .showModalProgressDialog (progress, cmachine.GetName(), 1311 this, 0); 1312 if (progress.GetResultCode() != 0) 1313 vboxProblem().cannotStopMachine (progress); 1314 else 1315 success = true; 1310 1316 } 1311 1317 else 1318 vboxProblem().cannotStopMachine (cconsole); 1319 1320 if (success) 1312 1321 { 1313 /* 1314 * set success to true even if we fail to discard the 1315 * current state later -- the console window will be 1316 * closed anyway 1317 */ 1318 success = true; 1322 /* Note: leave success = true even if we fail to 1323 * discard the current state later -- the console window 1324 * will closed anyway */ 1319 1325 1320 1326 /* discard the current state if requested */ -
trunk/src/VBox/Frontends/VirtualBox/src/VBoxProblemReporter.cpp
r11228 r13374 811 811 } 812 812 813 void VBoxProblemReporter::cannotStopMachine (const CProgress &progress) 814 { 815 AssertWrapperOk (progress); 816 CConsole console = CProgress (progress).GetInitiator(); 817 AssertWrapperOk (console); 818 819 message (mainWindowShown(), Error, 820 tr ("Failed to stop the virtual machine <b>%1</b>.") 821 .arg (console.GetMachine().GetName()), 822 formatErrorInfo (progress.GetErrorInfo())); 823 } 824 813 825 void VBoxProblemReporter::cannotDeleteMachine (const CVirtualBox &vbox, 814 826 const CMachine &machine) -
trunk/src/VBox/Frontends/VirtualBox4/include/VBoxProblemReporter.h
r12010 r13374 227 227 void cannotTakeSnapshot (const CProgress &progress); 228 228 void cannotStopMachine (const CConsole &console); 229 void cannotStopMachine (const CProgress &progress); 229 230 void cannotDeleteMachine (const CVirtualBox &vbox, const CMachine &machine); 230 231 void cannotDiscardSavedState (const CConsole &console); -
trunk/src/VBox/Frontends/VirtualBox4/src/VBoxConsoleWnd.cpp
r13278 r13374 1337 1337 if (dlg.mRbPowerOff->isChecked()) 1338 1338 { 1339 cconsole.PowerDown(); 1340 if (!cconsole.isOk()) 1339 CProgress progress = cconsole.PowerDownAsync(); 1340 1341 if (cconsole.isOk()) 1341 1342 { 1342 /// @todo (dmik) add an option to close the GUI anyway 1343 // and handle it 1344 vboxProblem().cannotStopMachine (cconsole); 1343 /* show the power down progress dialog */ 1344 vboxProblem() 1345 .showModalProgressDialog (progress, cmachine.GetName(), 1346 this, 0); 1347 if (progress.GetResultCode() != 0) 1348 vboxProblem().cannotStopMachine (progress); 1349 else 1350 success = true; 1345 1351 } 1346 1352 else 1353 vboxProblem().cannotStopMachine (cconsole); 1354 1355 if (success) 1347 1356 { 1348 /* 1349 * set success to true even if we fail to discard the 1350 * current state later -- the console window will be 1351 * closed anyway 1352 */ 1353 success = true; 1357 /* Note: leave success = true even if we fail to 1358 * discard the current state later -- the console window 1359 * will closed anyway */ 1354 1360 1355 1361 /* discard the current state if requested */ -
trunk/src/VBox/Frontends/VirtualBox4/src/VBoxProblemReporter.cpp
r12777 r13374 887 887 } 888 888 889 void VBoxProblemReporter::cannotStopMachine (const CProgress &progress) 890 { 891 AssertWrapperOk (progress); 892 CConsole console = CProgress (progress).GetInitiator(); 893 AssertWrapperOk (console); 894 895 message (mainWindowShown(), Error, 896 tr ("Failed to stop the virtual machine <b>%1</b>.") 897 .arg (console.GetMachine().GetName()), 898 formatErrorInfo (progress.GetErrorInfo())); 899 } 900 889 901 void VBoxProblemReporter::cannotDeleteMachine (const CVirtualBox &vbox, 890 902 const CMachine &machine) -
trunk/src/VBox/Main/ConsoleImpl.cpp
r13333 r13374 98 98 99 99 /** 100 * Task structure for asynchronous VM operations. 101 * 102 * Once created, the task structure adds itself as a Console caller. 103 * This means: 104 * 105 * 1. The user must check for #rc() before using the created structure 106 * (e.g. passing it as a thread function argument). If #rc() returns a 107 * failure, the Console object may not be used by the task (see 108 Console::addCaller() for more details). 109 * 2. On successful initialization, the structure keeps the Console caller 110 * until destruction (to ensure Console remains in the Ready state and won't 111 * be accidentially uninitialized). Forgetting to delete the created task 112 * will lead to Console::uninit() stuck waiting for releasing all added 113 * callers. 114 * 115 * If \a aUsesVMPtr parameter is true, the task structure will also add itself 116 * as a Console::mpVM caller with the same meaning as above. See 117 * Console::addVMCaller() for more info. 100 * Task structure for asynchronous VM operations. 101 * 102 * Once created, the task structure adds itself as a Console caller. This means: 103 * 104 * 1. The user must check for #rc() before using the created structure 105 * (e.g. passing it as a thread function argument). If #rc() returns a 106 * failure, the Console object may not be used by the task (see 107 Console::addCaller() for more details). 108 * 2. On successful initialization, the structure keeps the Console caller 109 * until destruction (to ensure Console remains in the Ready state and won't 110 * be accidentially uninitialized). Forgetting to delete the created task 111 * will lead to Console::uninit() stuck waiting for releasing all added 112 * callers. 113 * 114 * If \a aUsesVMPtr parameter is true, the task structure will also add itself 115 * as a Console::mpVM caller with the same meaning as above. See 116 * Console::addVMCaller() for more info. 118 117 */ 119 118 struct VMTask … … 208 207 }; 209 208 210 211 209 // constructor / desctructor 212 210 ///////////////////////////////////////////////////////////////////////////// … … 219 217 , mVMZeroCallersSem (NIL_RTSEMEVENT) 220 218 , mVMDestroying (false) 219 , mVMPoweredOff (false) 221 220 , meDVDState (DriveState_NotMounted) 222 221 , meFloppyState (DriveState_NotMounted) … … 1213 1212 STDMETHODIMP Console::PowerUp (IProgress **aProgress) 1214 1213 { 1215 return powerUp Common(aProgress, false /* aPaused */);1214 return powerUp (aProgress, false /* aPaused */); 1216 1215 } 1217 1216 1218 1217 STDMETHODIMP Console::PowerUpPaused (IProgress **aProgress) 1219 1218 { 1220 return powerUpCommon (aProgress, true /* aPaused */); 1221 } 1222 1223 /** 1224 * Common worker for PowerUp and PowerUpPaused. 1225 * 1226 * @returns COM status code. 1227 * 1228 * @param aProgress Where to return the progress object. 1229 * @param aPaused true if PowerUpPaused called. 1230 * 1231 * @todo move down to powerDown(); 1232 */ 1233 HRESULT Console::powerUpCommon (IProgress **aProgress, bool aPaused) 1219 return powerUp (aProgress, true /* aPaused */); 1220 } 1221 1222 STDMETHODIMP Console::PowerDown() 1234 1223 { 1235 1224 LogFlowThisFuncEnter(); … … 1241 1230 AutoWriteLock alock (this); 1242 1231 1243 if (mMachineState >= MachineState_Running) 1244 return setError(E_FAIL, tr ("Cannot power up the machine as it is " 1245 "already running (machine state: %d)"), 1246 mMachineState); 1247 1248 /* 1249 * First check whether all disks are accessible. This is not a 100% 1250 * bulletproof approach (race condition, it might become inaccessible 1251 * right after the check) but it's convenient as it will cover 99.9% 1252 * of the cases and here, we're able to provide meaningful error 1253 * information. 1254 */ 1255 ComPtr<IHardDiskAttachmentCollection> coll; 1256 mMachine->COMGETTER(HardDiskAttachments)(coll.asOutParam()); 1257 ComPtr<IHardDiskAttachmentEnumerator> enumerator; 1258 coll->Enumerate(enumerator.asOutParam()); 1259 BOOL fHasMore; 1260 while (SUCCEEDED(enumerator->HasMore(&fHasMore)) && fHasMore) 1261 { 1262 ComPtr<IHardDiskAttachment> attach; 1263 enumerator->GetNext(attach.asOutParam()); 1264 ComPtr<IHardDisk> hdd; 1265 attach->COMGETTER(HardDisk)(hdd.asOutParam()); 1266 Assert(hdd); 1267 BOOL fAccessible; 1268 HRESULT rc = hdd->COMGETTER(AllAccessible)(&fAccessible); 1269 CheckComRCReturnRC (rc); 1270 if (!fAccessible) 1271 { 1272 Bstr loc; 1273 hdd->COMGETTER(Location) (loc.asOutParam()); 1274 Bstr errMsg; 1275 hdd->COMGETTER(LastAccessError) (errMsg.asOutParam()); 1232 if (mMachineState != MachineState_Running && 1233 mMachineState != MachineState_Paused && 1234 mMachineState != MachineState_Stuck) 1235 { 1236 /* extra nice error message for a common case */ 1237 if (mMachineState == MachineState_Saved) 1276 1238 return setError (E_FAIL, 1277 tr ("VM cannot start because the hard disk '%ls' is not accessible " 1278 "(%ls)"), 1279 loc.raw(), errMsg.raw()); 1280 } 1281 } 1282 1283 /* now perform the same check if a ISO is mounted */ 1284 ComPtr<IDVDDrive> dvdDrive; 1285 mMachine->COMGETTER(DVDDrive)(dvdDrive.asOutParam()); 1286 ComPtr<IDVDImage> dvdImage; 1287 dvdDrive->GetImage(dvdImage.asOutParam()); 1288 if (dvdImage) 1289 { 1290 BOOL fAccessible; 1291 HRESULT rc = dvdImage->COMGETTER(Accessible)(&fAccessible); 1292 CheckComRCReturnRC (rc); 1293 if (!fAccessible) 1294 { 1295 Bstr filePath; 1296 dvdImage->COMGETTER(FilePath)(filePath.asOutParam()); 1297 /// @todo (r=dmik) grab the last access error once 1298 // IDVDImage::lastAccessError is there 1239 tr ("Cannot power down a saved virtual machine")); 1240 else if (mMachineState == MachineState_Stopping) 1299 1241 return setError (E_FAIL, 1300 tr ("The virtual machine could not be started because the DVD image '%ls' which is attached to it could not be found or could not be opened. Please detach the image and try again"), 1301 filePath.raw()); 1302 } 1303 } 1304 1305 /* now perform the same check if a floppy is mounted */ 1306 ComPtr<IFloppyDrive> floppyDrive; 1307 mMachine->COMGETTER(FloppyDrive)(floppyDrive.asOutParam()); 1308 ComPtr<IFloppyImage> floppyImage; 1309 floppyDrive->GetImage(floppyImage.asOutParam()); 1310 if (floppyImage) 1311 { 1312 BOOL fAccessible; 1313 HRESULT rc = floppyImage->COMGETTER(Accessible)(&fAccessible); 1314 CheckComRCReturnRC (rc); 1315 if (!fAccessible) 1316 { 1317 Bstr filePath; 1318 floppyImage->COMGETTER(FilePath)(filePath.asOutParam()); 1319 /// @todo (r=dmik) grab the last access error once 1320 // IDVDImage::lastAccessError is there 1242 tr ("Virtual machine is being powered down")); 1243 else 1244 return setError(E_FAIL, 1245 tr ("Invalid machine state: %d (must be Running, Paused " 1246 "or Stuck)"), 1247 mMachineState); 1248 } 1249 1250 LogFlowThisFunc (("Sending SHUTDOWN request...\n")); 1251 1252 HRESULT rc = powerDown(); 1253 1254 LogFlowThisFunc (("mMachineState=%d, rc=%08X\n", mMachineState, rc)); 1255 LogFlowThisFuncLeave(); 1256 return rc; 1257 } 1258 1259 STDMETHODIMP Console::PowerDownAsync (IProgress **aProgress) 1260 { 1261 if (aProgress == NULL) 1262 return E_POINTER; 1263 1264 LogFlowThisFuncEnter(); 1265 LogFlowThisFunc (("mMachineState=%d\n", mMachineState)); 1266 1267 AutoCaller autoCaller (this); 1268 CheckComRCReturnRC (autoCaller.rc()); 1269 1270 AutoWriteLock alock (this); 1271 1272 if (mMachineState != MachineState_Running && 1273 mMachineState != MachineState_Paused && 1274 mMachineState != MachineState_Stuck) 1275 { 1276 /* extra nice error message for a common case */ 1277 if (mMachineState == MachineState_Saved) 1321 1278 return setError (E_FAIL, 1322 tr ("The virtual machine could not be started because the floppy image '%ls' which is attached to it could not be found or could not be opened. Please detach the image and try again"), 1323 filePath.raw()); 1324 } 1325 } 1326 1327 /* now the network cards will undergo a quick consistency check */ 1328 for (ULONG slot = 0; slot < SchemaDefs::NetworkAdapterCount; slot ++) 1329 { 1330 ComPtr<INetworkAdapter> adapter; 1331 mMachine->GetNetworkAdapter (slot, adapter.asOutParam()); 1332 BOOL enabled = FALSE; 1333 adapter->COMGETTER(Enabled) (&enabled); 1334 if (!enabled) 1335 continue; 1336 1337 NetworkAttachmentType_T netattach; 1338 adapter->COMGETTER(AttachmentType)(&netattach); 1339 switch (netattach) 1340 { 1341 case NetworkAttachmentType_HostInterface: 1342 { 1343 #ifdef RT_OS_WINDOWS 1344 /* a valid host interface must have been set */ 1345 Bstr hostif; 1346 adapter->COMGETTER(HostInterface)(hostif.asOutParam()); 1347 if (!hostif) 1348 { 1349 return setError (E_FAIL, 1350 tr ("VM cannot start because host interface networking " 1351 "requires a host interface name to be set")); 1352 } 1353 ComPtr<IVirtualBox> virtualBox; 1354 mMachine->COMGETTER(Parent)(virtualBox.asOutParam()); 1355 ComPtr<IHost> host; 1356 virtualBox->COMGETTER(Host)(host.asOutParam()); 1357 ComPtr<IHostNetworkInterfaceCollection> coll; 1358 host->COMGETTER(NetworkInterfaces)(coll.asOutParam()); 1359 ComPtr<IHostNetworkInterface> hostInterface; 1360 if (!SUCCEEDED(coll->FindByName(hostif, hostInterface.asOutParam()))) 1361 { 1362 return setError (E_FAIL, 1363 tr ("VM cannot start because the host interface '%ls' " 1364 "does not exist"), 1365 hostif.raw()); 1366 } 1367 #endif /* RT_OS_WINDOWS */ 1368 break; 1369 } 1370 default: 1371 break; 1372 } 1373 } 1374 1375 /* Read console data stored in the saved state file (if not yet done) */ 1376 { 1377 HRESULT rc = loadDataFromSavedState(); 1378 CheckComRCReturnRC (rc); 1379 } 1380 1381 /* Check all types of shared folders and compose a single list */ 1382 SharedFolderDataMap sharedFolders; 1383 { 1384 /* first, insert global folders */ 1385 for (SharedFolderDataMap::const_iterator it = mGlobalSharedFolders.begin(); 1386 it != mGlobalSharedFolders.end(); ++ it) 1387 sharedFolders [it->first] = it->second; 1388 1389 /* second, insert machine folders */ 1390 for (SharedFolderDataMap::const_iterator it = mMachineSharedFolders.begin(); 1391 it != mMachineSharedFolders.end(); ++ it) 1392 sharedFolders [it->first] = it->second; 1393 1394 /* third, insert console folders */ 1395 for (SharedFolderMap::const_iterator it = mSharedFolders.begin(); 1396 it != mSharedFolders.end(); ++ it) 1397 sharedFolders [it->first] = SharedFolderData(it->second->hostPath(), it->second->writable()); 1398 } 1399 1400 Bstr savedStateFile; 1401 1402 /* 1403 * Saved VMs will have to prove that their saved states are kosher. 1404 */ 1405 if (mMachineState == MachineState_Saved) 1406 { 1407 HRESULT rc = mMachine->COMGETTER(StateFilePath) (savedStateFile.asOutParam()); 1408 CheckComRCReturnRC (rc); 1409 ComAssertRet (!!savedStateFile, E_FAIL); 1410 int vrc = SSMR3ValidateFile (Utf8Str (savedStateFile)); 1411 if (VBOX_FAILURE (vrc)) 1279 tr ("Cannot power down a saved virtual machine")); 1280 else if (mMachineState == MachineState_Stopping) 1412 1281 return setError (E_FAIL, 1413 tr ("VM cannot start because the saved state file '%ls' is invalid (%Vrc). " 1414 "Discard the saved state prior to starting the VM"), 1415 savedStateFile.raw(), vrc); 1416 } 1282 tr ("Virtual machine is being powered down.")); 1283 else 1284 return setError(E_FAIL, 1285 tr ("Invalid machine state: %d (must be Running, Paused " 1286 "or Stuck)"), 1287 mMachineState); 1288 } 1289 1290 LogFlowThisFunc (("Initiating SHUTDOWN request...\n")); 1417 1291 1418 1292 /* create an IProgress object to track progress of this operation */ 1419 1293 ComObjPtr <Progress> progress; 1420 1294 progress.createObject(); 1421 Bstr progressDesc;1422 if (mMachineState == MachineState_Saved)1423 progressDesc = tr ("Restoring the virtual machine");1424 else1425 progressDesc = tr ("Starting the virtual machine");1426 1295 progress->init (static_cast <IConsole *> (this), 1427 progressDesc, FALSE /* aCancelable */); 1428 1429 /* pass reference to caller if requested */ 1430 if (aProgress) 1431 progress.queryInterfaceTo (aProgress); 1296 Bstr (tr ("Stopping virtual machine")), 1297 FALSE /* aCancelable */); 1432 1298 1433 1299 /* setup task object and thread to carry out the operation asynchronously */ 1434 std::auto_ptr <VMPowerUpTask> task (new VMPowerUpTask (this, progress)); 1435 ComAssertComRCRetRC (task->rc()); 1436 1437 task->mSetVMErrorCallback = setVMErrorCallback; 1438 task->mConfigConstructor = configConstructor; 1439 task->mSharedFolders = sharedFolders; 1440 task->mStartPaused = aPaused; 1441 if (mMachineState == MachineState_Saved) 1442 task->mSavedStateFile = savedStateFile; 1443 1444 HRESULT hrc = consoleInitReleaseLog (mMachine); 1445 if (FAILED (hrc)) 1446 return hrc; 1447 1448 int vrc = RTThreadCreate (NULL, Console::powerUpThread, (void *) task.get(), 1449 0, RTTHREADTYPE_MAIN_WORKER, 0, "VMPowerUp"); 1450 1451 ComAssertMsgRCRet (vrc, ("Could not create VMPowerUp thread (%Vrc)\n", vrc), 1452 E_FAIL); 1453 1454 /* task is now owned by powerUpThread(), so release it */ 1300 std::auto_ptr <VMProgressTask> task ( 1301 new VMProgressTask (this, progress, true /* aUsesVMPtr */)); 1302 AssertReturn (task->isOk(), E_FAIL); 1303 1304 int vrc = RTThreadCreate (NULL, Console::powerDownThread, 1305 (void *) task.get(), 0, 1306 RTTHREADTYPE_MAIN_WORKER, 0, 1307 "VMPowerDown"); 1308 ComAssertMsgRCRet (vrc, 1309 ("Could not create VMPowerDown thread (%Vrc)\n", vrc), E_FAIL); 1310 1311 /* task is now owned by powerDownThread(), so release it */ 1455 1312 task.release(); 1456 1313 1457 if (mMachineState == MachineState_Saved)1458 setMachineState (MachineState_Restoring);1459 else 1460 setMachineState (MachineState_Starting);1461 1462 LogFlowThisFunc (("mMachineState=%d\n", mMachineState)); 1314 /* go to Stopping state to forbid state-dependant operations */ 1315 setMachineState (MachineState_Stopping); 1316 1317 /* pass the progress to the caller */ 1318 progress.queryInterfaceTo (aProgress); 1319 1463 1320 LogFlowThisFuncLeave(); 1321 1464 1322 return S_OK; 1465 }1466 1467 STDMETHODIMP Console::PowerDown()1468 {1469 LogFlowThisFuncEnter();1470 LogFlowThisFunc (("mMachineState=%d\n", mMachineState));1471 1472 AutoCaller autoCaller (this);1473 CheckComRCReturnRC (autoCaller.rc());1474 1475 AutoWriteLock alock (this);1476 1477 if (mMachineState != MachineState_Running &&1478 mMachineState != MachineState_Paused &&1479 mMachineState != MachineState_Stuck)1480 {1481 /* extra nice error message for a common case */1482 if (mMachineState == MachineState_Saved)1483 return setError(E_FAIL, tr ("Cannot power off a saved machine"));1484 else1485 return setError(E_FAIL, tr ("Cannot power off the machine as it is "1486 "not running or paused (machine state: %d)"),1487 mMachineState);1488 }1489 1490 LogFlowThisFunc (("Sending SHUTDOWN request...\n"));1491 1492 HRESULT rc = powerDown();1493 1494 LogFlowThisFunc (("mMachineState=%d, rc=%08X\n", mMachineState, rc));1495 LogFlowThisFuncLeave();1496 return rc;1497 1323 } 1498 1324 … … 4391 4217 } 4392 4218 4393 4394 4219 /** 4395 * Internal power off worker routine. 4396 * 4397 * This method may be called only at certain places with the folliwing meaning 4398 * as shown below: 4399 * 4400 * - if the machine state is either Running or Paused, a normal 4401 * Console-initiated powerdown takes place (e.g. PowerDown()); 4402 * - if the machine state is Saving, saveStateThread() has successfully 4403 * done its job; 4404 * - if the machine state is Starting or Restoring, powerUpThread() has 4405 * failed to start/load the VM; 4406 * - if the machine state is Stopping, the VM has powered itself off 4407 * (i.e. not as a result of the powerDown() call). 4408 * 4409 * Calling it in situations other than the above will cause unexpected 4410 * behavior. 4411 * 4412 * Note that this method should be the only one that destroys mpVM and sets 4413 * it to NULL. 4414 * 4415 * @note Locks this object for writing. 4416 * 4417 * @note Never call this method from a thread that called addVMCaller() or 4418 * instantiated an AutoVMCaller object; first call releaseVMCaller() or 4419 * release(). Otherwise it will deadlock. 4220 * Common worker for PowerUp and PowerUpPaused. 4221 * 4222 * @returns COM status code. 4223 * 4224 * @param aProgress Where to return the progress object. 4225 * @param aPaused true if PowerUpPaused called. 4226 * 4227 * @todo move down to powerDown(); 4420 4228 */ 4421 HRESULT Console::powerDown() 4229 HRESULT Console::powerUp (IProgress **aProgress, bool aPaused) 4230 { 4231 if (aProgress == NULL) 4232 return E_POINTER; 4233 4234 LogFlowThisFuncEnter(); 4235 LogFlowThisFunc (("mMachineState=%d\n", mMachineState)); 4236 4237 AutoCaller autoCaller (this); 4238 CheckComRCReturnRC (autoCaller.rc()); 4239 4240 AutoWriteLock alock (this); 4241 4242 if (mMachineState >= MachineState_Running) 4243 return setError(E_FAIL, tr ("Cannot power up the machine as it is " 4244 "already running (machine state: %d)"), 4245 mMachineState); 4246 4247 /* 4248 * First check whether all disks are accessible. This is not a 100% 4249 * bulletproof approach (race condition, it might become inaccessible 4250 * right after the check) but it's convenient as it will cover 99.9% 4251 * of the cases and here, we're able to provide meaningful error 4252 * information. 4253 */ 4254 ComPtr<IHardDiskAttachmentCollection> coll; 4255 mMachine->COMGETTER(HardDiskAttachments)(coll.asOutParam()); 4256 ComPtr<IHardDiskAttachmentEnumerator> enumerator; 4257 coll->Enumerate(enumerator.asOutParam()); 4258 BOOL fHasMore; 4259 while (SUCCEEDED(enumerator->HasMore(&fHasMore)) && fHasMore) 4260 { 4261 ComPtr<IHardDiskAttachment> attach; 4262 enumerator->GetNext(attach.asOutParam()); 4263 ComPtr<IHardDisk> hdd; 4264 attach->COMGETTER(HardDisk)(hdd.asOutParam()); 4265 Assert(hdd); 4266 BOOL fAccessible; 4267 HRESULT rc = hdd->COMGETTER(AllAccessible)(&fAccessible); 4268 CheckComRCReturnRC (rc); 4269 if (!fAccessible) 4270 { 4271 Bstr loc; 4272 hdd->COMGETTER(Location) (loc.asOutParam()); 4273 Bstr errMsg; 4274 hdd->COMGETTER(LastAccessError) (errMsg.asOutParam()); 4275 return setError (E_FAIL, 4276 tr ("VM cannot start because the hard disk '%ls' is not accessible " 4277 "(%ls)"), 4278 loc.raw(), errMsg.raw()); 4279 } 4280 } 4281 4282 /* now perform the same check if a ISO is mounted */ 4283 ComPtr<IDVDDrive> dvdDrive; 4284 mMachine->COMGETTER(DVDDrive)(dvdDrive.asOutParam()); 4285 ComPtr<IDVDImage> dvdImage; 4286 dvdDrive->GetImage(dvdImage.asOutParam()); 4287 if (dvdImage) 4288 { 4289 BOOL fAccessible; 4290 HRESULT rc = dvdImage->COMGETTER(Accessible)(&fAccessible); 4291 CheckComRCReturnRC (rc); 4292 if (!fAccessible) 4293 { 4294 Bstr filePath; 4295 dvdImage->COMGETTER(FilePath)(filePath.asOutParam()); 4296 /// @todo (r=dmik) grab the last access error once 4297 // IDVDImage::lastAccessError is there 4298 return setError (E_FAIL, 4299 tr ("The virtual machine could not be started because the DVD image '%ls' which is attached to it could not be found or could not be opened. Please detach the image and try again"), 4300 filePath.raw()); 4301 } 4302 } 4303 4304 /* now perform the same check if a floppy is mounted */ 4305 ComPtr<IFloppyDrive> floppyDrive; 4306 mMachine->COMGETTER(FloppyDrive)(floppyDrive.asOutParam()); 4307 ComPtr<IFloppyImage> floppyImage; 4308 floppyDrive->GetImage(floppyImage.asOutParam()); 4309 if (floppyImage) 4310 { 4311 BOOL fAccessible; 4312 HRESULT rc = floppyImage->COMGETTER(Accessible)(&fAccessible); 4313 CheckComRCReturnRC (rc); 4314 if (!fAccessible) 4315 { 4316 Bstr filePath; 4317 floppyImage->COMGETTER(FilePath)(filePath.asOutParam()); 4318 /// @todo (r=dmik) grab the last access error once 4319 // IDVDImage::lastAccessError is there 4320 return setError (E_FAIL, 4321 tr ("The virtual machine could not be started because the floppy image '%ls' which is attached to it could not be found or could not be opened. Please detach the image and try again"), 4322 filePath.raw()); 4323 } 4324 } 4325 4326 /* now the network cards will undergo a quick consistency check */ 4327 for (ULONG slot = 0; slot < SchemaDefs::NetworkAdapterCount; slot ++) 4328 { 4329 ComPtr<INetworkAdapter> adapter; 4330 mMachine->GetNetworkAdapter (slot, adapter.asOutParam()); 4331 BOOL enabled = FALSE; 4332 adapter->COMGETTER(Enabled) (&enabled); 4333 if (!enabled) 4334 continue; 4335 4336 NetworkAttachmentType_T netattach; 4337 adapter->COMGETTER(AttachmentType)(&netattach); 4338 switch (netattach) 4339 { 4340 case NetworkAttachmentType_HostInterface: 4341 { 4342 #ifdef RT_OS_WINDOWS 4343 /* a valid host interface must have been set */ 4344 Bstr hostif; 4345 adapter->COMGETTER(HostInterface)(hostif.asOutParam()); 4346 if (!hostif) 4347 { 4348 return setError (E_FAIL, 4349 tr ("VM cannot start because host interface networking " 4350 "requires a host interface name to be set")); 4351 } 4352 ComPtr<IVirtualBox> virtualBox; 4353 mMachine->COMGETTER(Parent)(virtualBox.asOutParam()); 4354 ComPtr<IHost> host; 4355 virtualBox->COMGETTER(Host)(host.asOutParam()); 4356 ComPtr<IHostNetworkInterfaceCollection> coll; 4357 host->COMGETTER(NetworkInterfaces)(coll.asOutParam()); 4358 ComPtr<IHostNetworkInterface> hostInterface; 4359 if (!SUCCEEDED(coll->FindByName(hostif, hostInterface.asOutParam()))) 4360 { 4361 return setError (E_FAIL, 4362 tr ("VM cannot start because the host interface '%ls' " 4363 "does not exist"), 4364 hostif.raw()); 4365 } 4366 #endif /* RT_OS_WINDOWS */ 4367 break; 4368 } 4369 default: 4370 break; 4371 } 4372 } 4373 4374 /* Read console data stored in the saved state file (if not yet done) */ 4375 { 4376 HRESULT rc = loadDataFromSavedState(); 4377 CheckComRCReturnRC (rc); 4378 } 4379 4380 /* Check all types of shared folders and compose a single list */ 4381 SharedFolderDataMap sharedFolders; 4382 { 4383 /* first, insert global folders */ 4384 for (SharedFolderDataMap::const_iterator it = mGlobalSharedFolders.begin(); 4385 it != mGlobalSharedFolders.end(); ++ it) 4386 sharedFolders [it->first] = it->second; 4387 4388 /* second, insert machine folders */ 4389 for (SharedFolderDataMap::const_iterator it = mMachineSharedFolders.begin(); 4390 it != mMachineSharedFolders.end(); ++ it) 4391 sharedFolders [it->first] = it->second; 4392 4393 /* third, insert console folders */ 4394 for (SharedFolderMap::const_iterator it = mSharedFolders.begin(); 4395 it != mSharedFolders.end(); ++ it) 4396 sharedFolders [it->first] = SharedFolderData(it->second->hostPath(), it->second->writable()); 4397 } 4398 4399 Bstr savedStateFile; 4400 4401 /* 4402 * Saved VMs will have to prove that their saved states are kosher. 4403 */ 4404 if (mMachineState == MachineState_Saved) 4405 { 4406 HRESULT rc = mMachine->COMGETTER(StateFilePath) (savedStateFile.asOutParam()); 4407 CheckComRCReturnRC (rc); 4408 ComAssertRet (!!savedStateFile, E_FAIL); 4409 int vrc = SSMR3ValidateFile (Utf8Str (savedStateFile)); 4410 if (VBOX_FAILURE (vrc)) 4411 return setError (E_FAIL, 4412 tr ("VM cannot start because the saved state file '%ls' is invalid (%Vrc). " 4413 "Discard the saved state prior to starting the VM"), 4414 savedStateFile.raw(), vrc); 4415 } 4416 4417 /* create an IProgress object to track progress of this operation */ 4418 ComObjPtr <Progress> progress; 4419 progress.createObject(); 4420 Bstr progressDesc; 4421 if (mMachineState == MachineState_Saved) 4422 progressDesc = tr ("Restoring virtual machine"); 4423 else 4424 progressDesc = tr ("Starting virtual machine"); 4425 progress->init (static_cast <IConsole *> (this), 4426 progressDesc, FALSE /* aCancelable */); 4427 4428 /* pass reference to caller if requested */ 4429 if (aProgress) 4430 progress.queryInterfaceTo (aProgress); 4431 4432 /* setup task object and thread to carry out the operation asynchronously */ 4433 std::auto_ptr <VMPowerUpTask> task (new VMPowerUpTask (this, progress)); 4434 ComAssertComRCRetRC (task->rc()); 4435 4436 task->mSetVMErrorCallback = setVMErrorCallback; 4437 task->mConfigConstructor = configConstructor; 4438 task->mSharedFolders = sharedFolders; 4439 task->mStartPaused = aPaused; 4440 if (mMachineState == MachineState_Saved) 4441 task->mSavedStateFile = savedStateFile; 4442 4443 HRESULT hrc = consoleInitReleaseLog (mMachine); 4444 if (FAILED (hrc)) 4445 return hrc; 4446 4447 int vrc = RTThreadCreate (NULL, Console::powerUpThread, (void *) task.get(), 4448 0, RTTHREADTYPE_MAIN_WORKER, 0, "VMPowerUp"); 4449 4450 ComAssertMsgRCRet (vrc, ("Could not create VMPowerUp thread (%Vrc)\n", vrc), 4451 E_FAIL); 4452 4453 /* task is now owned by powerUpThread(), so release it */ 4454 task.release(); 4455 4456 if (mMachineState == MachineState_Saved) 4457 setMachineState (MachineState_Restoring); 4458 else 4459 setMachineState (MachineState_Starting); 4460 4461 LogFlowThisFunc (("mMachineState=%d\n", mMachineState)); 4462 LogFlowThisFuncLeave(); 4463 return S_OK; 4464 } 4465 4466 /** 4467 * Internal power off worker routine. 4468 * 4469 * This method may be called only at certain places with the folliwing meaning 4470 * as shown below: 4471 * 4472 * - if the machine state is either Running or Paused, a normal 4473 * Console-initiated powerdown takes place (e.g. PowerDown()); 4474 * - if the machine state is Saving, saveStateThread() has successfully done its 4475 * job; 4476 * - if the machine state is Starting or Restoring, powerUpThread() has failed 4477 * to start/load the VM; 4478 * - if the machine state is Stopping, the VM has powered itself off (i.e. not 4479 * as a result of the powerDown() call). 4480 * 4481 * Calling it in situations other than the above will cause unexpected behavior. 4482 * 4483 * Note that this method should be the only one that destroys mpVM and sets it 4484 * to NULL. 4485 * 4486 * @param aProgress Progress object to run (may be NULL). 4487 * 4488 * @note Locks this object for writing. 4489 * 4490 * @note Never call this method from a thread that called addVMCaller() or 4491 * instantiated an AutoVMCaller object; first call releaseVMCaller() or 4492 * release(). Otherwise it will deadlock. 4493 */ 4494 HRESULT Console::powerDown (Progress *aProgress /*= NULL*/) 4422 4495 { 4423 4496 LogFlowThisFuncEnter(); … … 4427 4500 4428 4501 AutoWriteLock alock (this); 4502 4503 /* Total # of steps for the progress object. Must correspond to the 4504 * number of "advance percent count" comments in this method! */ 4505 enum { StepCount = 7 }; 4506 /* current step */ 4507 size_t step = 0; 4508 4509 HRESULT rc = S_OK; 4429 4510 int vrc = VINF_SUCCESS; 4430 4511 4431 4512 /* sanity */ 4432 AssertReturn (mVMDestroying == false, E_FAIL); 4433 4434 LogRel (("Console::powerDown(): a request to power off the VM has been issued " 4435 "(mMachineState=%d, InUninit=%d)\n", 4513 Assert (mVMDestroying == false); 4514 4515 Assert (mpVM != NULL); 4516 4517 AssertMsg (mMachineState == MachineState_Running || 4518 mMachineState == MachineState_Paused || 4519 mMachineState == MachineState_Stuck || 4520 mMachineState == MachineState_Saving || 4521 mMachineState == MachineState_Starting || 4522 mMachineState == MachineState_Restoring || 4523 mMachineState == MachineState_Stopping, 4524 ("Invalid machine state: %d\n", mMachineState)); 4525 4526 LogRel (("Console::powerDown(): A request to power off the VM has been " 4527 "issued (mMachineState=%d, InUninit=%d)\n", 4436 4528 mMachineState, autoCaller.state() == InUninit)); 4437 4529 4438 /* 4439 * Stop the VRDP server to prevent new clients connection while VM is being powered off. 4440 */ 4530 /* Check if we need to power off the VM. In case of mVMPoweredOff=true, the 4531 * VM has already powered itself off in vmstateChangeCallback() and is just 4532 * notifying Console about that. In case of Starting or Restoring, 4533 * powerUpThread() is calling us on failure, so the VM is already off at 4534 * that point. */ 4535 if (!mVMPoweredOff && 4536 (mMachineState == MachineState_Starting || 4537 mMachineState == MachineState_Restoring)) 4538 mVMPoweredOff = true; 4539 4540 /* go to Stopping state if not already there. Note that we don't go from 4541 * Saving to Stopping because vmstateChangeCallback() needs it to set the 4542 * state to Saved on VMSTATE_TERMINATED. In terms of protecting from 4543 * inappropriate operations while leaving the lock below, Saving should be 4544 * fine too */ 4545 if (mMachineState != MachineState_Saving && 4546 mMachineState != MachineState_Stopping) 4547 setMachineState (MachineState_Stopping); 4548 4549 /* ---------------------------------------------------------------------- 4550 * DONE with necessary state changes, perform the power down actions (it's 4551 * safe to leave the object lock now if needed) 4552 * ---------------------------------------------------------------------- */ 4553 4554 /* Stop the VRDP server to prevent new clients connection while VM is being 4555 * powered off. */ 4441 4556 if (mConsoleVRDPServer) 4442 4557 { 4443 4558 LogFlowThisFunc (("Stopping VRDP server...\n")); 4444 4559 4445 /* Leave the lock since EMT will call us back as addVMCaller in updateDisplayData(). */ 4560 /* Leave the lock since EMT will call us back as addVMCaller() 4561 * in updateDisplayData(). */ 4446 4562 alock.leave(); 4447 4563 … … 4451 4567 } 4452 4568 4569 /* advance percent count */ 4570 if (aProgress) 4571 aProgress->notifyProgress (99 * (++ step) / StepCount ); 4453 4572 4454 4573 #ifdef VBOX_WITH_HGCM 4455 /* 4456 * Shutdown HGCM services before stopping the guest, because they might need a cleanup.4457 * /4574 4575 /* Shutdown HGCM services before stopping the guest, because they might 4576 * need a cleanup. */ 4458 4577 if (mVMMDev) 4459 4578 { 4460 4579 LogFlowThisFunc (("Shutdown HGCM...\n")); 4461 4580 4462 /* Leave the lock .*/4581 /* Leave the lock since EMT will call us back as addVMCaller() */ 4463 4582 alock.leave(); 4464 4583 … … 4467 4586 alock.enter(); 4468 4587 } 4588 4589 /* advance percent count */ 4590 if (aProgress) 4591 aProgress->notifyProgress (99 * (++ step) / StepCount ); 4592 4469 4593 # ifdef VBOX_WITH_GUEST_PROPS 4594 4470 4595 /* Save all guest property store entries to the machine XML file */ 4471 4596 PCFGMNODE pValues = CFGMR3GetChild (CFGMR3GetRoot (mpVM), "GuestProps/Values/"); 4472 4597 PCFGMNODE pTimestamps = CFGMR3GetChild (CFGMR3GetRoot (mpVM), "GuestProps/Timestamps/"); 4473 4598 PCFGMNODE pFlags = CFGMR3GetChild (CFGMR3GetRoot (mpVM), "GuestProps/Flags/"); 4599 4474 4600 /* Count the number of entries we have */ 4475 4601 unsigned cValues = 0; … … 4490 4616 } 4491 4617 } 4618 4492 4619 /* And pack them into safe arrays */ 4493 4620 com::SafeArray <BSTR> names(cValues); … … 4496 4623 com::SafeArray <BSTR> flags(cValues); 4497 4624 pValue = CFGMR3GetFirstValue (pValues); 4625 4498 4626 vrc = VINF_SUCCESS; 4499 4627 unsigned iProp = 0; 4500 while (pValue != NULL && RT_SUCCESS (vrc))4628 while (pValue != NULL && RT_SUCCESS (vrc)) 4501 4629 { 4502 4630 using namespace guestProp; 4503 4631 4504 char szPropName [MAX_NAME_LEN + 1];4505 char szPropValue [MAX_VALUE_LEN + 1];4506 char szPropFlags [MAX_FLAGS_LEN + 1];4632 char szPropName [MAX_NAME_LEN + 1]; 4633 char szPropValue [MAX_VALUE_LEN + 1]; 4634 char szPropFlags [MAX_FLAGS_LEN + 1]; 4507 4635 ULONG64 u64Timestamp = 0; /* default */ 4508 vrc = CFGMR3GetValueName (pValue, szPropName, sizeof (szPropName));4636 vrc = CFGMR3GetValueName (pValue, szPropName, sizeof (szPropName)); 4509 4637 if (RT_SUCCESS(vrc)) 4510 vrc = CFGMR3QueryString (pValues, szPropName, szPropValue, sizeof(szPropValue)); 4638 vrc = CFGMR3QueryString (pValues, szPropName, szPropValue, 4639 sizeof (szPropValue)); 4511 4640 if (RT_SUCCESS(vrc)) 4512 4641 { … … 4530 4659 } 4531 4660 } 4661 4532 4662 if (RT_SUCCESS(vrc) || (VERR_TOO_MUCH_DATA == vrc)) 4533 4663 { 4534 4664 /* PushGuestProperties() calls DiscardSettings(), which calls us back */ 4535 4665 alock.leave(); 4536 mControl->PushGuestProperties (ComSafeArrayAsInParam (names),4537 ComSafeArrayAsInParam (values),4538 ComSafeArrayAsInParam (timestamps),4539 ComSafeArrayAsInParam (flags));4666 mControl->PushGuestProperties (ComSafeArrayAsInParam (names), 4667 ComSafeArrayAsInParam (values), 4668 ComSafeArrayAsInParam (timestamps), 4669 ComSafeArrayAsInParam (flags)); 4540 4670 alock.enter(); 4541 4671 } 4672 4673 /* advance percent count */ 4674 if (aProgress) 4675 aProgress->notifyProgress (99 * (++ step) / StepCount ); 4676 4542 4677 # endif /* VBOX_WITH_GUEST_PROPS defined */ 4678 4543 4679 #endif /* VBOX_WITH_HGCM */ 4544 4680 4545 /* First, wait for all mpVM callers to finish their work if necessary */ 4681 /* ---------------------------------------------------------------------- 4682 * Now, wait for all mpVM callers to finish their work if there are still 4683 * some on other threads. NO methods that need mpVM (or initiate other calls 4684 * that need it) may be called after this point 4685 * ---------------------------------------------------------------------- */ 4686 4546 4687 if (mVMCallers > 0) 4547 4688 { … … 4563 4704 } 4564 4705 4565 AssertReturn (mpVM, E_FAIL); 4566 4567 AssertMsg (mMachineState == MachineState_Running || 4568 mMachineState == MachineState_Paused || 4569 mMachineState == MachineState_Stuck || 4570 mMachineState == MachineState_Saving || 4571 mMachineState == MachineState_Starting || 4572 mMachineState == MachineState_Restoring || 4573 mMachineState == MachineState_Stopping, 4574 ("Invalid machine state: %d\n", mMachineState)); 4575 4576 HRESULT rc = S_OK; 4706 /* advance percent count */ 4707 if (aProgress) 4708 aProgress->notifyProgress (99 * (++ step) / StepCount ); 4709 4577 4710 vrc = VINF_SUCCESS; 4578 4711 4579 /* 4580 * Power off the VM if not already done that. In case of Stopping, the VM 4581 * has powered itself off and notified Console in vmstateChangeCallback(). 4582 * In case of Starting or Restoring, powerUpThread() is calling us on 4583 * failure, so the VM is already off at that point. 4584 */ 4585 if (mMachineState != MachineState_Stopping && 4586 mMachineState != MachineState_Starting && 4587 mMachineState != MachineState_Restoring) 4588 { 4589 /* 4590 * don't go from Saving to Stopping, vmstateChangeCallback needs it 4591 * to set the state to Saved on VMSTATE_TERMINATED. 4592 */ 4593 if (mMachineState != MachineState_Saving) 4594 setMachineState (MachineState_Stopping); 4595 4712 /* Power off the VM if not already done that */ 4713 if (!mVMPoweredOff) 4714 { 4596 4715 LogFlowThisFunc (("Powering off the VM...\n")); 4597 4716 … … 4600 4719 4601 4720 vrc = VMR3PowerOff (mpVM); 4602 /* 4603 * Note that VMR3PowerOff() may fail here (invalid VMSTATE) if the 4604 * VM-(guest-)initiated power off happened in parallel a ms before 4605 * this call. So far, we let this error pop up on the user's side. 4606 */ 4721 4722 /* Note that VMR3PowerOff() may fail here (invalid VMSTATE) if the 4723 * VM-(guest-)initiated power off happened in parallel a ms before this 4724 * call. So far, we let this error pop up on the user's side. */ 4607 4725 4608 4726 alock.enter(); 4609 } 4610 4611 LogFlowThisFunc (("Ready for VM destruction\n")); 4612 4613 /* 4614 * If we are called from Console::uninit(), then try to destroy the VM 4615 * even on failure (this will most likely fail too, but what to do?..) 4616 */ 4727 4728 } 4729 else 4730 { 4731 /* reset the flag for further re-use */ 4732 mVMPoweredOff = false; 4733 } 4734 4735 /* advance percent count */ 4736 if (aProgress) 4737 aProgress->notifyProgress (99 * (++ step) / StepCount ); 4738 4739 LogFlowThisFunc (("Ready for VM destruction.\n")); 4740 4741 /* If we are called from Console::uninit(), then try to destroy the VM even 4742 * on failure (this will most likely fail too, but what to do?..) */ 4617 4743 if (VBOX_SUCCESS (vrc) || autoCaller.state() == InUninit) 4618 4744 { … … 4630 4756 } 4631 4757 4632 /* 4633 * Now we've got to destroy the VM as well. (mpVM is not valid 4634 * beyond this point). We leave the lock before calling VMR3Destroy() 4635 * because it will result into calling destructors of drivers 4636 * associated with Console children which may in turn try to lock 4637 * Console (e.g. by instantiating SafeVMPtr to access mpVM). It's safe 4638 * here because mVMDestroying is set which should prevent any activity. 4639 */ 4640 4641 /* 4642 * Set mpVM to NULL early just in case if some old code is not using 4643 * addVMCaller()/releaseVMCaller(). 4644 */ 4758 /* Now we've got to destroy the VM as well. (mpVM is not valid beyond 4759 * this point). We leave the lock before calling VMR3Destroy() because 4760 * it will result into calling destructors of drivers associated with 4761 * Console children which may in turn try to lock Console (e.g. by 4762 * instantiating SafeVMPtr to access mpVM). It's safe here because 4763 * mVMDestroying is set which should prevent any activity. */ 4764 4765 /* Set mpVM to NULL early just in case if some old code is not using 4766 * addVMCaller()/releaseVMCaller(). */ 4645 4767 PVM pVM = mpVM; 4646 4768 mpVM = NULL; … … 4655 4777 alock.enter(); 4656 4778 4779 /* advance percent count */ 4780 if (aProgress) 4781 aProgress->notifyProgress (99 * (++ step) / StepCount ); 4782 4657 4783 if (VBOX_SUCCESS (vrc)) 4658 4784 { 4659 4785 LogFlowThisFunc (("Machine has been destroyed (mMachineState=%d)\n", 4660 4786 mMachineState)); 4661 /* 4662 * Note: the Console-level machine state change happens on the 4663 * VMSTATE_TERMINATE state change in vmstateChangeCallback(). If 4664 * powerDown() is called from EMT (i.e. from vmstateChangeCallback() 4665 * on receiving VM-initiated VMSTATE_OFF), VMSTATE_TERMINATE hasn't 4666 * occured yet. This is okay, because mMachineState is already 4667 * Stopping in this case, so any other attempt to call PowerDown() 4668 * will be rejected. 4669 */ 4787 /* Note: the Console-level machine state change happens on the 4788 * VMSTATE_TERMINATE state change in vmstateChangeCallback(). If 4789 * powerDown() is called from EMT (i.e. from vmstateChangeCallback() 4790 * on receiving VM-initiated VMSTATE_OFF), VMSTATE_TERMINATE hasn't 4791 * occured yet. This is okay, because mMachineState is already 4792 * Stopping in this case, so any other attempt to call PowerDown() 4793 * will be rejected. */ 4670 4794 } 4671 4795 else … … 4677 4801 } 4678 4802 4679 /* 4680 * Complete the detaching of the USB devices. 4681 */ 4803 /* Complete the detaching of the USB devices. */ 4682 4804 if (fHasUSBController) 4683 4805 detachAllUSBDevices (true /* aDone */); 4806 4807 /* advance percent count */ 4808 if (aProgress) 4809 aProgress->notifyProgress (99 * (++ step) / StepCount ); 4684 4810 } 4685 4811 else … … 4689 4815 } 4690 4816 4691 /* 4692 * Finished with destruction. Note that if something impossible happened 4693 * and we've failed to destroy the VM, mVMDestroying will remain false and 4694 * mMachineState will be something like Stopping, so most Console methods 4695 * will return an error to the caller. 4696 */ 4817 /* Finished with destruction. Note that if something impossible happened and 4818 * we've failed to destroy the VM, mVMDestroying will remain true and 4819 * mMachineState will be something like Stopping, so most Console methods 4820 * will return an error to the caller. */ 4697 4821 if (mpVM == NULL) 4698 4822 mVMDestroying = false; … … 4708 4832 memset (&mCallbackData, 0, sizeof (mCallbackData)); 4709 4833 } 4834 4835 /* complete the progress */ 4836 if (aProgress) 4837 aProgress->notifyComplete (rc); 4710 4838 4711 4839 LogFlowThisFuncLeave(); … … 5097 5225 5098 5226 AutoCaller autoCaller (that); 5099 /* 5100 * Note that we must let this method proceed even if Console::uninit() has 5101 * been already called. In such case this VMSTATE change is a result of: 5102 * 1) powerDown() called from uninit() itself, or 5103 * 2) VM-(guest-)initiated power off. 5104 */ 5227 5228 /* Note that we must let this method proceed even if Console::uninit() has 5229 * been already called. In such case this VMSTATE change is a result of: 5230 * 1) powerDown() called from uninit() itself, or 5231 * 2) VM-(guest-)initiated power off. */ 5105 5232 AssertReturnVoid (autoCaller.isOk() || 5106 5233 autoCaller.state() == InUninit); … … 5109 5236 { 5110 5237 /* 5111 * 5238 * The VM has terminated 5112 5239 */ 5113 5240 case VMSTATE_OFF: … … 5118 5245 break; 5119 5246 5120 /* 5121 * Do we still think that it is running? It may happen if this is 5122 * a VM-(guest-)initiated shutdown/poweroff. 5247 /* Do we still think that it is running? It may happen if this is a 5248 * VM-(guest-)initiated shutdown/poweroff. 5123 5249 */ 5124 5250 if (that->mMachineState != MachineState_Stopping && … … 5130 5256 5131 5257 /* prevent powerDown() from calling VMR3PowerOff() again */ 5258 Assert (that->mVMPoweredOff == false); 5259 that->mVMPoweredOff = true; 5260 5261 /* we are stopping now */ 5132 5262 that->setMachineState (MachineState_Stopping); 5133 5263 5134 /* 5135 * Setup task object and thread to carry out the operation 5136 * asynchronously (if we call powerDown() right here but there 5137 * is one or more mpVM callers (added with addVMCaller()) we'll 5138 * deadlock. 5264 /* Setup task object and thread to carry out the operation 5265 * asynchronously (if we call powerDown() right here but there 5266 * is one or more mpVM callers (added with addVMCaller()) we'll 5267 * deadlock). 5139 5268 */ 5140 std::auto_ptr <VMTask> task (new VMTask (that, true /* aUsesVMPtr */)); 5141 /* 5142 * If creating a task is falied, this can currently mean one 5143 * of two: either Console::uninit() has been called just a ms 5144 * before (so a powerDown() call is already on the way), or 5145 * powerDown() itself is being already executed. Just do 5146 * nothing . 5269 std::auto_ptr <VMProgressTask> task ( 5270 new VMProgressTask (that, NULL /* aProgress */, 5271 true /* aUsesVMPtr */)); 5272 5273 /* If creating a task is falied, this can currently mean one of 5274 * two: either Console::uninit() has been called just a ms 5275 * before (so a powerDown() call is already on the way), or 5276 * powerDown() itself is being already executed. Just do 5277 * nothing. 5147 5278 */ 5148 5279 if (!task->isOk()) … … 5155 5286 (void *) task.get(), 0, 5156 5287 RTTHREADTYPE_MAIN_WORKER, 0, 5157 "VMPowerDowm"); 5158 5159 AssertMsgRC (vrc, ("Could not create VMPowerUp thread (%Vrc)\n", vrc)); 5160 if (VBOX_FAILURE (vrc)) 5161 break; 5288 "VMPowerDown"); 5289 5290 AssertMsgRCBreak (vrc, 5291 ("Could not create VMPowerDown thread (%Vrc)\n", vrc)); 5162 5292 5163 5293 /* task is now owned by powerDownThread(), so release it */ … … 5167 5297 } 5168 5298 5169 /* 5170 * The VM has been completely destroyed. 5299 /* The VM has been completely destroyed. 5171 5300 * 5172 * 5173 * 5174 * 5175 * 5301 * Note: This state change can happen at two points: 5302 * 1) At the end of VMR3Destroy() if it was not called from EMT. 5303 * 2) At the end of vmR3EmulationThread if VMR3Destroy() was 5304 * called by EMT. 5176 5305 */ 5177 5306 case VMSTATE_TERMINATED: … … 5182 5311 break; 5183 5312 5184 /* 5185 * Terminate host interface networking. If aVM is NULL, we've been 5186 * manually called from powerUpThread() either before calling 5187 * VMR3Create() or after VMR3Create() failed, so no need to touch 5188 * networking. 5313 /* Terminate host interface networking. If aVM is NULL, we've been 5314 * manually called from powerUpThread() either before calling 5315 * VMR3Create() or after VMR3Create() failed, so no need to touch 5316 * networking. 5189 5317 */ 5190 5318 if (aVM) 5191 5319 that->powerDownHostInterfaces(); 5192 5320 5193 /* 5194 * From now on the machine is officially powered down or 5195 * remains in the Saved state. 5321 /* From now on the machine is officially powered down or remains in 5322 * the Saved state. 5196 5323 */ 5197 5324 switch (that->mMachineState) … … 5205 5332 break; 5206 5333 case MachineState_Saving: 5207 /* 5208 * successfully saved (note that the machine is already 5209 * in the Saved state on the server due to EndSavingState() 5210 * called from saveStateThread(), so only change the local 5211 * state) 5212 */ 5334 /* successfully saved (note that the machine is already in 5335 * the Saved state on the server due to EndSavingState() 5336 * called from saveStateThread(), so only change the local 5337 * state) */ 5213 5338 that->setMachineStateLocally (MachineState_Saved); 5214 5339 break; 5215 5340 case MachineState_Starting: 5216 /* 5217 * failed to start, but be patient: set back to PoweredOff 5218 * (for similarity with the below) 5219 */ 5341 /* failed to start, but be patient: set back to PoweredOff 5342 * (for similarity with the below) */ 5220 5343 that->setMachineState (MachineState_PoweredOff); 5221 5344 break; 5222 5345 case MachineState_Restoring: 5223 /* 5224 * failed to load the saved state file, but be patient: 5225 * set back to Saved (to preserve the saved state file) 5226 */ 5346 /* failed to load the saved state file, but be patient: set 5347 * back to Saved (to preserve the saved state file) */ 5227 5348 that->setMachineState (MachineState_Saved); 5228 5349 break; … … 5259 5380 break; 5260 5381 5261 /* 5262 * Change the machine state from Starting, Restoring or Paused 5263 * to Running 5264 */ 5382 /* Change the machine state from Starting, Restoring or Paused 5383 * to Running */ 5265 5384 Assert ( ( ( that->mMachineState == MachineState_Starting 5266 5385 || that->mMachineState == MachineState_Paused) … … 6292 6411 } 6293 6412 6294 6295 6296 6413 /** 6297 6414 * Thread function which starts the VM (also from saved state) and … … 7014 7131 LogFlowFuncEnter(); 7015 7132 7016 std::auto_ptr <VM Task> task (static_cast <VMTask *> (pvUser));7133 std::auto_ptr <VMProgressTask> task (static_cast <VMProgressTask *> (pvUser)); 7017 7134 AssertReturn (task.get(), VERR_INVALID_PARAMETER); 7018 7135 … … 7021 7138 const ComObjPtr <Console> &that = task->mConsole; 7022 7139 7023 /* 7024 * Note: no need to use addCaller() to protect Console 7025 * because VMTask does that 7026 */ 7027 7028 /* release VM caller to let powerDown() proceed */ 7140 /* Note: no need to use addCaller() to protect Console because VMTask does 7141 * that */ 7142 7143 /* wait until the method tat started us returns */ 7144 AutoWriteLock thatLock (that); 7145 7146 /* release VM caller to avoid the powerDown() deadlock */ 7029 7147 task->releaseVMCaller(); 7030 7148 7031 HRESULT rc = that->powerDown(); 7032 AssertComRC (rc); 7149 that->powerDown (task->mProgress); 7033 7150 7034 7151 LogFlowFuncLeave(); -
trunk/src/VBox/Main/idl/VirtualBox.xidl
r13227 r13374 4287 4287 <interface 4288 4288 name="IConsole" extends="$unknown" 4289 uuid=" 3acbd337-925f-497d-a624-465c8a99ae5a"4289 uuid="e3c6d4a1-a935-47ca-b16d-f9e9c496e53e" 4290 4290 wsmap="managed" 4291 4291 > … … 4424 4424 4425 4425 <note> 4426 4427 4428 4429 4430 4431 4432 4433 <link to="IVirtualBox::openRemoteSession"/>; these front-ends4434 willpower up the machine automatically for you.4426 Unless you are trying to write a new VirtualBox front-end that 4427 performs direct machine execution (like the VirtualBox or VBoxSDL 4428 front-ends), don't call <link to="IConsole::powerUp"/> in a direct 4429 session opened by <link to="IVirtualBox::openSession"/> and use this 4430 session only to change virtual machine settings. If you simply want to 4431 start virtual machine execution using one of the existing front-ends 4432 (for example the VirtualBox GUI or headless server), simply use 4433 <link to="IVirtualBox::openRemoteSession"/>; these front-ends will 4434 power up the machine automatically for you. 4435 4435 </note> 4436 4436 … … 4444 4444 <method name="powerUpPaused"> 4445 4445 <desc> 4446 Identical to powerUp savethat the VM will enter the4447 4448 4446 Identical to powerUp except that the VM will enter the 4447 <link to="MachineState::Paused"/> state, instead of 4448 <link to="MachineState::Running"/>. 4449 4449 4450 4450 <see>#powerUp</see> … … 4460 4460 After this operation completes, the machine will go to the 4461 4461 PoweredOff state. 4462 </desc> 4462 4463 @deprecated This method will be removed in VirtualBox 2.1 where the 4464 powerDownAsync() method will take its name. Do not use this method in 4465 the code. 4466 </desc> 4467 </method> 4468 4469 <method name="powerDownAsync"> 4470 <desc> 4471 Initiates the power down procedure to stop the virtual machine 4472 execution. 4473 4474 The completion of the power down procedure is tracked using the returned 4475 IProgress object. After the operation is complete, the machine will go 4476 to the PoweredOff state. 4477 4478 @warning This method will be renamed to "powerDown" in VirtualBox 2.1 4479 where the original powerDown() method will be removed. You will need to 4480 rename "powerDownAsync" to "powerDown" in your sources to make them 4481 build with version 2.1. 4482 </desc> 4483 <param name="progress" type="IProgress" dir="return"> 4484 <desc>Progress object to track the operation completion.</desc> 4485 </param> 4463 4486 </method> 4464 4487 -
trunk/src/VBox/Main/include/ConsoleImpl.h
r13165 r13374 130 130 STDMETHOD(PowerUpPaused) (IProgress **aProgress); 131 131 STDMETHOD(PowerDown)(); 132 STDMETHOD(PowerDownAsync) (IProgress **aProgress); 132 133 STDMETHOD(Reset)(); 133 134 STDMETHOD(Pause)(); … … 403 404 HRESULT consoleInitReleaseLog (const ComPtr <IMachine> aMachine); 404 405 405 HRESULT powerUp Common(IProgress **aProgress, bool aPaused);406 HRESULT powerDown ();406 HRESULT powerUp (IProgress **aProgress, bool aPaused); 407 HRESULT powerDown (Progress *aProgress = NULL); 407 408 408 409 HRESULT callTapSetupApplication(bool isStatic, RTFILE tapFD, Bstr &tapDevice, … … 525 526 /** true when Console has entered the mpVM destruction phase */ 526 527 bool mVMDestroying : 1; 528 /** true when power down is initiated by vmstateChangeCallback (EMT) */ 529 bool mVMPoweredOff : 1; 527 530 528 531 /** The current DVD drive state in the VM.
Note:
See TracChangeset
for help on using the changeset viewer.