third_party/virtualbox/src/VBox/VMM/VMMR3/VM.cpp
/**
 * Destroys the UVM portion.
 *
 * This is called as the final step in the VM destruction or as the cleanup
 * in case of a creation failure.
 *
 * @param   pUVM            The user mode VM structure.
 * @param   cMilliesEMTWait The number of milliseconds to wait for the emulation
 *                          threads.
 */
Destroys the UVM portion.
This is called as the final step in the VM destruction or as the cleanup
in case of a creation failure.

@param   pUVM            The user mode VM structure.
@param   cMilliesEMTWait The number of milliseconds to wait for the emulation
threads.
Destroys the UVM portion . This is called as the final step in the VM destruction or as the cleanup in case of a creation failure . @param pUVM The user mode VM structure . @param cMilliesEMTWait The number of milliseconds to wait for the emulation threads .
static void vmR3DestroyUVM(PUVM pUVM, uint32_t cMilliesEMTWait)
{
    ASMAtomicUoWriteBool(&pUVM->vm.s.fTerminateEMT, true);
    if (pUVM->pVM)
        VM_FF_SET(pUVM->pVM, VM_FF_CHECK_VM_STATE); 
    VMCPUID iCpu = pUVM->cCpus;
    while (iCpu-- > 0)
    {
        VMR3NotifyGlobalFFU(pUVM, VMNOTIFYFF_FLAGS_DONE_REM);
        RTSemEventSignal(pUVM->aCpus[iCpu].vm.s.EventSemWait);
    }
    ASMAtomicUoWriteBool(&pUVM->vm.s.fTerminateEMT, true);
    RTTHREAD const hSelf = RTThreadSelf();
    RTTHREAD hThread = pUVM->aCpus[0].vm.s.ThreadEMT;
    if (   hThread != NIL_RTTHREAD
        && hThread != hSelf)
    {
        int rc2 = RTThreadWait(hThread, RT_MAX(cMilliesEMTWait, 2000), NULL);
        if (rc2 == VERR_TIMEOUT) 
            rc2 = RTThreadWait(hThread, 1000, NULL);
        AssertLogRelMsgRC(rc2, ("iCpu=0 rc=%Rrc\n", rc2));
        if (RT_SUCCESS(rc2))
            pUVM->aCpus[0].vm.s.ThreadEMT = NIL_RTTHREAD;
    }
    for (iCpu = 1; iCpu < pUVM->cCpus; iCpu++)
    {
        ASMAtomicXchgHandle(&pUVM->aCpus[iCpu].vm.s.ThreadEMT, NIL_RTTHREAD, &hThread);
        if (hThread != NIL_RTTHREAD)
        {
            if (hThread != hSelf)
            {
                int rc2 = RTThreadWait(hThread, 250 , NULL);
                AssertLogRelMsgRC(rc2, ("iCpu=%u rc=%Rrc\n", iCpu, rc2));
                if (RT_SUCCESS(rc2))
                    continue;
            }
            pUVM->aCpus[iCpu].vm.s.ThreadEMT = hThread;
        }
    }
    iCpu = pUVM->cCpus;
    while (iCpu-- > 0)
    {
        RTSemEventDestroy(pUVM->aCpus[iCpu].vm.s.EventSemWait);
        pUVM->aCpus[iCpu].vm.s.EventSemWait = NIL_RTSEMEVENT;
    }
    unsigned cReqs = 0;
    for (unsigned i = 0; i < RT_ELEMENTS(pUVM->vm.s.apReqFree); i++)
    {
        PVMREQ pReq = pUVM->vm.s.apReqFree[i];
        pUVM->vm.s.apReqFree[i] = NULL;
        for (; pReq; pReq = pReq->pNext, cReqs++)
        {
            pReq->enmState = VMREQSTATE_INVALID;
            RTSemEventDestroy(pReq->EventSem);
        }
    }
    Assert(cReqs == pUVM->vm.s.cReqFree); NOREF(cReqs);
    for (unsigned i = 0; i < 10; i++)
    {
        PVMREQ pReqHead = ASMAtomicXchgPtrT(&pUVM->vm.s.pPriorityReqs, NULL, PVMREQ);
        if (!pReqHead)
        {
            pReqHead = ASMAtomicXchgPtrT(&pUVM->vm.s.pNormalReqs, NULL, PVMREQ);
            if (!pReqHead)
                break;
        }
        AssertLogRelMsgFailed(("Requests pending! VMR3Destroy caller has to serialize this.\n"));
        for (PVMREQ pReq = pReqHead; pReq; pReq = pReq->pNext)
        {
            ASMAtomicUoWriteS32(&pReq->iStatus, VERR_VM_REQUEST_KILLED);
            ASMAtomicWriteSize(&pReq->enmState, VMREQSTATE_INVALID);
            RTSemEventSignal(pReq->EventSem);
            RTThreadSleep(2);
            RTSemEventDestroy(pReq->EventSem);
        }
        RTThreadSleep(32);
    }
    for (VMCPUID idCpu = 0; idCpu < pUVM->cCpus; idCpu++)
    {
        PUVMCPU pUVCpu = &pUVM->aCpus[idCpu];
        for (unsigned i = 0; i < 10; i++)
        {
            PVMREQ pReqHead = ASMAtomicXchgPtrT(&pUVCpu->vm.s.pPriorityReqs, NULL, PVMREQ);
            if (!pReqHead)
            {
                pReqHead = ASMAtomicXchgPtrT(&pUVCpu->vm.s.pNormalReqs, NULL, PVMREQ);
                if (!pReqHead)
                    break;
            }
            AssertLogRelMsgFailed(("Requests pending! VMR3Destroy caller has to serialize this.\n"));
            for (PVMREQ pReq = pReqHead; pReq; pReq = pReq->pNext)
            {
                ASMAtomicUoWriteS32(&pReq->iStatus, VERR_VM_REQUEST_KILLED);
                ASMAtomicWriteSize(&pReq->enmState, VMREQSTATE_INVALID);
                RTSemEventSignal(pReq->EventSem);
                RTThreadSleep(2);
                RTSemEventDestroy(pReq->EventSem);
            }
            RTThreadSleep(32);
        }
    }
    PDMR3TermUVM(pUVM);
    RTCritSectDelete(&pUVM->vm.s.AtErrorCritSect);
    RTCritSectDelete(&pUVM->vm.s.AtStateCritSect);
    if (pUVM->vm.s.pSession)
    {
        int rc = SUPR3Term(false );
        AssertRC(rc);
        pUVM->vm.s.pSession = NIL_RTR0PTR;
    }
    VMR3ReleaseUVM(pUVM);
#ifdef LOG_ENABLED
    RTLogSetCustomPrefixCallback(NULL, NULL, NULL);
#endif
    RTLogFlush(NULL);
}
static void vmR3DestroyUVM ( PUVM pUVM , uint32_t cMilliesEMTWait ) { ASMAtomicUoWriteBool ( & pUVM -> vm . s . fTerminateEMT , true ) ; if ( pUVM -> pVM ) VM_FF_SET ( pUVM -> pVM , VM_FF_CHECK_VM_STATE ) ; VMCPUID iCpu = pUVM -> cCpus ; while ( iCpu -- > 0 ) { VMR3NotifyGlobalFFU ( pUVM , VMNOTIFYFF_FLAGS_DONE_REM ) ; RTSemEventSignal ( pUVM -> aCpus [ iCpu ] . vm . s . EventSemWait ) ; } ASMAtomicUoWriteBool ( & pUVM -> vm . s . fTerminateEMT , true ) ; RTTHREAD const hSelf = RTThreadSelf ( ) ; RTTHREAD hThread = pUVM -> aCpus [ 0 ] . vm . s . ThreadEMT ; if ( hThread != NIL_RTTHREAD && hThread != hSelf ) { int rc2 = RTThreadWait ( hThread , RT_MAX ( cMilliesEMTWait , 2000 ) , NULL ) ; if ( rc2 == VERR_TIMEOUT ) rc2 = RTThreadWait ( hThread , 1000 , NULL ) ; AssertLogRelMsgRC ( rc2 , ( " \n " , rc2 ) ) ; if ( RT_SUCCESS ( rc2 ) ) pUVM -> aCpus [ 0 ] . vm . s . ThreadEMT = NIL_RTTHREAD ; } for ( iCpu = 1 ; iCpu < pUVM -> cCpus ; iCpu ++ ) { ASMAtomicXchgHandle ( & pUVM -> aCpus [ iCpu ] . vm . s . ThreadEMT , NIL_RTTHREAD , & hThread ) ; if ( hThread != NIL_RTTHREAD ) { if ( hThread != hSelf ) { int rc2 = RTThreadWait ( hThread , 250 , NULL ) ; AssertLogRelMsgRC ( rc2 , ( " \n " , iCpu , rc2 ) ) ; if ( RT_SUCCESS ( rc2 ) ) continue ; } pUVM -> aCpus [ iCpu ] . vm . s . ThreadEMT = hThread ; } } iCpu = pUVM -> cCpus ; while ( iCpu -- > 0 ) { RTSemEventDestroy ( pUVM -> aCpus [ iCpu ] . vm . s . EventSemWait ) ; pUVM -> aCpus [ iCpu ] . vm . s . EventSemWait = NIL_RTSEMEVENT ; } unsigned cReqs = 0 ; for ( unsigned i = 0 ; i < RT_ELEMENTS ( pUVM -> vm . s . apReqFree ) ; i ++ ) { PVMREQ pReq = pUVM -> vm . s . apReqFree [ i ] ; pUVM -> vm . s . apReqFree [ i ] = NULL ; for ( ; pReq ; pReq = pReq -> pNext , cReqs ++ ) { pReq -> enmState = VMREQSTATE_INVALID ; RTSemEventDestroy ( pReq -> EventSem ) ; } } Assert ( cReqs == pUVM -> vm . s . cReqFree ) ; NOREF ( cReqs ) ; for ( unsigned i = 0 ; i < 10 ; i ++ ) { PVMREQ pReqHead = ASMAtomicXchgPtrT ( & pUVM -> vm . s . pPriorityReqs , NULL , PVMREQ ) ; if ( ! pReqHead ) { pReqHead = ASMAtomicXchgPtrT ( & pUVM -> vm . s . pNormalReqs , NULL , PVMREQ ) ; if ( ! pReqHead ) break ; } AssertLogRelMsgFailed ( ( " \n " ) ) ; for ( PVMREQ pReq = pReqHead ; pReq ; pReq = pReq -> pNext ) { ASMAtomicUoWriteS32 ( & pReq -> iStatus , VERR_VM_REQUEST_KILLED ) ; ASMAtomicWriteSize ( & pReq -> enmState , VMREQSTATE_INVALID ) ; RTSemEventSignal ( pReq -> EventSem ) ; RTThreadSleep ( 2 ) ; RTSemEventDestroy ( pReq -> EventSem ) ; } RTThreadSleep ( 32 ) ; } for ( VMCPUID idCpu = 0 ; idCpu < pUVM -> cCpus ; idCpu ++ ) { PUVMCPU pUVCpu = & pUVM -> aCpus [ idCpu ] ; for ( unsigned i = 0 ; i < 10 ; i ++ ) { PVMREQ pReqHead = ASMAtomicXchgPtrT ( & pUVCpu -> vm . s . pPriorityReqs , NULL , PVMREQ ) ; if ( ! pReqHead ) { pReqHead = ASMAtomicXchgPtrT ( & pUVCpu -> vm . s . pNormalReqs , NULL , PVMREQ ) ; if ( ! pReqHead ) break ; } AssertLogRelMsgFailed ( ( " \n " ) ) ; for ( PVMREQ pReq = pReqHead ; pReq ; pReq = pReq -> pNext ) { ASMAtomicUoWriteS32 ( & pReq -> iStatus , VERR_VM_REQUEST_KILLED ) ; ASMAtomicWriteSize ( & pReq -> enmState , VMREQSTATE_INVALID ) ; RTSemEventSignal ( pReq -> EventSem ) ; RTThreadSleep ( 2 ) ; RTSemEventDestroy ( pReq -> EventSem ) ; } RTThreadSleep ( 32 ) ; } } PDMR3TermUVM ( pUVM ) ; RTCritSectDelete ( & pUVM -> vm . s . AtErrorCritSect ) ; RTCritSectDelete ( & pUVM -> vm . s . AtStateCritSect ) ; if ( pUVM -> vm . s . pSession ) { int rc = SUPR3Term ( false ) ; AssertRC ( rc ) ; pUVM -> vm . s . pSession = NIL_RTR0PTR ; } VMR3ReleaseUVM ( pUVM ) ; #ifdef LOG_ENABLED RTLogSetCustomPrefixCallback ( NULL , NULL , NULL ) ; #endif RTLogFlush ( NULL ) ; }
Destroys the UVM portion.
Destroys the UVM portion .
/*
     * Signal termination of each the emulation threads and
     * wait for them to complete.
     */ /* Signal them - in reverse order since EMT(0) waits for the others. */ /* Can't hurt... */ /* Wait for EMT(0), it in turn waits for the rest. */ /* avoid the assertion when debugging. */ /* Just in case we're in a weird failure situation w/o EMT(0) to do the
       waiting, wait the other EMTs too. */ /*ms*/ /* Cleanup the semaphores. */ /*
     * Free the event semaphores associated with the request packets.
     */ /*
     * Kill all queued requests. (There really shouldn't be any!)
     */ /* give them a chance to respond before we free the request memory. */ /*
     * Now all queued VCPU requests (again, there shouldn't be any).
     */ /* give them a chance to respond before we free the request memory. */ /*
     * Make sure the VMMR0.r0 module and whatever else is unloaded.
     */ /*
     * Terminate the support library if initialized.
     */ /*fForced*/ /*
     * Release the UVM structure reference.
     */ /*
     * Clean up and flush logs.
     */