VirtualBox

Changeset 43378 in vbox for trunk/src/VBox/Frontends


Ignore:
Timestamp:
Sep 20, 2012 8:16:58 PM (12 years ago)
Author:
vboxsync
Message:

Autostart: Implement stop feature for Linux hosts

Location:
trunk/src/VBox/Frontends/VBoxAutostart
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Frontends/VBoxAutostart/VBoxAutostart.cpp

    r42732 r43378  
    9999};
    100100
     101/** Set by the signal handler. */
     102static volatile bool    g_fCanceled = false;
     103
     104
     105/**
     106 * Signal handler that sets g_fCanceled.
     107 *
     108 * This can be executed on any thread in the process, on Windows it may even be
     109 * a thread dedicated to delivering this signal.  Do not doing anything
     110 * unnecessary here.
     111 */
     112static void showProgressSignalHandler(int iSignal)
     113{
     114    NOREF(iSignal);
     115    ASMAtomicWriteBool(&g_fCanceled, true);
     116}
     117
     118/**
     119 * Print out progress on the console.
     120 *
     121 * This runs the main event queue every now and then to prevent piling up
     122 * unhandled things (which doesn't cause real problems, just makes things
     123 * react a little slower than in the ideal case).
     124 */
     125DECLHIDDEN(HRESULT) showProgress(ComPtr<IProgress> progress)
     126{
     127    using namespace com;
     128
     129    BOOL fCompleted = FALSE;
     130    ULONG ulCurrentPercent = 0;
     131    ULONG ulLastPercent = 0;
     132
     133    ULONG ulLastOperationPercent = (ULONG)-1;
     134
     135    ULONG ulLastOperation = (ULONG)-1;
     136    Bstr bstrOperationDescription;
     137
     138    EventQueue::getMainEventQueue()->processEventQueue(0);
     139
     140    ULONG cOperations = 1;
     141    HRESULT hrc = progress->COMGETTER(OperationCount)(&cOperations);
     142    if (FAILED(hrc))
     143    {
     144        RTStrmPrintf(g_pStdErr, "Progress object failure: %Rhrc\n", hrc);
     145        RTStrmFlush(g_pStdErr);
     146        return hrc;
     147    }
     148
     149    /*
     150     * Note: Outputting the progress info to stderr (g_pStdErr) is intentional
     151     *       to not get intermixed with other (raw) stdout data which might get
     152     *       written in the meanwhile.
     153     */
     154    RTStrmPrintf(g_pStdErr, "0%%...");
     155    RTStrmFlush(g_pStdErr);
     156
     157    /* setup signal handling if cancelable */
     158    bool fCanceledAlready = false;
     159    BOOL fCancelable;
     160    hrc = progress->COMGETTER(Cancelable)(&fCancelable);
     161    if (FAILED(hrc))
     162        fCancelable = FALSE;
     163    if (fCancelable)
     164    {
     165        signal(SIGINT,   showProgressSignalHandler);
     166#ifdef SIGBREAK
     167        signal(SIGBREAK, showProgressSignalHandler);
     168#endif
     169    }
     170
     171    hrc = progress->COMGETTER(Completed(&fCompleted));
     172    while (SUCCEEDED(hrc))
     173    {
     174        progress->COMGETTER(Percent(&ulCurrentPercent));
     175
     176        /* did we cross a 10% mark? */
     177        if (ulCurrentPercent / 10  >  ulLastPercent / 10)
     178        {
     179            /* make sure to also print out missed steps */
     180            for (ULONG curVal = (ulLastPercent / 10) * 10 + 10; curVal <= (ulCurrentPercent / 10) * 10; curVal += 10)
     181            {
     182                if (curVal < 100)
     183                {
     184                    RTStrmPrintf(g_pStdErr, "%u%%...", curVal);
     185                    RTStrmFlush(g_pStdErr);
     186                }
     187            }
     188            ulLastPercent = (ulCurrentPercent / 10) * 10;
     189        }
     190
     191        if (fCompleted)
     192            break;
     193
     194        /* process async cancelation */
     195        if (g_fCanceled && !fCanceledAlready)
     196        {
     197            hrc = progress->Cancel();
     198            if (SUCCEEDED(hrc))
     199                fCanceledAlready = true;
     200            else
     201                g_fCanceled = false;
     202        }
     203
     204        /* make sure the loop is not too tight */
     205        progress->WaitForCompletion(100);
     206
     207        EventQueue::getMainEventQueue()->processEventQueue(0);
     208        hrc = progress->COMGETTER(Completed(&fCompleted));
     209    }
     210
     211    /* undo signal handling */
     212    if (fCancelable)
     213    {
     214        signal(SIGINT,   SIG_DFL);
     215#ifdef SIGBREAK
     216        signal(SIGBREAK, SIG_DFL);
     217#endif
     218    }
     219
     220    /* complete the line. */
     221    LONG iRc = E_FAIL;
     222    hrc = progress->COMGETTER(ResultCode)(&iRc);
     223    if (SUCCEEDED(hrc))
     224    {
     225        if (SUCCEEDED(iRc))
     226            RTStrmPrintf(g_pStdErr, "100%%\n");
     227        else if (g_fCanceled)
     228            RTStrmPrintf(g_pStdErr, "CANCELED\n");
     229        else
     230        {
     231            RTStrmPrintf(g_pStdErr, "\n");
     232            RTStrmPrintf(g_pStdErr, "Progress state: %Rhrc\n", iRc);
     233        }
     234        hrc = iRc;
     235    }
     236    else
     237    {
     238        RTStrmPrintf(g_pStdErr, "\n");
     239        RTStrmPrintf(g_pStdErr, "Progress object failure: %Rhrc\n", hrc);
     240    }
     241    RTStrmFlush(g_pStdErr);
     242    return hrc;
     243}
     244
     245DECLHIDDEN(const char *) machineStateToName(MachineState_T machineState, bool fShort)
     246{
     247    switch (machineState)
     248    {
     249        case MachineState_PoweredOff:
     250            return fShort ? "poweroff"             : "powered off";
     251        case MachineState_Saved:
     252            return "saved";
     253        case MachineState_Aborted:
     254            return "aborted";
     255        case MachineState_Teleported:
     256            return "teleported";
     257        case MachineState_Running:
     258            return "running";
     259        case MachineState_Paused:
     260            return "paused";
     261        case MachineState_Stuck:
     262            return fShort ? "gurumeditation"       : "guru meditation";
     263        case MachineState_LiveSnapshotting:
     264            return fShort ? "livesnapshotting"     : "live snapshotting";
     265        case MachineState_Teleporting:
     266            return "teleporting";
     267        case MachineState_Starting:
     268            return "starting";
     269        case MachineState_Stopping:
     270            return "stopping";
     271        case MachineState_Saving:
     272            return "saving";
     273        case MachineState_Restoring:
     274            return "restoring";
     275        case MachineState_TeleportingPausedVM:
     276            return fShort ? "teleportingpausedvm"  : "teleporting paused vm";
     277        case MachineState_TeleportingIn:
     278            return fShort ? "teleportingin"        : "teleporting (incoming)";
     279        case MachineState_RestoringSnapshot:
     280            return fShort ? "restoringsnapshot"    : "restoring snapshot";
     281        case MachineState_DeletingSnapshot:
     282            return fShort ? "deletingsnapshot"     : "deleting snapshot";
     283        case MachineState_DeletingSnapshotOnline:
     284            return fShort ? "deletingsnapshotlive" : "deleting snapshot live";
     285        case MachineState_DeletingSnapshotPaused:
     286            return fShort ? "deletingsnapshotlivepaused" : "deleting snapshot live paused";
     287        case MachineState_SettingUp:
     288            return fShort ? "settingup"           : "setting up";
     289        default:
     290            break;
     291    }
     292    return "unknown";
     293}
    101294
    102295DECLHIDDEN(void) serviceLog(const char *pszFormat, ...)
  • trunk/src/VBox/Frontends/VBoxAutostart/VBoxAutostart.h

    r42732 r43378  
    113113
    114114/**
     115 * Print out progress on the console.
     116 *
     117 * This runs the main event queue every now and then to prevent piling up
     118 * unhandled things (which doesn't cause real problems, just makes things
     119 * react a little slower than in the ideal case).
     120 */
     121DECLHIDDEN(HRESULT) showProgress(ComPtr<IProgress> progress);
     122
     123/**
     124 * Converts the machine state to a human readable string.
     125 *
     126 * @returns Pointer to the human readable state.
     127 * @param   enmMachineState    Machine state to convert.
     128 * @param   fShort             Flag whether to return a short form.
     129 */
     130DECLHIDDEN(const char *) machineStateToName(MachineState_T enmMachineState, bool fShort);
     131
     132/**
    115133 * Parse the given configuration file and return the interesting config parameters.
    116134 *
  • trunk/src/VBox/Frontends/VBoxAutostart/VBoxAutostartStop.cpp

    r42732 r43378  
    2727#include <iprt/log.h>
    2828#include <iprt/assert.h>
     29#include <iprt/message.h>
    2930
    3031#include <algorithm>
     
    3637using namespace com;
    3738
     39/**
     40 * VM list entry.
     41 */
     42typedef struct AUTOSTOPVM
     43{
     44    /** ID of the VM to start. */
     45    Bstr           strId;
     46    /** Action to do with the VM. */
     47    AutostopType_T enmAutostopType;
     48} AUTOSTOPVM;
     49
     50static HRESULT autostartSaveVMState(ComPtr<IConsole> &console)
     51{
     52    HRESULT rc = S_OK;
     53    ComPtr<IProgress> progress;
     54
     55    do
     56    {
     57        /* first pause so we don't trigger a live save which needs more time/resources */
     58        bool fPaused = false;
     59        rc = console->Pause();
     60        if (FAILED(rc))
     61        {
     62            bool fError = true;
     63            if (rc == VBOX_E_INVALID_VM_STATE)
     64            {
     65                /* check if we are already paused */
     66                MachineState_T machineState;
     67                CHECK_ERROR_BREAK(console, COMGETTER(State)(&machineState));
     68                /* the error code was lost by the previous instruction */
     69                rc = VBOX_E_INVALID_VM_STATE;
     70                if (machineState != MachineState_Paused)
     71                {
     72                    RTMsgError("Machine in invalid state %d -- %s\n",
     73                               machineState, machineStateToName(machineState, false));
     74                }
     75                else
     76                {
     77                    fError = false;
     78                    fPaused = true;
     79                }
     80            }
     81            if (fError)
     82                break;
     83        }
     84
     85        CHECK_ERROR(console, SaveState(progress.asOutParam()));
     86        if (FAILED(rc))
     87        {
     88            if (!fPaused)
     89                console->Resume();
     90            break;
     91        }
     92
     93        rc = showProgress(progress);
     94        CHECK_PROGRESS_ERROR(progress, ("Failed to save machine state"));
     95        if (FAILED(rc))
     96        {
     97            if (!fPaused)
     98                console->Resume();
     99        }
     100    } while (0);
     101
     102    return rc;
     103}
     104
    38105DECLHIDDEN(RTEXITCODE) autostartStopMain(PCFGAST pCfgAst)
    39106{
    40107    RTEXITCODE rcExit = RTEXITCODE_SUCCESS;
    41 
    42     AssertMsgFailed(("Not implemented yet!\n"));
     108    int vrc = VINF_SUCCESS;
     109    std::list<AUTOSTOPVM> listVM;
     110
     111    /*
     112     * Build a list of all VMs we need to autostop first, apply the overrides
     113     * from the configuration and start the VMs afterwards.
     114     */
     115    com::SafeIfaceArray<IMachine> machines;
     116    HRESULT rc = g_pVirtualBox->COMGETTER(Machines)(ComSafeArrayAsOutParam(machines));
     117    if (SUCCEEDED(rc))
     118    {
     119        /*
     120         * Iterate through the collection and construct a list of machines
     121         * we have to check.
     122         */
     123        for (size_t i = 0; i < machines.size(); ++i)
     124        {
     125            if (machines[i])
     126            {
     127                BOOL fAccessible;
     128                CHECK_ERROR_BREAK(machines[i], COMGETTER(Accessible)(&fAccessible));
     129                if (!fAccessible)
     130                    continue;
     131
     132                AutostopType_T enmAutostopType;
     133                CHECK_ERROR_BREAK(machines[i], COMGETTER(AutostopType)(&enmAutostopType));
     134                if (enmAutostopType != AutostopType_Disabled)
     135                {
     136                    AUTOSTOPVM autostopVM;
     137
     138                    CHECK_ERROR_BREAK(machines[i], COMGETTER(Id)(autostopVM.strId.asOutParam()));
     139                    autostopVM.enmAutostopType = enmAutostopType;
     140
     141                    listVM.push_back(autostopVM);
     142                }
     143            }
     144        }
     145
     146        if (   SUCCEEDED(rc)
     147            && listVM.size())
     148        {
     149            std::list<AUTOSTOPVM>::iterator it;
     150            for (it = listVM.begin(); it != listVM.end(); it++)
     151            {
     152                MachineState_T enmMachineState;
     153                ComPtr<IMachine> machine;
     154
     155                CHECK_ERROR_BREAK(g_pVirtualBox, FindMachine((*it).strId.raw(),
     156                                                             machine.asOutParam()));
     157
     158                CHECK_ERROR_BREAK(machine, COMGETTER(State)(&enmMachineState));
     159
     160                /* Only power off running machines. */
     161                /** @todo: What about transient VM states? */
     162                if (   enmMachineState == MachineState_Running
     163                    || enmMachineState == MachineState_Paused)
     164                {
     165                    ComPtr<IMachine> sessionMachine;
     166                    ComPtr<IConsole> console;
     167                    ComPtr<IProgress> progress;
     168
     169                    /* open a session for the VM */
     170                    CHECK_ERROR_BREAK(machine, LockMachine(g_pSession, LockType_Shared));
     171
     172                    /* get the associated console */
     173                    CHECK_ERROR_BREAK(g_pSession, COMGETTER(Console)(console.asOutParam()));
     174                    CHECK_ERROR_BREAK(g_pSession, COMGETTER(Machine)(sessionMachine.asOutParam()));
     175
     176                    switch ((*it).enmAutostopType)
     177                    {
     178                        case AutostopType_SaveState:
     179                        {
     180                            rc = autostartSaveVMState(console);
     181                            break;
     182                        }
     183                        case AutostopType_PowerOff:
     184                        {
     185                            CHECK_ERROR_BREAK(console, PowerDown(progress.asOutParam()));
     186
     187                            rc = showProgress(progress);
     188                            CHECK_PROGRESS_ERROR(progress, ("Failed to power off machine"));
     189                            break;
     190                        }
     191                        case AutostopType_AcpiShutdown:
     192                        {
     193                            /** @todo: Wait for VM to change to powered off state. */
     194                            BOOL fGuestEnteredACPI = false;
     195                            CHECK_ERROR_BREAK(console, GetGuestEnteredACPIMode(&fGuestEnteredACPI));
     196                            if (fGuestEnteredACPI)
     197                                CHECK_ERROR_BREAK(console, PowerButton());
     198                            else
     199                            {
     200                                /* Use save state instead and log this to the console. */
     201                                serviceLog("The guest of VM \"%ls\" does not support ACPI shutdown, saving state...\n",
     202                                           (*it).strId.raw());
     203                                rc = autostartSaveVMState(console);
     204                            }
     205                            break;
     206                        }
     207                        default:
     208                            serviceLog("Unknown autostop type for VM \"%ls\"\n", (*it).strId.raw());
     209                    }
     210                }
     211                g_pSession->UnlockMachine();
     212            }
     213        }
     214    }
    43215
    44216    return rcExit;
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