third_party/virtualbox/src/VBox/VMM/VMMR3/VM.cpp
/**
 * Common worker for VMR3Save and VMR3Teleport.
 *
 * @returns VBox status code.
 *
 * @param   pVM                 The cross context VM structure.
 * @param   cMsMaxDowntime      The maximum downtime given as milliseconds.
 * @param   pszFilename         The name of the file.  NULL if pStreamOps is used.
 * @param   pStreamOps          The stream methods.  NULL if pszFilename is used.
 * @param   pvStreamOpsUser     The user argument to the stream methods.
 * @param   enmAfter            What to do afterwards.
 * @param   pfnProgress         Progress callback. Optional.
 * @param   pvProgressUser      User argument for the progress callback.
 * @param   pfSuspended         Set if we suspended the VM.
 * @param   fSkipStateChanges   Set if we're supposed to skip state changes (FTM delta case)
 *
 * @thread  Non-EMT
 */


@param   pVM                 The cross context VM structure.
@param   cMsMaxDowntime      The maximum downtime given as milliseconds.
@param   pszFilename         The name of the file.  NULL if pStreamOps is used.
@param   pStreamOps          The stream methods.  NULL if pszFilename is used.
@param   pvStreamOpsUser     The user argument to the stream methods.
@param   enmAfter            What to do afterwards.
@param   pfnProgress         Progress callback. Optional.
@param   pvProgressUser      User argument for the progress callback.
@param   pfSuspended         Set if we suspended the VM.
@param   fSkipStateChanges   Set if we're supposed to skip state changes (FTM delta case)

@thread  Non-EMT
@param pVM The cross context VM structure . @param cMsMaxDowntime The maximum downtime given as milliseconds . @param pszFilename The name of the file . NULL if pStreamOps is used . @param pStreamOps The stream methods . NULL if pszFilename is used . @param pvStreamOpsUser The user argument to the stream methods . @param enmAfter What to do afterwards . @param pfnProgress Progress callback . Optional . @param pvProgressUser User argument for the progress callback . @param pfSuspended Set if we suspended the VM . @param fSkipStateChanges Set if we ' re supposed to skip state changes ( FTM delta case ) @thread Non - EMT
static int vmR3SaveTeleport(PVM pVM, uint32_t cMsMaxDowntime,
                            const char *pszFilename, PCSSMSTRMOPS pStreamOps, void *pvStreamOpsUser,
                            SSMAFTER enmAfter, PFNVMPROGRESS pfnProgress, void *pvProgressUser, bool *pfSuspended,
                            bool fSkipStateChanges)
{
    PSSMHANDLE pSSM;
    int rc = VMR3ReqCallWait(pVM, 0 ,
                             (PFNRT)vmR3Save, 10, pVM, cMsMaxDowntime, pszFilename, pStreamOps, pvStreamOpsUser,
                             enmAfter, pfnProgress, pvProgressUser, &pSSM, fSkipStateChanges);
    if (    RT_SUCCESS(rc)
        &&  pSSM)
    {
        Assert(!fSkipStateChanges);
        rc = SSMR3LiveDoStep1(pSSM);
        if (RT_SUCCESS(rc))
        {
            if (VMR3GetState(pVM) != VMSTATE_SAVING)
                for (;;)
                {
                    rc = VMMR3EmtRendezvous(pVM, VMMEMTRENDEZVOUS_FLAGS_TYPE_DESCENDING | VMMEMTRENDEZVOUS_FLAGS_STOP_ON_ERROR,
                                            vmR3LiveDoSuspend, pfSuspended);
                    if (rc != VERR_TRY_AGAIN)
                        break;
                    RTThreadSleep(250); 
                }
            if (RT_SUCCESS(rc))
                rc = VMR3ReqCallWait(pVM, 0 , (PFNRT)vmR3LiveDoStep2, 2, pVM, pSSM);
            else
            {
                int rc2 = VMR3ReqCallWait(pVM, 0 , (PFNRT)SSMR3LiveDone, 1, pSSM);
                AssertMsg(rc2 == rc, ("%Rrc != %Rrc\n", rc2, rc)); NOREF(rc2);
            }
        }
        else
        {
            int rc2 = VMR3ReqCallWait(pVM, 0 , (PFNRT)SSMR3LiveDone, 1, pSSM);
            AssertMsg(rc2 == rc, ("%Rrc != %Rrc\n", rc2, rc));
            rc2 = VMMR3EmtRendezvous(pVM, VMMEMTRENDEZVOUS_FLAGS_TYPE_ONCE, vmR3LiveDoStep1Cleanup, pfSuspended);
            if (RT_FAILURE(rc2) && rc == VERR_SSM_CANCELLED)
                rc = rc2;
        }
    }
    return rc;
}
static int vmR3SaveTeleport ( PVM pVM , uint32_t cMsMaxDowntime , const char * pszFilename , PCSSMSTRMOPS pStreamOps , void * pvStreamOpsUser , SSMAFTER enmAfter , PFNVMPROGRESS pfnProgress , void * pvProgressUser , bool * pfSuspended , bool fSkipStateChanges ) { PSSMHANDLE pSSM ; int rc = VMR3ReqCallWait ( pVM , 0 , ( PFNRT ) vmR3Save , 10 , pVM , cMsMaxDowntime , pszFilename , pStreamOps , pvStreamOpsUser , enmAfter , pfnProgress , pvProgressUser , & pSSM , fSkipStateChanges ) ; if ( RT_SUCCESS ( rc ) && pSSM ) { Assert ( ! fSkipStateChanges ) ; rc = SSMR3LiveDoStep1 ( pSSM ) ; if ( RT_SUCCESS ( rc ) ) { if ( VMR3GetState ( pVM ) != VMSTATE_SAVING ) for ( ; ; ) { rc = VMMR3EmtRendezvous ( pVM , VMMEMTRENDEZVOUS_FLAGS_TYPE_DESCENDING | VMMEMTRENDEZVOUS_FLAGS_STOP_ON_ERROR , vmR3LiveDoSuspend , pfSuspended ) ; if ( rc != VERR_TRY_AGAIN ) break ; RTThreadSleep ( 250 ) ; } if ( RT_SUCCESS ( rc ) ) rc = VMR3ReqCallWait ( pVM , 0 , ( PFNRT ) vmR3LiveDoStep2 , 2 , pVM , pSSM ) ; else { int rc2 = VMR3ReqCallWait ( pVM , 0 , ( PFNRT ) SSMR3LiveDone , 1 , pSSM ) ; AssertMsg ( rc2 == rc , ( " \n " , rc2 , rc ) ) ; NOREF ( rc2 ) ; } } else { int rc2 = VMR3ReqCallWait ( pVM , 0 , ( PFNRT ) SSMR3LiveDone , 1 , pSSM ) ; AssertMsg ( rc2 == rc , ( " \n " , rc2 , rc ) ) ; rc2 = VMMR3EmtRendezvous ( pVM , VMMEMTRENDEZVOUS_FLAGS_TYPE_ONCE , vmR3LiveDoStep1Cleanup , pfSuspended ) ; if ( RT_FAILURE ( rc2 ) && rc == VERR_SSM_CANCELLED ) rc = rc2 ; } } return rc ; }
Common worker for VMR3Save and VMR3Teleport.
Common worker for VMR3Save and VMR3Teleport .
/*
     * Request the operation in EMT(0).
     */ /*idDstCpu*/ /*
         * Live snapshot.
         *
         * The state handling here is kind of tricky, doing it on EMT(0) helps
         * a bit. See the VMSTATE diagram for details.
         */ /* Try suspend the VM. */ /* Wait for the state to change. */ /** @todo Live Migration: fix this polling wait by some smart use of multiple release event  semaphores.. */ /*idDstCpu*/ /*idDstCpu*/ /*idDstCpu*/