VirtualBox

Changeset 20663 in vbox


Ignore:
Timestamp:
Jun 17, 2009 12:47:55 PM (16 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
48758
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
Files:
7 edited

Legend:

Unmodified
Added
Removed
  • trunk/include/VBox/vm.h

    r20530 r20663  
    254254#define VM_FF_TM_VIRTUAL_SYNC               RT_BIT_32(2)
    255255/** PDM Queues are pending. */
     256#define VM_FF_PDM_QUEUES                    RT_BIT_32(VM_FF_PDM_QUEUES_BIT)
     257/** The bit number for VM_FF_PDM_QUEUES. */
    256258#define VM_FF_PDM_QUEUES_BIT                3
    257 #define VM_FF_PDM_QUEUES                    RT_BIT_32(VM_FF_PDM_QUEUES_BIT)
    258259/** PDM DMA transfers are pending. */
     260#define VM_FF_PDM_DMA                       RT_BIT_32(VM_FF_PDM_DMA_BIT)
     261/** The bit number for VM_FF_PDM_DMA. */
    259262#define VM_FF_PDM_DMA_BIT                   4
    260 #define VM_FF_PDM_DMA                       RT_BIT_32(VM_FF_PDM_DMA_BIT)
    261263/** This action forces the VM to call DBGF so DBGF can service debugger
    262264 * requests in the emulation thread.
    263265 * This action flag stays asserted till DBGF clears it.*/
     266#define VM_FF_DBGF                          RT_BIT_32(VM_FF_DBGF_BIT)
     267/** The bit number for VM_FF_DBGF. */
    264268#define VM_FF_DBGF_BIT                      8
    265 #define VM_FF_DBGF                          RT_BIT_32(VM_FF_DBGF_BIT)
    266269/** This action forces the VM to service pending requests from other
    267270 * thread or requests which must be executed in another context. */
     
    270273#define VM_FF_TERMINATE                     RT_BIT_32(10)
    271274/** Reset the VM. (postponed) */
     275#define VM_FF_RESET                         RT_BIT_32(VM_FF_RESET_BIT)
     276/** The bit number for VM_FF_RESET. */
    272277#define VM_FF_RESET_BIT                     11
    273 #define VM_FF_RESET                         RT_BIT_32(VM_FF_RESET_BIT)
     278/** EMT rendezvous in VMM. */
     279#define VM_FF_EMT_RENDEZVOUS                RT_BIT_32(VM_FF_EMT_RENDEZVOUS_BIT)
     280#define VM_FF_EMT_RENDEZVOUS_BIT            12
     281
    274282/** PGM needs to allocate handy pages. */
    275283#define VM_FF_PGM_NEED_HANDY_PAGES          RT_BIT_32(18)
     
    279287#define VM_FF_PGM_NO_MEMORY                 RT_BIT_32(19)
    280288/** REM needs to be informed about handler changes. */
     289#define VM_FF_REM_HANDLER_NOTIFY            RT_BIT_32(VM_FF_REM_HANDLER_NOTIFY_BIT)
     290/** The bit number for VM_FF_REM_HANDLER_NOTIFY. */
    281291#define VM_FF_REM_HANDLER_NOTIFY_BIT        29
    282 #define VM_FF_REM_HANDLER_NOTIFY            RT_BIT_32(VM_FF_REM_HANDLER_NOTIFY_BIT)
    283292/** Suspend the VM - debug only. */
    284293#define VM_FF_DEBUG_SUSPEND                 RT_BIT_32(31)
     
    306315#define VMCPU_FF_TLB_SHOOTDOWN              RT_BIT_32(18)
    307316/** Check for pending TLB flush action. */
     317#define VMCPU_FF_TLB_FLUSH                  RT_BIT_32(VMCPU_FF_TLB_FLUSH_BIT)
     318/** The bit number for VMCPU_FF_TLB_FLUSH. */
    308319#define VMCPU_FF_TLB_FLUSH_BIT              19
    309 #define VMCPU_FF_TLB_FLUSH                  RT_BIT_32(VMCPU_FF_TLB_FLUSH_BIT)
    310320/** Check the interupt and trap gates */
    311321#define VMCPU_FF_TRPM_SYNC_IDT              RT_BIT_32(20)
     
    326336
    327337/** Externally VM forced actions. Used to quit the idle/wait loop. */
    328 #define VM_FF_EXTERNAL_SUSPENDED_MASK           (VM_FF_TERMINATE | VM_FF_DBGF | VM_FF_REQUEST)
     338#define VM_FF_EXTERNAL_SUSPENDED_MASK           (VM_FF_TERMINATE | VM_FF_DBGF | VM_FF_REQUEST | VM_FF_EMT_RENDEZVOUS)
    329339/** Externally VMCPU forced actions. Used to quit the idle/wait loop. */
    330340#define VMCPU_FF_EXTERNAL_SUSPENDED_MASK        (VMCPU_FF_REQUEST)
    331341
    332342/** Externally forced VM actions. Used to quit the idle/wait loop. */
    333 #define VM_FF_EXTERNAL_HALTED_MASK              (VM_FF_TERMINATE | VM_FF_DBGF | VM_FF_REQUEST | VM_FF_PDM_QUEUES | VM_FF_PDM_DMA)
     343#define VM_FF_EXTERNAL_HALTED_MASK              (VM_FF_TERMINATE | VM_FF_DBGF | VM_FF_REQUEST | VM_FF_PDM_QUEUES | VM_FF_PDM_DMA | VM_FF_EMT_RENDEZVOUS)
    334344/** Externally forced VMCPU actions. Used to quit the idle/wait loop. */
    335345#define VMCPU_FF_EXTERNAL_HALTED_MASK           (VMCPU_FF_INTERRUPT_APIC | VMCPU_FF_INTERRUPT_PIC | VMCPU_FF_REQUEST | VMCPU_FF_TIMER)
     
    337347/** High priority VM pre-execution actions. */
    338348#define VM_FF_HIGH_PRIORITY_PRE_MASK            (  VM_FF_TERMINATE | VM_FF_DBGF | VM_FF_TM_VIRTUAL_SYNC | VM_FF_DEBUG_SUSPEND \
    339                                                  | VM_FF_PGM_NEED_HANDY_PAGES | VM_FF_PGM_NO_MEMORY)
     349                                                 | VM_FF_PGM_NEED_HANDY_PAGES | VM_FF_PGM_NO_MEMORY | VM_FF_EMT_RENDEZVOUS)
    340350/** High priority VMCPU pre-execution actions. */
    341351#define VMCPU_FF_HIGH_PRIORITY_PRE_MASK         (  VMCPU_FF_TIMER | VMCPU_FF_INTERRUPT_APIC | VMCPU_FF_INTERRUPT_PIC | VMCPU_FF_PGM_SYNC_CR3 \
     
    355365
    356366/** Normal priority VM post-execution actions. */
    357 #define VM_FF_NORMAL_PRIORITY_POST_MASK         (VM_FF_TERMINATE | VM_FF_DBGF | VM_FF_RESET | VM_FF_PGM_NO_MEMORY)
     367#define VM_FF_NORMAL_PRIORITY_POST_MASK         (VM_FF_TERMINATE | VM_FF_DBGF | VM_FF_RESET | VM_FF_PGM_NO_MEMORY | VM_FF_EMT_RENDEZVOUS)
    358368/** Normal priority VMCPU post-execution actions. */
    359369#define VMCPU_FF_NORMAL_PRIORITY_POST_MASK      (VMCPU_FF_CSAM_SCAN_PAGE)
    360370
    361371/** Normal priority VM actions. */
    362 #define VM_FF_NORMAL_PRIORITY_MASK              (VM_FF_REQUEST | VM_FF_PDM_QUEUES | VM_FF_PDM_DMA | VM_FF_REM_HANDLER_NOTIFY)
     372#define 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)
    363373/** Normal priority VMCPU actions. */
    364374#define VMCPU_FF_NORMAL_PRIORITY_MASK           (VMCPU_FF_REQUEST)
  • trunk/include/VBox/vmm.h

    r20374 r20663  
    119119 * @param   pVM     Pointer to the shared VM structure.
    120120 * @param   pvUser  User specified argument
     121 *
     122 * @todo missing prefix.
    121123 */
    122124typedef DECLCALLBACK(int) FNATOMICHANDLER(PVM pVM, void *pvUser);
    123125/** Pointer to a FNMMATOMICHANDLER(). */
    124126typedef FNATOMICHANDLER *PFNATOMICHANDLER;
     127
     128/**
     129 * Rendezvous callback.
     130 *
     131 * @returns VBox status code.
     132 * @param   pVM         The VM handle.
     133 * @param   pVCpu       The handle of the calling virtual CPU.
     134 * @param   pvUser      The user argument.
     135 */
     136typedef DECLCALLBACK(int) FNVMMEMTRENDEZVOUS(PVM pVM, PVMCPU pVCpu, void *pvUser);
     137/** Pointer to a rendezvous callback function. */
     138typedef FNVMMEMTRENDEZVOUS *PFNVMMEMTRENDEZVOUS;
    125139
    126140
     
    178192VMMR3DECL(void)     VMMR3SendInitIpi(PVM pVM, VMCPUID idCpu);
    179193VMMR3DECL(int)      VMMR3AtomicExecuteHandler(PVM pVM, PFNATOMICHANDLER pfnHandler, void *pvUser);
     194VMMR3DECL(int)      VMMR3EmtRendezvous(PVM pVM, uint32_t fFlags, PFNVMMEMTRENDEZVOUS pfnRendezvous, void *pvUser);
     195/** @defgroup grp_VMMR3EmtRendezvous_fFlags     VMMR3EmtRendezvous flags
     196 *  @{ */
     197/** Execution type mask. */
     198#define VMMEMTRENDEZVOUS_FLAGS_TYPE_MASK        UINT32_C(0x00000003)
     199/** Invalid execution type. */
     200#define VMMEMTRENDEZVOUS_FLAGS_TYPE_INVALID     UINT32_C(0)
     201/** Let the EMTs execute the callback one by one (in no particular order). */
     202#define VMMEMTRENDEZVOUS_FLAGS_TYPE_ONE_BY_ONE  UINT32_C(1)
     203/** Let all the EMTs execute the callback at the same time. */
     204#define VMMEMTRENDEZVOUS_FLAGS_TYPE_ALL_AT_ONCE UINT32_C(2)
     205/** Only execute the callback on one EMT (no particular one). */
     206#define VMMEMTRENDEZVOUS_FLAGS_TYPE_ONCE        UINT32_C(3)
     207/** The valid flags. */
     208#define VMMEMTRENDEZVOUS_FLAGS_VALID_MASK       VMMEMTRENDEZVOUS_FLAGS_TYPE_MASK
     209/** @} */
     210VMMR3DECL(void)     VMMR3EmtRendezvousFF(PVM pVM, PVMCPU pVCpu);
    180211VMMR3DECL(int)      VMMR3ReadR0Stack(PVM pVM, VMCPUID idCpu, RTHCUINTPTR pAddress, void *pvBuf, size_t cbRead);
    181212/** @} */
  • 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.

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