VirtualBox

Changeset 20663 in vbox for trunk/src/VBox/VMM


Ignore:
Timestamp:
Jun 17, 2009 12:47:55 PM (16 years ago)
Author:
vboxsync
Message:

VMM: Added VMMR3EmtRendezvous for getting the attention of all EMTs and run some code on one. Made first use of it in vmR3SetHaltMethodU that is called at the end of VMR3CreateVM.

Location:
trunk/src/VBox/VMM
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/VMM/EM.cpp

    r20408 r20663  
    33203320    {
    33213321        /*
     3322         * EMT Rendezvous (must be serviced before termination).
     3323         */
     3324        if (VM_FF_ISPENDING(pVM, VM_FF_EMT_RENDEZVOUS))
     3325            VMMR3EmtRendezvousFF(pVM, pVCpu);
     3326
     3327        /*
    33223328         * Termination request.
    33233329         */
     
    33743380
    33753381        /* check that we got them all  */
    3376         AssertCompile(VM_FF_NORMAL_PRIORITY_POST_MASK == (VM_FF_TERMINATE | VM_FF_DBGF | VM_FF_RESET | VM_FF_PGM_NO_MEMORY));
     3382        AssertCompile(VM_FF_NORMAL_PRIORITY_POST_MASK == (VM_FF_TERMINATE | VM_FF_DBGF | VM_FF_RESET | VM_FF_PGM_NO_MEMORY | VM_FF_EMT_RENDEZVOUS));
    33773383        AssertCompile(VMCPU_FF_NORMAL_PRIORITY_POST_MASK == VMCPU_FF_CSAM_SCAN_PAGE);
    33783384    }
     
    33953401        if (VM_FF_IS_PENDING_EXCEPT(pVM, VM_FF_PDM_DMA, VM_FF_PGM_NO_MEMORY))
    33963402            PDMR3DmaRun(pVM);
     3403
     3404        /*
     3405         * EMT Rendezvous (make sure they are handled before the requests).
     3406         */
     3407        if (VM_FF_ISPENDING(pVM, VM_FF_EMT_RENDEZVOUS))
     3408            VMMR3EmtRendezvousFF(pVM, pVCpu);
    33973409
    33983410        /*
     
    34213433
    34223434        /* check that we got them all  */
    3423         AssertCompile(VM_FF_NORMAL_PRIORITY_MASK == (VM_FF_REQUEST | VM_FF_PDM_QUEUES | VM_FF_PDM_DMA | VM_FF_REM_HANDLER_NOTIFY));
     3435        AssertCompile(VM_FF_NORMAL_PRIORITY_MASK == (VM_FF_REQUEST | VM_FF_PDM_QUEUES | VM_FF_PDM_DMA | VM_FF_REM_HANDLER_NOTIFY | VM_FF_EMT_RENDEZVOUS));
    34243436    }
    34253437
     
    35363548
    35373549        /*
     3550         * EMT Rendezvous (must be serviced before termination).
     3551         */
     3552        if (VM_FF_ISPENDING(pVM, VM_FF_EMT_RENDEZVOUS))
     3553            VMMR3EmtRendezvousFF(pVM, pVCpu);
     3554
     3555        /*
    35383556         * Termination request.
    35393557         */
     
    35783596
    35793597        /* check that we got them all  */
    3580         AssertCompile(VM_FF_HIGH_PRIORITY_PRE_MASK == (VM_FF_TM_VIRTUAL_SYNC | VM_FF_DBGF | VM_FF_TERMINATE | VM_FF_DEBUG_SUSPEND | VM_FF_PGM_NEED_HANDY_PAGES | VM_FF_PGM_NO_MEMORY));
     3598        AssertCompile(VM_FF_HIGH_PRIORITY_PRE_MASK == (VM_FF_TM_VIRTUAL_SYNC | VM_FF_DBGF | VM_FF_TERMINATE | VM_FF_DEBUG_SUSPEND | VM_FF_PGM_NEED_HANDY_PAGES | VM_FF_PGM_NO_MEMORY | VM_FF_EMT_RENDEZVOUS));
    35813599        AssertCompile(VMCPU_FF_HIGH_PRIORITY_PRE_MASK == (VMCPU_FF_TIMER | VMCPU_FF_INTERRUPT_APIC | VMCPU_FF_INTERRUPT_PIC | VMCPU_FF_PGM_SYNC_CR3 | VMCPU_FF_PGM_SYNC_CR3_NON_GLOBAL | VMCPU_FF_SELM_SYNC_TSS | VMCPU_FF_TRPM_SYNC_IDT | VMCPU_FF_SELM_SYNC_GDT | VMCPU_FF_SELM_SYNC_LDT | VMCPU_FF_INHIBIT_INTERRUPTS));
    35823600    }
  • trunk/src/VBox/VMM/VMEmt.cpp

    r20593 r20663  
    155155                break;
    156156            }
     157            if (VM_FF_ISPENDING(pVM, VM_FF_EMT_RENDEZVOUS))
     158                VMMR3EmtRendezvousFF(pVM, &pVM->aCpus[idCpu]);
    157159            if (pUVM->vm.s.pReqs)
    158160            {
     
    203205            if (    rc == VINF_EM_TERMINATE
    204206                ||  pUVM->vm.s.fTerminateEMT
    205                 ||  (   pUVM->pVM
     207                ||  (   pUVM->pVM /* pVM may have become invalid by now. */
    206208                     && VM_FF_ISSET(pUVM->pVM, VM_FF_TERMINATE)))
    207209                break;
     
    10861088
    10871089/**
     1090 * Rendezvous callback that will be called once.
     1091 *
     1092 * @returns VBox status code.
     1093 * @param   pVM                 VM handle.
     1094 * @param   pVCpu               The VMCPU handle for the calling EMT.
     1095 * @param   pvUser              The new g_aHaltMethods index.
     1096 */
     1097static DECLCALLBACK(int) vmR3SetHaltMethodCallback(PVM pVM, PVMCPU pVCpu, void *pvUser)
     1098{
     1099    PUVM        pUVM = pVM->pUVM;
     1100    uintptr_t   i    = (uintptr_t)pvUser;
     1101    Assert(i < RT_ELEMENTS(g_aHaltMethods));
     1102    NOREF(pVCpu);
     1103
     1104    /*
     1105     * Terminate the old one.
     1106     */
     1107    if (    pUVM->vm.s.enmHaltMethod != VMHALTMETHOD_INVALID
     1108        &&  g_aHaltMethods[pUVM->vm.s.iHaltMethod].pfnTerm)
     1109    {
     1110        g_aHaltMethods[pUVM->vm.s.iHaltMethod].pfnTerm(pUVM);
     1111        pUVM->vm.s.enmHaltMethod = VMHALTMETHOD_INVALID;
     1112    }
     1113
     1114    /* Assert that the failure fallback is where we expect. */
     1115    Assert(g_aHaltMethods[0].enmHaltMethod == VMHALTMETHOD_BOOTSTRAP);
     1116    Assert(!g_aHaltMethods[0].pfnTerm && !g_aHaltMethods[0].pfnInit);
     1117
     1118    /*
     1119     * Init the new one.
     1120     */
     1121    int rc = VINF_SUCCESS;
     1122    memset(&pUVM->vm.s.Halt, 0, sizeof(pUVM->vm.s.Halt));
     1123    if (g_aHaltMethods[i].pfnInit)
     1124    {
     1125        rc = g_aHaltMethods[i].pfnInit(pUVM);
     1126        if (RT_FAILURE(rc))
     1127        {
     1128            /* Fall back on the bootstrap method. This requires no
     1129               init/term (see assertion above), and will always work. */
     1130            AssertLogRelRC(rc);
     1131            i = 0;
     1132        }
     1133    }
     1134
     1135    /*
     1136     * Commit it.
     1137     */
     1138    pUVM->vm.s.enmHaltMethod = g_aHaltMethods[i].enmHaltMethod;
     1139    ASMAtomicWriteU32(&pUVM->vm.s.iHaltMethod, i);
     1140
     1141    return rc;
     1142}
     1143
     1144
     1145/**
    10881146 * Changes the halt method.
    10891147 *
     
    11311189
    11321190    /*
    1133      * Terminate the old one.
    1134      */
    1135     if (    pUVM->vm.s.enmHaltMethod != VMHALTMETHOD_INVALID
    1136         &&  g_aHaltMethods[pUVM->vm.s.iHaltMethod].pfnTerm)
    1137     {
    1138         g_aHaltMethods[pUVM->vm.s.iHaltMethod].pfnTerm(pUVM);
    1139         pUVM->vm.s.enmHaltMethod = VMHALTMETHOD_INVALID;
    1140     }
    1141 
    1142 /** @todo SMP: Need rendezvous thing here, the other EMTs must not be
    1143  *        sleeping when we switch the notification method or we'll never
    1144  *        manage to wake them up properly and end up relying on timeouts... */
    1145 
    1146     /*
    1147      * Init the new one.
    1148      */
    1149     memset(&pUVM->vm.s.Halt, 0, sizeof(pUVM->vm.s.Halt));
    1150     if (g_aHaltMethods[i].pfnInit)
    1151     {
    1152         int rc = g_aHaltMethods[i].pfnInit(pUVM);
    1153         AssertRCReturn(rc, rc);
    1154     }
    1155     pUVM->vm.s.enmHaltMethod = enmHaltMethod;
    1156 
    1157     ASMAtomicWriteU32(&pUVM->vm.s.iHaltMethod, i);
    1158     return VINF_SUCCESS;
    1159 }
    1160 
     1191     * This needs to be done while the other EMTs are not sleeping or otherwise messing around.
     1192     */
     1193    return VMMR3EmtRendezvous(pVM, VMMEMTRENDEZVOUS_FLAGS_TYPE_ONCE, vmR3SetHaltMethodCallback, (void *)(uintptr_t)i);
     1194}
     1195
  • trunk/src/VBox/VMM/VMM.cpp

    r20566 r20663  
    8888#include <iprt/asm.h>
    8989#include <iprt/time.h>
     90#include <iprt/semaphore.h>
    9091#include <iprt/stream.h>
    9192#include <iprt/string.h>
     
    136137     */
    137138    pVM->vmm.s.offVM = RT_OFFSETOF(VM, vmm);
     139    pVM->vmm.s.hEvtRendezvousEnterOneByOne      = NIL_RTSEMEVENT;
     140    pVM->vmm.s.hEvtMulRendezvousEnterAllAtOnce  = NIL_RTSEMEVENTMULTI;
     141    pVM->vmm.s.hEvtMulRendezvousDone            = NIL_RTSEMEVENTMULTI;
     142    pVM->vmm.s.hEvtRendezvousDoneCaller         = NIL_RTSEMEVENT;
    138143    int rc = CFGMR3QueryU32(CFGMR3GetRoot(pVM), "YieldEMTInterval", &pVM->vmm.s.cYieldEveryMillies);
    139144    if (rc == VERR_CFGM_VALUE_NOT_FOUND)
     
    144149
    145150    /*
    146      * Initialize the VMM sync critical section.
     151     * Initialize the VMM sync critical section and semaphores.
    147152     */
    148153    rc = RTCritSectInit(&pVM->vmm.s.CritSectSync);
     154    AssertRCReturn(rc, rc);
     155    rc = RTSemEventCreate(&pVM->vmm.s.hEvtRendezvousEnterOneByOne);
     156    AssertRCReturn(rc, rc);
     157    rc = RTSemEventMultiCreate(&pVM->vmm.s.hEvtMulRendezvousEnterAllAtOnce);
     158    AssertRCReturn(rc, rc);
     159    rc = RTSemEventMultiCreate(&pVM->vmm.s.hEvtMulRendezvousDone);
     160    AssertRCReturn(rc, rc);
     161    rc = RTSemEventCreate(&pVM->vmm.s.hEvtRendezvousDoneCaller);
    149162    AssertRCReturn(rc, rc);
    150163
     
    649662
    650663    RTCritSectDelete(&pVM->vmm.s.CritSectSync);
     664    RTSemEventDestroy(pVM->vmm.s.hEvtRendezvousEnterOneByOne);
     665    pVM->vmm.s.hEvtRendezvousEnterOneByOne = NIL_RTSEMEVENT;
     666    RTSemEventMultiDestroy(pVM->vmm.s.hEvtMulRendezvousEnterAllAtOnce);
     667    pVM->vmm.s.hEvtMulRendezvousEnterAllAtOnce = NIL_RTSEMEVENTMULTI;
     668    RTSemEventMultiDestroy(pVM->vmm.s.hEvtMulRendezvousDone);
     669    pVM->vmm.s.hEvtMulRendezvousDone = NIL_RTSEMEVENTMULTI;
     670    RTSemEventDestroy(pVM->vmm.s.hEvtRendezvousDoneCaller);
     671    pVM->vmm.s.hEvtRendezvousDoneCaller = NIL_RTSEMEVENT;
    651672
    652673#ifdef VBOX_STRICT_VMM_STACK
     
    12981319 * @param   pfnHandler  Callback handler
    12991320 * @param   pvUser      User specified parameter
     1321 *
     1322 * @thread EMT
    13001323 */
    13011324VMMR3DECL(int) VMMR3AtomicExecuteHandler(PVM pVM, PFNATOMICHANDLER pfnHandler, void *pvUser)
     
    13251348    rc = pfnHandler(pVM, pvUser);
    13261349    RTCritSectLeave(&pVM->vmm.s.CritSectSync);
     1350    return rc;
     1351}
     1352
     1353
     1354/**
     1355 * Count returns and have the last non-caller EMT wake up the caller.
     1356 *
     1357 * @param   pVM                 The VM handle.
     1358 */
     1359DECL_FORCE_INLINE(void) vmmR3EmtRendezvousNonCallerReturn(PVM pVM)
     1360{
     1361    uint32_t cReturned = ASMAtomicIncU32(&pVM->vmm.s.cRendezvousEmtsReturned);
     1362    if (cReturned == pVM->cCPUs - 1U)
     1363    {
     1364        int rc = RTSemEventSignal(pVM->vmm.s.hEvtRendezvousDoneCaller);
     1365        AssertLogRelRC(rc);
     1366    }
     1367}
     1368
     1369
     1370/**
     1371 * Common worker for VMMR3EmtRendezvous and VMMR3EmtRendezvousFF.
     1372 *
     1373 * @param   pVM                 The VM handle.
     1374 * @param   pVCpu               The VMCPU structure for the calling EMT.
     1375 * @param   fIsCaller           Whether we're the VMMR3EmtRendezvous caller or
     1376 *                              not.
     1377 * @param   fFlags              The flags.
     1378 * @param   pfnRendezvous       The callback.
     1379 * @param   pvUser              The user argument for the callback.
     1380 */
     1381static void vmmR3EmtRendezvousCommon(PVM pVM, PVMCPU pVCpu, bool fIsCaller,
     1382                                     uint32_t fFlags, PFNVMMEMTRENDEZVOUS pfnRendezvous, void *pvUser)
     1383{
     1384    int rc;
     1385
     1386    /*
     1387     * Enter, the last EMT triggers the next callback phase.
     1388     */
     1389    uint32_t cEntered = ASMAtomicIncU32(&pVM->vmm.s.cRendezvousEmtsEntered);
     1390    if (cEntered != pVM->cCPUs)
     1391    {
     1392        if ((fFlags & VMMEMTRENDEZVOUS_FLAGS_TYPE_MASK) == VMMEMTRENDEZVOUS_FLAGS_TYPE_ONE_BY_ONE)
     1393        {
     1394            /* Wait for our turn. */
     1395            rc = RTSemEventWait(pVM->vmm.s.hEvtRendezvousEnterOneByOne, RT_INDEFINITE_WAIT);
     1396            AssertLogRelRC(rc);
     1397        }
     1398        else if ((fFlags & VMMEMTRENDEZVOUS_FLAGS_TYPE_MASK) == VMMEMTRENDEZVOUS_FLAGS_TYPE_ALL_AT_ONCE)
     1399        {
     1400            /* Wait for the last EMT to arrive and wake everyone up. */
     1401            rc = RTSemEventMultiWait(pVM->vmm.s.hEvtMulRendezvousEnterAllAtOnce, RT_INDEFINITE_WAIT);
     1402            AssertLogRelRC(rc);
     1403        }
     1404        else
     1405        {
     1406            Assert((fFlags & VMMEMTRENDEZVOUS_FLAGS_TYPE_MASK) == VMMEMTRENDEZVOUS_FLAGS_TYPE_ONCE);
     1407
     1408            /*
     1409             * The execute once is handled specially to optimize the code flow.
     1410             *
     1411             * The last EMT to arrive will perform the callback and the other
     1412             * EMTs will wait on the Done/DoneCaller semaphores (instead of
     1413             * the EnterOneByOne/AllAtOnce) in the meanwhile. When the callback
     1414             * returns, that EMT will initiate the normal return sequence.
     1415             */
     1416            if (!fIsCaller)
     1417            {
     1418                rc = RTSemEventMultiWait(pVM->vmm.s.hEvtMulRendezvousDone, RT_INDEFINITE_WAIT);
     1419                AssertLogRelRC(rc);
     1420
     1421                vmmR3EmtRendezvousNonCallerReturn(pVM);
     1422            }
     1423            return;
     1424        }
     1425    }
     1426    else
     1427    {
     1428        /*
     1429         * All EMTs are waiting, clear the FF and take action according to the
     1430         * execution method.
     1431         */
     1432        VM_FF_CLEAR(pVM, VM_FF_EMT_RENDEZVOUS);
     1433
     1434        if ((fFlags & VMMEMTRENDEZVOUS_FLAGS_TYPE_MASK) == VMMEMTRENDEZVOUS_FLAGS_TYPE_ALL_AT_ONCE)
     1435        {
     1436            /* Wake up everyone. */
     1437            rc = RTSemEventMultiSignal(pVM->vmm.s.hEvtMulRendezvousEnterAllAtOnce);
     1438            AssertLogRelRC(rc);
     1439        }
     1440        /* else: execute the handler on the current EMT and wake up one or more threads afterwards. */
     1441    }
     1442
     1443
     1444    /*
     1445     * Do the callback and update the status if necessary.
     1446     */
     1447    rc = pfnRendezvous(pVM, pVCpu, pvUser);
     1448    if (rc != VINF_SUCCESS)
     1449    {
     1450        int32_t i32RendezvousStatus;
     1451        do
     1452        {
     1453            i32RendezvousStatus = ASMAtomicUoReadS32(&pVM->vmm.s.i32RendezvousStatus);
     1454            if (    RT_FAILURE(i32RendezvousStatus)
     1455                ||  (   i32RendezvousStatus != VINF_SUCCESS
     1456                     && RT_SUCCESS(rc)))
     1457                break;
     1458        } while (!ASMAtomicCmpXchgS32(&pVM->vmm.s.i32RendezvousStatus, rc, i32RendezvousStatus));
     1459    }
     1460
     1461    /*
     1462     * Increment the done counter and take action depending on whether we're
     1463     * the last to finish callback execution.
     1464     */
     1465    uint32_t cDone = ASMAtomicIncU32(&pVM->vmm.s.cRendezvousEmtsDone);
     1466    if (    cDone != pVM->cCPUs
     1467        &&  (fFlags & VMMEMTRENDEZVOUS_FLAGS_TYPE_MASK) != VMMEMTRENDEZVOUS_FLAGS_TYPE_ONCE)
     1468    {
     1469        /* Signal the next EMT? */
     1470        if ((fFlags & VMMEMTRENDEZVOUS_FLAGS_TYPE_MASK) == VMMEMTRENDEZVOUS_FLAGS_TYPE_ONE_BY_ONE)
     1471        {
     1472            rc = RTSemEventSignal(pVM->vmm.s.hEvtRendezvousEnterOneByOne);
     1473            AssertLogRelRC(rc);
     1474        }
     1475
     1476        /* Wait for the rest to finish (the caller waits on hEvtRendezvousDoneCaller). */
     1477        if (!fIsCaller)
     1478        {
     1479            rc = RTSemEventMultiWait(pVM->vmm.s.hEvtMulRendezvousDone, RT_INDEFINITE_WAIT);
     1480            AssertLogRelRC(rc);
     1481        }
     1482    }
     1483    else
     1484    {
     1485        /* Callback execution is all done, tell the rest to return. */
     1486        rc = RTSemEventMultiSignal(pVM->vmm.s.hEvtMulRendezvousDone);
     1487        AssertLogRelRC(rc);
     1488    }
     1489
     1490    if (!fIsCaller)
     1491        vmmR3EmtRendezvousNonCallerReturn(pVM);
     1492}
     1493
     1494
     1495/**
     1496 * Called in response to VM_FF_EMT_RENDEZVOUS.
     1497 *
     1498 * @param   pVM         The VM handle
     1499 * @param   pVCpu       The handle of the calling EMT.
     1500 *
     1501 * @thread  EMT
     1502 */
     1503VMMR3DECL(void) VMMR3EmtRendezvousFF(PVM pVM, PVMCPU pVCpu)
     1504{
     1505    vmmR3EmtRendezvousCommon(pVM, pVCpu, false /* fIsCaller */, pVM->vmm.s.fRendezvousFlags,
     1506                             pVM->vmm.s.pfnRendezvous, pVM->vmm.s.pvRendezvousUser);
     1507}
     1508
     1509
     1510/**
     1511 * EMT rendezvous.
     1512 *
     1513 * Gathers all the EMTs and execute some code on each of them, either in a one
     1514 * by one fashion or all at once.
     1515 *
     1516 * @returns VBox status code. This will be the first error or, if all succeed,
     1517 *          the first informational status code.
     1518 * @retval  VERR_VM_THREAD_NOT_EMT if the caller is not an EMT.
     1519 *
     1520 * @param   pVM             The VM handle.
     1521 * @param   fFlags          Flags indicating execution methods. See
     1522 *                          grp_VMMR3EmtRendezvous_fFlags.
     1523 * @param   pfnRendezvous   The callback.
     1524 * @param   pvUser          User argument for the callback.
     1525 *
     1526 * @thread  EMT
     1527 */
     1528VMMR3DECL(int) VMMR3EmtRendezvous(PVM pVM, uint32_t fFlags, PFNVMMEMTRENDEZVOUS pfnRendezvous, void *pvUser)
     1529{
     1530    /*
     1531     * Validate input.
     1532     */
     1533    PVMCPU pVCpu = VMMGetCpu(pVM);
     1534    AssertReturn(pVCpu, VERR_VM_THREAD_NOT_EMT);
     1535    AssertMsg(   (fFlags & VMMEMTRENDEZVOUS_FLAGS_TYPE_MASK) != VMMEMTRENDEZVOUS_FLAGS_TYPE_INVALID
     1536              && !(fFlags & ~VMMEMTRENDEZVOUS_FLAGS_VALID_MASK), ("%#x\n", fFlags));
     1537
     1538    int rc;
     1539    if (pVM->cCPUs == 1)
     1540        /*
     1541         * Shortcut for the single EMT case.
     1542         */
     1543        rc = pfnRendezvous(pVM, pVCpu, pvUser);
     1544    else
     1545    {
     1546        /*
     1547         * Spin lock. If busy, wait for the other EMT to finish while keeping a
     1548         * lookout of the RENDEZVOUS FF.
     1549         */
     1550        while (!ASMAtomicCmpXchgU32(&pVM->vmm.s.u32RendezvousLock, 0x77778888, 0))
     1551        {
     1552            if (VM_FF_ISPENDING(pVM, VM_FF_EMT_RENDEZVOUS))
     1553                VMMR3EmtRendezvousFF(pVM, pVCpu);
     1554        }
     1555        Assert(!VM_FF_ISPENDING(pVM, VM_FF_EMT_RENDEZVOUS));
     1556
     1557        /*
     1558         * Clear the slate. This is a semaphore ping-pong orgy. :-)
     1559         */
     1560        rc = RTSemEventWait(pVM->vmm.s.hEvtRendezvousEnterOneByOne, 0);         AssertLogRelMsg(rc == VERR_TIMEOUT || rc == VINF_SUCCESS, ("%Rrc\n", rc));
     1561        rc = RTSemEventMultiReset(pVM->vmm.s.hEvtMulRendezvousEnterAllAtOnce);  AssertLogRelRC(rc);
     1562        rc = RTSemEventMultiReset(pVM->vmm.s.hEvtMulRendezvousDone);            AssertLogRelRC(rc);
     1563        rc = RTSemEventWait(pVM->vmm.s.hEvtRendezvousDoneCaller, 0);            AssertLogRelMsg(rc == VERR_TIMEOUT || rc == VINF_SUCCESS, ("%Rrc\n", rc));
     1564        ASMAtomicWriteU32(&pVM->vmm.s.cRendezvousEmtsEntered, 0);
     1565        ASMAtomicWriteU32(&pVM->vmm.s.cRendezvousEmtsDone, 0);
     1566        ASMAtomicWriteU32(&pVM->vmm.s.cRendezvousEmtsReturned, 0);
     1567        ASMAtomicWriteS32(&pVM->vmm.s.i32RendezvousStatus, VINF_SUCCESS);
     1568        ASMAtomicWritePtr((void * volatile *)&pVM->vmm.s.pfnRendezvous, (void *)(uintptr_t)pfnRendezvous);
     1569        ASMAtomicWritePtr(&pVM->vmm.s.pvRendezvousUser, pvUser);
     1570        ASMAtomicWriteU32(&pVM->vmm.s.fRendezvousFlags, fFlags);
     1571
     1572        /*
     1573         * Set the FF and poke the other EMTs.
     1574         */
     1575        VM_FF_SET(pVM, VM_FF_EMT_RENDEZVOUS);
     1576        VMR3NotifyGlobalFFU(pVM->pUVM, VMNOTIFYFF_FLAGS_POKE);
     1577
     1578        /*
     1579         * Do the same ourselves.
     1580         */
     1581        vmmR3EmtRendezvousCommon(pVM, pVCpu, true /* fIsCaller */, fFlags, pfnRendezvous, pvUser);
     1582
     1583        /*
     1584         * The caller waits for the other EMTs to be done and return before doing
     1585         * the cleanup. This makes away with wakeup / reset races we would otherwise
     1586         * risk in the multiple release event semaphore code (hEvtRendezvousDoneCaller).
     1587         */
     1588        rc = RTSemEventWait(pVM->vmm.s.hEvtRendezvousDoneCaller, RT_INDEFINITE_WAIT);
     1589        AssertLogRelRC(rc);
     1590
     1591        /*
     1592         * Get the return code and clean up a little bit.
     1593         */
     1594        rc = pVM->vmm.s.i32RendezvousStatus;
     1595        ASMAtomicWritePtr((void * volatile *)&pVM->vmm.s.pfnRendezvous, NULL);
     1596
     1597        ASMAtomicWriteU32(&pVM->vmm.s.u32RendezvousLock, 0);
     1598    }
     1599
    13271600    return rc;
    13281601}
     
    17602033    PRINT_FLAG(VM_FF_,TERMINATE);
    17612034    PRINT_FLAG(VM_FF_,RESET);
     2035    PRINT_FLAG(VM_FF_,EMT_RENDEZVOUS);
    17622036    PRINT_FLAG(VM_FF_,PGM_NEED_HANDY_PAGES);
    17632037    PRINT_FLAG(VM_FF_,PGM_NO_MEMORY);
  • trunk/src/VBox/VMM/VMMInternal.h

    r20545 r20663  
    267267     * Use for synchronizing all VCPUs
    268268     */
    269     RTCRITSECT                 CritSectSync;
     269    RTCRITSECT                  CritSectSync;
     270
     271    /** @name EMT Rendezvous
     272     * @{ */
     273    /** Semaphore to wait on upon entering for one-by-one execution. */
     274    RTSEMEVENT                  hEvtRendezvousEnterOneByOne;
     275    /** Semaphore to wait on upon entering for all-at-once execution. */
     276    RTSEMEVENTMULTI             hEvtMulRendezvousEnterAllAtOnce;
     277    /** Semaphore to wait on when done. */
     278    RTSEMEVENTMULTI             hEvtMulRendezvousDone;
     279    /** Semaphore the VMMR3EmtRendezvous caller waits on at the end. */
     280    RTSEMEVENT                  hEvtRendezvousDoneCaller;
     281    /** Callback. */
     282    R3PTRTYPE(PFNVMMEMTRENDEZVOUS) volatile pfnRendezvous;
     283    /** The user argument for the callback. */
     284    RTR3PTR volatile            pvRendezvousUser;
     285    /** Flags. */
     286    volatile uint32_t           fRendezvousFlags;
     287    /** The number of EMTs that has entered. */
     288    volatile uint32_t           cRendezvousEmtsEntered;
     289    /** The number of EMTs that has done their job. */
     290    volatile uint32_t           cRendezvousEmtsDone;
     291    /** The number of EMTs that has returned. */
     292    volatile uint32_t           cRendezvousEmtsReturned;
     293    /** The status code. */
     294    volatile int32_t            i32RendezvousStatus;
     295    /** Spin lock. */
     296    volatile uint32_t           u32RendezvousLock;
     297    /** @} */
    270298
    271299    /** Buffer for storing the standard assertion message for a ring-0 assertion.
  • trunk/src/VBox/VMM/testcase/tstVMStructGC.cpp

    r20530 r20663  
    882882    GEN_CHECK_OFF(VMM, pfnCPUMRCResumeGuest);
    883883    GEN_CHECK_OFF(VMM, pfnCPUMRCResumeGuestV86);
     884    GEN_CHECK_OFF(VMM, pRCLoggerRC);
     885    GEN_CHECK_OFF(VMM, pRCLoggerR3);
     886    GEN_CHECK_OFF(VMM, cbRCLogger);
     887    GEN_CHECK_OFF(VMM, pYieldTimer);
     888    GEN_CHECK_OFF(VMM, cYieldResumeMillies);
     889    GEN_CHECK_OFF(VMM, cYieldEveryMillies);
     890    GEN_CHECK_OFF(VMM, CritSectSync);
     891    GEN_CHECK_OFF(VMM, hEvtRendezvousEnterOneByOne);
     892    GEN_CHECK_OFF(VMM, hEvtMulRendezvousEnterAllAtOnce);
     893    GEN_CHECK_OFF(VMM, hEvtMulRendezvousDone);
     894    GEN_CHECK_OFF(VMM, hEvtRendezvousDoneCaller);
     895    GEN_CHECK_OFF(VMM, pfnRendezvous);
     896    GEN_CHECK_OFF(VMM, pvRendezvousUser);
     897    GEN_CHECK_OFF(VMM, fRendezvousFlags);
     898    GEN_CHECK_OFF(VMM, cRendezvousEmtsEntered);
     899    GEN_CHECK_OFF(VMM, cRendezvousEmtsDone);
     900    GEN_CHECK_OFF(VMM, cRendezvousEmtsReturned);
     901    GEN_CHECK_OFF(VMM, i32RendezvousStatus);
     902    GEN_CHECK_OFF(VMM, u32RendezvousLock);
     903    GEN_CHECK_OFF(VMM, szRing0AssertMsg1);
     904    GEN_CHECK_OFF(VMM, szRing0AssertMsg2);
     905    GEN_CHECK_OFF(VMM, StatRunRC);
     906    GEN_CHECK_OFF(VMM, StatRZCallPGMLock);
    884907    GEN_CHECK_OFF(VMMCPU, iLastGZRc);
    885908    GEN_CHECK_OFF(VMMCPU, pbEMTStackR3);
    886909    GEN_CHECK_OFF(VMMCPU, pbEMTStackRC);
    887910    GEN_CHECK_OFF(VMMCPU, pbEMTStackBottomRC);
    888     GEN_CHECK_OFF(VMM, pRCLoggerRC);
    889     GEN_CHECK_OFF(VMM, pRCLoggerR3);
    890911#ifdef LOG_ENABLED
    891912    GEN_CHECK_OFF(VMMCPU, pR0LoggerR0);
    892913    GEN_CHECK_OFF(VMMCPU, pR0LoggerR3);
    893914#endif
    894     GEN_CHECK_OFF(VMM, cbRCLogger);
    895     GEN_CHECK_OFF(VMM, pYieldTimer);
    896     GEN_CHECK_OFF(VMM, cYieldResumeMillies);
    897     GEN_CHECK_OFF(VMM, cYieldEveryMillies);
    898915    GEN_CHECK_OFF(VMMCPU, enmCallHostOperation);
    899916    GEN_CHECK_OFF(VMMCPU, rcCallHost);
     
    902919    GEN_CHECK_OFF(VMMCPU, CallHostR0JmpBuf.SpCheck);
    903920    GEN_CHECK_OFF(VMMCPU, CallHostR0JmpBuf.SpResume);
    904     GEN_CHECK_OFF(VMM, StatRunRC);
    905     GEN_CHECK_OFF(VMM, StatRZCallPGMLock);
    906921
    907922    GEN_CHECK_SIZE(RTPINGPONG);
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