VirtualBox

Changeset 13374 in vbox for trunk/src


Ignore:
Timestamp:
Oct 17, 2008 1:01:44 PM (16 years ago)
Author:
vboxsync
Message:

Main, FE/Qt: Added IProgress::PowerDownAsync() (#3242).

Location:
trunk/src/VBox
Files:
9 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Frontends/VirtualBox/include/VBoxProblemReporter.h

    r11228 r13374  
    170170    void cannotTakeSnapshot (const CProgress &progress);
    171171    void cannotStopMachine (const CConsole &console);
     172    void cannotStopMachine (const CProgress &progress);
    172173    void cannotDeleteMachine (const CVirtualBox &vbox, const CMachine &machine);
    173174    void cannotDiscardSavedState (const CConsole &console);
  • trunk/src/VBox/Frontends/VirtualBox/src/VBoxConsoleWnd.cpp

    r12424 r13374  
    13021302                if (dlg.rbPowerOff->isChecked())
    13031303                {
    1304                     cconsole.PowerDown();
    1305                     if (!cconsole.isOk())
     1304                    CProgress progress = cconsole.PowerDownAsync();
     1305
     1306                    if (cconsole.isOk())
    13061307                    {
    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;
    13101316                    }
    13111317                    else
     1318                        vboxProblem().cannotStopMachine (cconsole);
     1319
     1320                    if (success)
    13121321                    {
    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 */
    13191325
    13201326                        /* discard the current state if requested */
  • trunk/src/VBox/Frontends/VirtualBox/src/VBoxProblemReporter.cpp

    r11228 r13374  
    811811}
    812812
     813void 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
    813825void VBoxProblemReporter::cannotDeleteMachine (const CVirtualBox &vbox,
    814826                                               const CMachine &machine)
  • trunk/src/VBox/Frontends/VirtualBox4/include/VBoxProblemReporter.h

    r12010 r13374  
    227227    void cannotTakeSnapshot (const CProgress &progress);
    228228    void cannotStopMachine (const CConsole &console);
     229    void cannotStopMachine (const CProgress &progress);
    229230    void cannotDeleteMachine (const CVirtualBox &vbox, const CMachine &machine);
    230231    void cannotDiscardSavedState (const CConsole &console);
  • trunk/src/VBox/Frontends/VirtualBox4/src/VBoxConsoleWnd.cpp

    r13278 r13374  
    13371337                if (dlg.mRbPowerOff->isChecked())
    13381338                {
    1339                     cconsole.PowerDown();
    1340                     if (!cconsole.isOk())
     1339                    CProgress progress = cconsole.PowerDownAsync();
     1340
     1341                    if (cconsole.isOk())
    13411342                    {
    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;
    13451351                    }
    13461352                    else
     1353                        vboxProblem().cannotStopMachine (cconsole);
     1354
     1355                    if (success)
    13471356                    {
    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 */
    13541360
    13551361                        /* discard the current state if requested */
  • trunk/src/VBox/Frontends/VirtualBox4/src/VBoxProblemReporter.cpp

    r12777 r13374  
    887887}
    888888
     889void 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
    889901void VBoxProblemReporter::cannotDeleteMachine (const CVirtualBox &vbox,
    890902                                               const CMachine &machine)
  • trunk/src/VBox/Main/ConsoleImpl.cpp

    r13333 r13374  
    9898
    9999/**
    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.
    118117 */
    119118struct VMTask
     
    208207};
    209208
    210 
    211209// constructor / desctructor
    212210/////////////////////////////////////////////////////////////////////////////
     
    219217    , mVMZeroCallersSem (NIL_RTSEMEVENT)
    220218    , mVMDestroying (false)
     219    , mVMPoweredOff (false)
    221220    , meDVDState (DriveState_NotMounted)
    222221    , meFloppyState (DriveState_NotMounted)
     
    12131212STDMETHODIMP Console::PowerUp (IProgress **aProgress)
    12141213{
    1215     return powerUpCommon (aProgress, false /* aPaused */);
     1214    return powerUp (aProgress, false /* aPaused */);
    12161215}
    12171216
    12181217STDMETHODIMP Console::PowerUpPaused (IProgress **aProgress)
    12191218{
    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
     1222STDMETHODIMP Console::PowerDown()
    12341223{
    12351224    LogFlowThisFuncEnter();
     
    12411230    AutoWriteLock alock (this);
    12421231
    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)
    12761238            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)
    12991241            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
     1259STDMETHODIMP 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)
    13211278            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)
    14121281            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"));
    14171291
    14181292    /* create an IProgress object to track progress of this operation */
    14191293    ComObjPtr <Progress> progress;
    14201294    progress.createObject();
    1421     Bstr progressDesc;
    1422     if (mMachineState == MachineState_Saved)
    1423         progressDesc = tr ("Restoring the virtual machine");
    1424     else
    1425         progressDesc = tr ("Starting the virtual machine");
    14261295    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 */);
    14321298
    14331299    /* 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 */
    14551312    task.release();
    14561313
    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
    14631320    LogFlowThisFuncLeave();
     1321
    14641322    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         else
    1485             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;
    14971323}
    14981324
     
    43914217}
    43924218
    4393 
    43944219/**
    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();
    44204228 */
    4421 HRESULT Console::powerDown()
     4229HRESULT 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 */
     4494HRESULT Console::powerDown (Progress *aProgress /*= NULL*/)
    44224495{
    44234496    LogFlowThisFuncEnter();
     
    44274500
    44284501    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;
    44294510    int vrc = VINF_SUCCESS;
    44304511
    44314512    /* 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",
    44364528             mMachineState, autoCaller.state() == InUninit));
    44374529
    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. */
    44414556    if (mConsoleVRDPServer)
    44424557    {
    44434558        LogFlowThisFunc (("Stopping VRDP server...\n"));
    44444559
    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(). */
    44464562        alock.leave();
    44474563
     
    44514567    }
    44524568
     4569    /* advance percent count */
     4570    if (aProgress)
     4571        aProgress->notifyProgress (99 * (++ step) / StepCount );
    44534572
    44544573#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. */
    44584577    if (mVMMDev)
    44594578    {
    44604579        LogFlowThisFunc (("Shutdown HGCM...\n"));
    44614580
    4462         /* Leave the lock. */
     4581        /* Leave the lock since EMT will call us back as addVMCaller() */
    44634582        alock.leave();
    44644583
     
    44674586        alock.enter();
    44684587    }
     4588
     4589    /* advance percent count */
     4590    if (aProgress)
     4591        aProgress->notifyProgress (99 * (++ step) / StepCount );
     4592
    44694593# ifdef VBOX_WITH_GUEST_PROPS
     4594
    44704595    /* Save all guest property store entries to the machine XML file */
    44714596    PCFGMNODE pValues = CFGMR3GetChild (CFGMR3GetRoot (mpVM), "GuestProps/Values/");
    44724597    PCFGMNODE pTimestamps = CFGMR3GetChild (CFGMR3GetRoot (mpVM), "GuestProps/Timestamps/");
    44734598    PCFGMNODE pFlags = CFGMR3GetChild (CFGMR3GetRoot (mpVM), "GuestProps/Flags/");
     4599
    44744600    /* Count the number of entries we have */
    44754601    unsigned cValues = 0;
     
    44904616        }
    44914617    }
     4618
    44924619    /* And pack them into safe arrays */
    44934620    com::SafeArray <BSTR> names(cValues);
     
    44964623    com::SafeArray <BSTR> flags(cValues);
    44974624    pValue = CFGMR3GetFirstValue (pValues);
     4625
    44984626    vrc = VINF_SUCCESS;
    44994627    unsigned iProp = 0;
    4500     while (pValue != NULL && RT_SUCCESS(vrc))
     4628    while (pValue != NULL && RT_SUCCESS (vrc))
    45014629    {
    45024630        using namespace guestProp;
    45034631
    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];
    45074635        ULONG64 u64Timestamp = 0;  /* default */
    4508         vrc = CFGMR3GetValueName (pValue, szPropName, sizeof(szPropName));
     4636        vrc = CFGMR3GetValueName (pValue, szPropName, sizeof (szPropName));
    45094637        if (RT_SUCCESS(vrc))
    4510             vrc = CFGMR3QueryString (pValues, szPropName, szPropValue, sizeof(szPropValue));
     4638            vrc = CFGMR3QueryString (pValues, szPropName, szPropValue,
     4639                                     sizeof (szPropValue));
    45114640        if (RT_SUCCESS(vrc))
    45124641        {
     
    45304659        }
    45314660    }
     4661
    45324662    if (RT_SUCCESS(vrc) || (VERR_TOO_MUCH_DATA == vrc))
    45334663    {
    45344664        /* PushGuestProperties() calls DiscardSettings(), which calls us back */
    45354665        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));
    45404670        alock.enter();
    45414671    }
     4672
     4673    /* advance percent count */
     4674    if (aProgress)
     4675        aProgress->notifyProgress (99 * (++ step) / StepCount );
     4676
    45424677# endif /* VBOX_WITH_GUEST_PROPS defined */
     4678
    45434679#endif /* VBOX_WITH_HGCM */
    45444680
    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
    45464687    if (mVMCallers > 0)
    45474688    {
     
    45634704    }
    45644705
    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
    45774710    vrc = VINF_SUCCESS;
    45784711
    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    {
    45964715        LogFlowThisFunc (("Powering off the VM...\n"));
    45974716
     
    46004719
    46014720        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. */
    46074725
    46084726        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?..) */
    46174743    if (VBOX_SUCCESS (vrc) || autoCaller.state() == InUninit)
    46184744    {
     
    46304756        }
    46314757
    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(). */
    46454767        PVM pVM = mpVM;
    46464768        mpVM = NULL;
     
    46554777        alock.enter();
    46564778
     4779        /* advance percent count */
     4780        if (aProgress)
     4781            aProgress->notifyProgress (99 * (++ step) / StepCount );
     4782
    46574783        if (VBOX_SUCCESS (vrc))
    46584784        {
    46594785            LogFlowThisFunc (("Machine has been destroyed (mMachineState=%d)\n",
    46604786                              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. */
    46704794        }
    46714795        else
     
    46774801        }
    46784802
    4679         /*
    4680          *  Complete the detaching of the USB devices.
    4681          */
     4803        /* Complete the detaching of the USB devices. */
    46824804        if (fHasUSBController)
    46834805            detachAllUSBDevices (true /* aDone */);
     4806
     4807        /* advance percent count */
     4808        if (aProgress)
     4809            aProgress->notifyProgress (99 * (++ step) / StepCount );
    46844810    }
    46854811    else
     
    46894815    }
    46904816
    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. */
    46974821    if (mpVM == NULL)
    46984822        mVMDestroying = false;
     
    47084832        memset (&mCallbackData, 0, sizeof (mCallbackData));
    47094833    }
     4834
     4835    /* complete the progress */
     4836    if (aProgress)
     4837        aProgress->notifyComplete (rc);
    47104838
    47114839    LogFlowThisFuncLeave();
     
    50975225
    50985226    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. */
    51055232    AssertReturnVoid (autoCaller.isOk() ||
    51065233                      autoCaller.state() == InUninit);
     
    51095236    {
    51105237        /*
    5111          *  The VM has terminated
     5238         * The VM has terminated
    51125239         */
    51135240        case VMSTATE_OFF:
     
    51185245                break;
    51195246
    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.
    51235249             */
    51245250            if (that->mMachineState != MachineState_Stopping &&
     
    51305256
    51315257                /* prevent powerDown() from calling VMR3PowerOff() again */
     5258                Assert (that->mVMPoweredOff == false);
     5259                that->mVMPoweredOff = true;
     5260
     5261                /* we are stopping now */
    51325262                that->setMachineState (MachineState_Stopping);
    51335263
    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).
    51395268                 */
    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.
    51475278                  */
    51485279                if (!task->isOk())
     
    51555286                                          (void *) task.get(), 0,
    51565287                                          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));
    51625292
    51635293                /* task is now owned by powerDownThread(), so release it */
     
    51675297        }
    51685298
    5169         /*
    5170          *  The VM has been completely destroyed.
     5299        /* The VM has been completely destroyed.
    51715300         *
    5172          *  Note: This state change can happen at two points:
    5173          *        1) At the end of VMR3Destroy() if it was not called from EMT.
    5174          *        2) At the end of vmR3EmulationThread if VMR3Destroy() was
    5175          *           called by EMT.
     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.
    51765305         */
    51775306        case VMSTATE_TERMINATED:
     
    51825311                break;
    51835312
    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.
    51895317             */
    51905318            if (aVM)
    51915319                that->powerDownHostInterfaces();
    51925320
    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.
    51965323             */
    51975324            switch (that->mMachineState)
     
    52055332                    break;
    52065333                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) */
    52135338                    that->setMachineStateLocally (MachineState_Saved);
    52145339                    break;
    52155340                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) */
    52205343                    that->setMachineState (MachineState_PoweredOff);
    52215344                    break;
    52225345                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) */
    52275348                    that->setMachineState (MachineState_Saved);
    52285349                    break;
     
    52595380                    break;
    52605381
    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 */
    52655384                Assert (   (   (   that->mMachineState == MachineState_Starting
    52665385                                || that->mMachineState == MachineState_Paused)
     
    62926411}
    62936412
    6294 
    6295 
    62966413/**
    62976414 *  Thread function which starts the VM (also from saved state) and
     
    70147131    LogFlowFuncEnter();
    70157132
    7016     std::auto_ptr <VMTask> task (static_cast <VMTask *> (pvUser));
     7133    std::auto_ptr <VMProgressTask> task (static_cast <VMProgressTask *> (pvUser));
    70177134    AssertReturn (task.get(), VERR_INVALID_PARAMETER);
    70187135
     
    70217138    const ComObjPtr <Console> &that = task->mConsole;
    70227139
    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 */
    70297147    task->releaseVMCaller();
    70307148
    7031     HRESULT rc = that->powerDown();
    7032     AssertComRC (rc);
     7149    that->powerDown (task->mProgress);
    70337150
    70347151    LogFlowFuncLeave();
  • trunk/src/VBox/Main/idl/VirtualBox.xidl

    r13227 r13374  
    42874287  <interface
    42884288     name="IConsole" extends="$unknown"
    4289      uuid="3acbd337-925f-497d-a624-465c8a99ae5a"
     4289     uuid="e3c6d4a1-a935-47ca-b16d-f9e9c496e53e"
    42904290     wsmap="managed"
    42914291     >
     
    44244424
    44254425        <note>
    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
    4434             will power 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.
    44354435        </note>
    44364436
     
    44444444    <method name="powerUpPaused">
    44454445      <desc>
    4446         Identical to powerUp save that the VM will enter the
    4447         <link to="MachineState::Paused"/> state, instead of
    4448         <link to="MachineState::Running"/>.
     4446        Identical to powerUp except that the VM will enter the
     4447        <link to="MachineState::Paused"/> state, instead of
     4448        <link to="MachineState::Running"/>.
    44494449
    44504450        <see>#powerUp</see>
     
    44604460        After this operation completes, the machine will go to the
    44614461        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>
    44634486    </method>
    44644487
  • trunk/src/VBox/Main/include/ConsoleImpl.h

    r13165 r13374  
    130130    STDMETHOD(PowerUpPaused) (IProgress **aProgress);
    131131    STDMETHOD(PowerDown)();
     132    STDMETHOD(PowerDownAsync) (IProgress **aProgress);
    132133    STDMETHOD(Reset)();
    133134    STDMETHOD(Pause)();
     
    403404    HRESULT consoleInitReleaseLog (const ComPtr <IMachine> aMachine);
    404405
    405     HRESULT powerUpCommon (IProgress **aProgress, bool aPaused);
    406     HRESULT powerDown();
     406    HRESULT powerUp (IProgress **aProgress, bool aPaused);
     407    HRESULT powerDown (Progress *aProgress = NULL);
    407408
    408409    HRESULT callTapSetupApplication(bool isStatic, RTFILE tapFD, Bstr &tapDevice,
     
    525526    /** true when Console has entered the mpVM destruction phase */
    526527    bool mVMDestroying : 1;
     528    /** true when power down is initiated by vmstateChangeCallback (EMT) */
     529    bool mVMPoweredOff : 1;
    527530
    528531    /** The current DVD drive state in the VM.
Note: See TracChangeset for help on using the changeset viewer.

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