VirtualBox

Changeset 59124 in vbox for trunk


Ignore:
Timestamp:
Dec 14, 2015 2:59:46 PM (9 years ago)
Author:
vboxsync
Message:

VMMR3EmtRendezvous: Added support for recursion of the ordered and unorded one-by-one rendezvous types. Not debugged yet.

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

Legend:

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

    r58397 r59124  
    165165static DECLCALLBACK(int)    vmmR3Load(PVM pVM, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass);
    166166static DECLCALLBACK(void)   vmmR3YieldEMT(PVM pVM, PTMTIMER pTimer, void *pvUser);
     167static VBOXSTRICTRC         vmmR3EmtRendezvousCommon(PVM pVM, PVMCPU pVCpu, bool fIsCaller,
     168                                                     uint32_t fFlags, PFNVMMEMTRENDEZVOUS pfnRendezvous, void *pvUser);
    167169static int                  vmmR3ServiceCallRing3Request(PVM pVM, PVMCPU pVCpu);
    168170static DECLCALLBACK(void)   vmmR3InfoFF(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs);
     
    195197    pVM->vmm.s.hEvtMulRendezvousDone            = NIL_RTSEMEVENTMULTI;
    196198    pVM->vmm.s.hEvtRendezvousDoneCaller         = NIL_RTSEMEVENT;
     199    pVM->vmm.s.hEvtMulRendezvousRecursionPush   = NIL_RTSEMEVENTMULTI;
     200    pVM->vmm.s.hEvtMulRendezvousRecursionPop    = NIL_RTSEMEVENTMULTI;
     201    pVM->vmm.s.hEvtRendezvousRecursionPushCaller = NIL_RTSEMEVENT;
     202    pVM->vmm.s.hEvtRendezvousRecursionPopCaller = NIL_RTSEMEVENT;
    197203
    198204    /** @cfgm{/YieldEMTInterval, uint32_t, 1, UINT32_MAX, 23, ms}
     
    236242    AssertRCReturn(rc, rc);
    237243    rc = RTSemEventCreate(&pVM->vmm.s.hEvtRendezvousDoneCaller);
     244    AssertRCReturn(rc, rc);
     245    rc = RTSemEventMultiCreate(&pVM->vmm.s.hEvtMulRendezvousRecursionPush);
     246    AssertRCReturn(rc, rc);
     247    rc = RTSemEventMultiCreate(&pVM->vmm.s.hEvtMulRendezvousRecursionPop);
     248    AssertRCReturn(rc, rc);
     249    rc = RTSemEventCreate(&pVM->vmm.s.hEvtRendezvousRecursionPushCaller);
     250    AssertRCReturn(rc, rc);
     251    rc = RTSemEventCreate(&pVM->vmm.s.hEvtRendezvousRecursionPopCaller);
    238252    AssertRCReturn(rc, rc);
    239253
     
    814828    RTSemEventDestroy(pVM->vmm.s.hEvtRendezvousDoneCaller);
    815829    pVM->vmm.s.hEvtRendezvousDoneCaller = NIL_RTSEMEVENT;
     830    RTSemEventMultiDestroy(pVM->vmm.s.hEvtMulRendezvousRecursionPush);
     831    pVM->vmm.s.hEvtMulRendezvousRecursionPush = NIL_RTSEMEVENTMULTI;
     832    RTSemEventMultiDestroy(pVM->vmm.s.hEvtMulRendezvousRecursionPop);
     833    pVM->vmm.s.hEvtMulRendezvousRecursionPop = NIL_RTSEMEVENTMULTI;
     834    RTSemEventDestroy(pVM->vmm.s.hEvtRendezvousRecursionPushCaller);
     835    pVM->vmm.s.hEvtRendezvousRecursionPushCaller = NIL_RTSEMEVENT;
     836    RTSemEventDestroy(pVM->vmm.s.hEvtRendezvousRecursionPopCaller);
     837    pVM->vmm.s.hEvtRendezvousRecursionPopCaller = NIL_RTSEMEVENT;
    816838
    817839#ifdef VBOX_STRICT_VMM_STACK
     
    15341556
    15351557
     1558/**
     1559 * Common recursion handler for the other EMTs.
     1560 * 
     1561 * @returns Strict VBox status code.
     1562 * @param   pVM                 The cross context VM structure.
     1563 * @param   pVCpu               The cross context virtual CPU structure of the calling EMT.
     1564 * @param   rcStrict            Current status code to be combined with the one
     1565 *                              from this recursion and returned.
     1566 */ 
     1567static VBOXSTRICTRC vmmR3EmtRendezvousCommonRecursion(PVM pVM, PVMCPU pVCpu, VBOXSTRICTRC rcStrict)
     1568{
     1569    int rc2;
     1570
     1571    /*
     1572     * We wait here while the initiator of this recursion reconfigures
     1573     * everything.  The last EMT to get in signals the initiator.
     1574     */
     1575    if (ASMAtomicIncU32(&pVM->vmm.s.cRendezvousEmtsRecursingPush) == pVM->cCpus)
     1576    {
     1577        rc2 = RTSemEventSignal(pVM->vmm.s.hEvtRendezvousRecursionPushCaller);
     1578        AssertLogRelRC(rc2);
     1579    }
     1580
     1581    rc2 = RTSemEventMultiWait(pVM->vmm.s.hEvtMulRendezvousRecursionPush, RT_INDEFINITE_WAIT);
     1582    AssertLogRelRC(rc2);
     1583
     1584    /*
     1585     * Do the normal rendezvous processing.
     1586     */
     1587    VBOXSTRICTRC rcStrict2 = vmmR3EmtRendezvousCommon(pVM, pVCpu, false /* fIsCaller */, pVM->vmm.s.fRendezvousFlags,
     1588                                                      pVM->vmm.s.pfnRendezvous, pVM->vmm.s.pvRendezvousUser);
     1589
     1590    /*
     1591     * Wait for the initiator to restore everything.
     1592     */
     1593    rc2 = RTSemEventMultiWait(pVM->vmm.s.hEvtMulRendezvousRecursionPop, RT_INDEFINITE_WAIT);
     1594    AssertLogRelRC(rc2);
     1595
     1596    /*
     1597     * Last thread out of here signals the initiator.
     1598     */
     1599    if (ASMAtomicIncU32(&pVM->vmm.s.cRendezvousEmtsRecursingPop) == pVM->cCpus)
     1600    {
     1601        rc2 = RTSemEventSignal(pVM->vmm.s.hEvtRendezvousRecursionPopCaller);
     1602        AssertLogRelRC(rc2);
     1603    }
     1604
     1605    /*
     1606     * Merge status codes and return.
     1607     */
     1608    AssertRC(VBOXSTRICTRC_VAL(rcStrict2));
     1609    if (    rcStrict2 != VINF_SUCCESS
     1610        &&  (   rcStrict == VINF_SUCCESS
     1611             || rcStrict > rcStrict2))
     1612        rcStrict = rcStrict2;
     1613    return rcStrict;
     1614}
     1615
     1616
    15361617/**
    15371618 * Count returns and have the last non-caller EMT wake up the caller.
     
    15401621 *          will be returned here, those are for the caller only.
    15411622 *
    1542  * @param   pVM                 The cross context VM structure.
    1543  */
    1544 DECL_FORCE_INLINE(int) vmmR3EmtRendezvousNonCallerReturn(PVM pVM)
    1545 {
    1546     int rcRet = ASMAtomicReadS32(&pVM->vmm.s.i32RendezvousStatus);
     1623 * @param   pVM                 The cross context VM structure.
     1624 * @param   rcStrict            The current accumulated recursive status code,
     1625 *                              to be merged with i32RendezvousStatus and
     1626 *                              returned.
     1627 */
     1628DECL_FORCE_INLINE(VBOXSTRICTRC) vmmR3EmtRendezvousNonCallerReturn(PVM pVM, VBOXSTRICTRC rcStrict)
     1629{
     1630    VBOXSTRICTRC rcStrict2 = ASMAtomicReadS32(&pVM->vmm.s.i32RendezvousStatus);
     1631
    15471632    uint32_t cReturned = ASMAtomicIncU32(&pVM->vmm.s.cRendezvousEmtsReturned);
    15481633    if (cReturned == pVM->cCpus - 1U)
     
    15521637    }
    15531638
    1554     AssertLogRelMsgReturn(   rcRet <= VINF_SUCCESS
    1555                           || (rcRet >= VINF_EM_FIRST && rcRet <= VINF_EM_LAST),
    1556                           ("%Rrc\n", rcRet),
     1639    /*
     1640     * Merge the status codes, ignoring error statuses in this code path.
     1641     */
     1642    AssertLogRelMsgReturn(   rcStrict2 <= VINF_SUCCESS
     1643                          || (rcStrict2 >= VINF_EM_FIRST && rcStrict2 <= VINF_EM_LAST),
     1644                          ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict2)),
    15571645                          VERR_IPE_UNEXPECTED_INFO_STATUS);
    1558     return RT_SUCCESS(rcRet) ? rcRet : VINF_SUCCESS;
     1646
     1647    if (RT_SUCCESS(rcStrict2))
     1648    {
     1649        if (    rcStrict2 != VINF_SUCCESS
     1650            &&  (   rcStrict == VINF_SUCCESS
     1651                 || rcStrict > rcStrict2))
     1652            rcStrict = rcStrict2;
     1653    }
     1654    return rcStrict;
    15591655}
    15601656
     
    15751671 * @param   pvUser              The user argument for the callback.
    15761672 */
    1577 static int vmmR3EmtRendezvousCommon(PVM pVM, PVMCPU pVCpu, bool fIsCaller,
    1578                                     uint32_t fFlags, PFNVMMEMTRENDEZVOUS pfnRendezvous, void *pvUser)
     1673static VBOXSTRICTRC vmmR3EmtRendezvousCommon(PVM pVM, PVMCPU pVCpu, bool fIsCaller,
     1674                                             uint32_t fFlags, PFNVMMEMTRENDEZVOUS pfnRendezvous, void *pvUser)
    15791675{
    15801676    int rc;
     1677    VBOXSTRICTRC rcStrictRecursion = VINF_SUCCESS;
    15811678
    15821679    /*
     
    15891686        {
    15901687            /* Wait for our turn. */
    1591             rc = RTSemEventWait(pVM->vmm.s.hEvtRendezvousEnterOneByOne, RT_INDEFINITE_WAIT);
    1592             AssertLogRelRC(rc);
     1688            for (;;)
     1689            {
     1690                rc = RTSemEventWait(pVM->vmm.s.hEvtRendezvousEnterOneByOne, RT_INDEFINITE_WAIT);
     1691                AssertLogRelRC(rc);
     1692                if (!pVM->vmm.s.fRendezvousRecursion)
     1693                    break;
     1694                rcStrictRecursion = vmmR3EmtRendezvousCommonRecursion(pVM, pVCpu, rcStrictRecursion);
     1695            }
    15931696        }
    15941697        else if ((fFlags & VMMEMTRENDEZVOUS_FLAGS_TYPE_MASK) == VMMEMTRENDEZVOUS_FLAGS_TYPE_ALL_AT_ONCE)
     
    15971700            rc = RTSemEventMultiWait(pVM->vmm.s.hEvtMulRendezvousEnterAllAtOnce, RT_INDEFINITE_WAIT);
    15981701            AssertLogRelRC(rc);
     1702            Assert(!pVM->vmm.s.fRendezvousRecursion);
    15991703        }
    16001704        else if (   (fFlags & VMMEMTRENDEZVOUS_FLAGS_TYPE_MASK) == VMMEMTRENDEZVOUS_FLAGS_TYPE_ASCENDING
     
    16021706        {
    16031707            /* Wait for our turn. */
    1604             rc = RTSemEventWait(pVM->vmm.s.pahEvtRendezvousEnterOrdered[pVCpu->idCpu], RT_INDEFINITE_WAIT);
    1605             AssertLogRelRC(rc);
     1708            for (;;)
     1709            {
     1710                rc = RTSemEventWait(pVM->vmm.s.pahEvtRendezvousEnterOrdered[pVCpu->idCpu], RT_INDEFINITE_WAIT);
     1711                AssertLogRelRC(rc);
     1712                if (!pVM->vmm.s.fRendezvousRecursion)
     1713                    break;
     1714                rcStrictRecursion = vmmR3EmtRendezvousCommonRecursion(pVM, pVCpu, rcStrictRecursion);
     1715            }
    16061716        }
    16071717        else
     
    16211731                rc = RTSemEventMultiWait(pVM->vmm.s.hEvtMulRendezvousDone, RT_INDEFINITE_WAIT);
    16221732                AssertLogRelRC(rc);
    1623 
    1624                 return vmmR3EmtRendezvousNonCallerReturn(pVM);
     1733                Assert(!pVM->vmm.s.fRendezvousRecursion);
     1734
     1735                return vmmR3EmtRendezvousNonCallerReturn(pVM, rcStrictRecursion);
    16251736            }
    16261737            return VINF_SUCCESS;
     
    16671778        ||  RT_SUCCESS(ASMAtomicUoReadS32(&pVM->vmm.s.i32RendezvousStatus)) )
    16681779    {
    1669         VBOXSTRICTRC rcStrict = pfnRendezvous(pVM, pVCpu, pvUser);
    1670         if (rcStrict != VINF_SUCCESS)
    1671         {
    1672             AssertLogRelMsg(   rcStrict <= VINF_SUCCESS
    1673                             || (rcStrict >= VINF_EM_FIRST && rcStrict <= VINF_EM_LAST),
    1674                             ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
     1780        VBOXSTRICTRC rcStrict2 = pfnRendezvous(pVM, pVCpu, pvUser);
     1781        if (rcStrict2 != VINF_SUCCESS)
     1782        {
     1783            AssertLogRelMsg(   rcStrict2 <= VINF_SUCCESS
     1784                            || (rcStrict2 >= VINF_EM_FIRST && rcStrict2 <= VINF_EM_LAST),
     1785                            ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict2)));
    16751786            int32_t i32RendezvousStatus;
    16761787            do
    16771788            {
    16781789                i32RendezvousStatus = ASMAtomicUoReadS32(&pVM->vmm.s.i32RendezvousStatus);
    1679                 if (    rcStrict == i32RendezvousStatus
     1790                if (    rcStrict2 == i32RendezvousStatus
    16801791                    ||  RT_FAILURE(i32RendezvousStatus)
    16811792                    ||  (   i32RendezvousStatus != VINF_SUCCESS
    1682                          && rcStrict > i32RendezvousStatus))
     1793                         && rcStrict2 > i32RendezvousStatus))
    16831794                    break;
    1684             } while (!ASMAtomicCmpXchgS32(&pVM->vmm.s.i32RendezvousStatus, VBOXSTRICTRC_VAL(rcStrict), i32RendezvousStatus));
     1795            } while (!ASMAtomicCmpXchgS32(&pVM->vmm.s.i32RendezvousStatus, VBOXSTRICTRC_VAL(rcStrict2), i32RendezvousStatus));
    16851796        }
    16861797    }
     
    17161827        if (!fIsCaller)
    17171828        {
    1718             rc = RTSemEventMultiWait(pVM->vmm.s.hEvtMulRendezvousDone, RT_INDEFINITE_WAIT);
    1719             AssertLogRelRC(rc);
     1829            for (;;)
     1830            {
     1831                rc = RTSemEventMultiWait(pVM->vmm.s.hEvtMulRendezvousDone, RT_INDEFINITE_WAIT);
     1832                AssertLogRelRC(rc);
     1833                if (!pVM->vmm.s.fRendezvousRecursion)
     1834                    break;
     1835                rcStrictRecursion = vmmR3EmtRendezvousCommonRecursion(pVM, pVCpu, rcStrictRecursion);
     1836            }
    17201837        }
    17211838    }
     
    17281845
    17291846    if (!fIsCaller)
    1730         return vmmR3EmtRendezvousNonCallerReturn(pVM);
    1731     return VINF_SUCCESS;
     1847        return vmmR3EmtRendezvousNonCallerReturn(pVM, rcStrictRecursion);
     1848    return rcStrictRecursion;
    17321849}
    17331850
     
    17481865    Assert(!pVCpu->vmm.s.fInRendezvous);
    17491866    pVCpu->vmm.s.fInRendezvous = true;
    1750     int rc = vmmR3EmtRendezvousCommon(pVM, pVCpu, false /* fIsCaller */, pVM->vmm.s.fRendezvousFlags,
    1751                                       pVM->vmm.s.pfnRendezvous, pVM->vmm.s.pvRendezvousUser);
     1867    VBOXSTRICTRC rcStrict = vmmR3EmtRendezvousCommon(pVM, pVCpu, false /* fIsCaller */, pVM->vmm.s.fRendezvousFlags,
     1868                                                     pVM->vmm.s.pfnRendezvous, pVM->vmm.s.pvRendezvousUser);
    17521869    pVCpu->vmm.s.fInRendezvous = false;
    1753     return rc;
     1870    return VBOXSTRICTRC_TODO(rcStrict);
     1871}
     1872
     1873
     1874/**
     1875 * Helper for resetting an single wakeup event sempahore.
     1876 *
     1877 * @returns VERR_TIMEOUT on success, RTSemEventWait status otherwise.
     1878 * @param   hEvt        The event semaphore to reset.
     1879 */
     1880static int vmmR3HlpResetEvent(RTSEMEVENT hEvt)
     1881{
     1882    for (uint32_t cLoops = 0; ; cLoops++)
     1883    {
     1884        int rc = RTSemEventWait(hEvt, 0 /*cMsTimeout*/);
     1885        if (rc != VINF_SUCCESS || cLoops > _4K)
     1886            return rc;
     1887    }
     1888}
     1889
     1890
     1891/**
     1892 * Worker for VMMR3EmtRendezvous that handles recursion.
     1893 *
     1894 * @returns VBox strict status code.  This will be the first error,
     1895 *          VINF_SUCCESS, or an EM scheduling status code.
     1896 *
     1897 * @param   pVM             The cross context VM structure.
     1898 * @param   pVCpu           The cross context virtual CPU structure of the
     1899 *                          calling EMT.
     1900 * @param   fFlags          Flags indicating execution methods. See
     1901 *                          grp_VMMR3EmtRendezvous_fFlags.
     1902 * @param   pfnRendezvous   The callback.
     1903 * @param   pvUser          User argument for the callback.
     1904 *
     1905 * @thread  EMT(pVCpu)
     1906 */ 
     1907static VBOXSTRICTRC vmmR3EmtRendezvousRecursive(PVM pVM, PVMCPU pVCpu, uint32_t fFlags,
     1908                                                PFNVMMEMTRENDEZVOUS pfnRendezvous, void *pvUser)
     1909{
     1910    AssertLogRelReturn(pVM->vmm.s.cRendezvousRecursions < 3, VERR_DEADLOCK);
     1911
     1912    /*
     1913     * Save the current state.
     1914     */
     1915    uint32_t const              fParentFlags    = pVM->vmm.s.fRendezvousFlags;
     1916    uint32_t const              cParentDone     = pVM->vmm.s.cRendezvousEmtsDone;
     1917    int32_t const               iParentStatus   = pVM->vmm.s.i32RendezvousStatus;
     1918    PFNVMMEMTRENDEZVOUS const   pfnParent       = pVM->vmm.s.pfnRendezvous;
     1919    void * const                pvParentUser    = pVM->vmm.s.pvRendezvousUser;
     1920
     1921    /*
     1922     * Check preconditions and save the current state.
     1923     */
     1924    AssertReturn(   (fParentFlags & VMMEMTRENDEZVOUS_FLAGS_TYPE_MASK) == VMMEMTRENDEZVOUS_FLAGS_TYPE_ASCENDING
     1925                 || (fParentFlags & VMMEMTRENDEZVOUS_FLAGS_TYPE_MASK) == VMMEMTRENDEZVOUS_FLAGS_TYPE_DESCENDING
     1926                 || (fParentFlags & VMMEMTRENDEZVOUS_FLAGS_TYPE_MASK) == VMMEMTRENDEZVOUS_FLAGS_TYPE_ONE_BY_ONE,
     1927                 VERR_INTERNAL_ERROR);
     1928    AssertReturn(pVM->vmm.s.cRendezvousEmtsEntered == pVM->cCpus, VERR_INTERNAL_ERROR_2);
     1929    AssertReturn(pVM->vmm.s.cRendezvousEmtsReturned == 0, VERR_INTERNAL_ERROR_3);
     1930
     1931    /*
     1932     * Reset the recursion prep and pop semaphores.
     1933     */
     1934    int rc = RTSemEventMultiReset(pVM->vmm.s.hEvtMulRendezvousRecursionPush);
     1935    AssertLogRelRCReturn(rc, rc);
     1936    rc = RTSemEventMultiReset(pVM->vmm.s.hEvtMulRendezvousRecursionPop);
     1937    AssertLogRelRCReturn(rc, rc);
     1938    rc = vmmR3HlpResetEvent(pVM->vmm.s.hEvtRendezvousRecursionPushCaller);
     1939    AssertLogRelMsgReturn(rc == VERR_TIMEOUT, ("%Rrc\n", rc), RT_FAILURE_NP(rc) ? rc : VERR_IPE_UNEXPECTED_INFO_STATUS);
     1940    rc = vmmR3HlpResetEvent(pVM->vmm.s.hEvtRendezvousRecursionPopCaller);
     1941    AssertLogRelMsgReturn(rc == VERR_TIMEOUT, ("%Rrc\n", rc), RT_FAILURE_NP(rc) ? rc : VERR_IPE_UNEXPECTED_INFO_STATUS);
     1942
     1943    /*
     1944     * Usher the other thread into the recursion routine.
     1945     */
     1946    ASMAtomicWriteU32(&pVM->vmm.s.cRendezvousEmtsRecursingPush, 0);
     1947    ASMAtomicWriteU32(&pVM->vmm.s.cRendezvousEmtsRecursingPop, 0);
     1948    ASMAtomicWriteBool(&pVM->vmm.s.fRendezvousRecursion, true);
     1949
     1950    uint32_t cLeft = pVM->cCpus - (cParentDone + 1U);
     1951    if ((fFlags & VMMEMTRENDEZVOUS_FLAGS_TYPE_MASK) == VMMEMTRENDEZVOUS_FLAGS_TYPE_ONE_BY_ONE)
     1952        while (cLeft-- > 0)
     1953        {
     1954            rc = RTSemEventSignal(pVM->vmm.s.hEvtRendezvousEnterOneByOne);
     1955            AssertLogRelRC(rc);
     1956        }
     1957    else if ((fFlags & VMMEMTRENDEZVOUS_FLAGS_TYPE_MASK) == VMMEMTRENDEZVOUS_FLAGS_TYPE_ASCENDING)
     1958    {
     1959        Assert(cLeft == pVM->cCpus - (pVCpu->idCpu + 1U));
     1960        for (VMCPUID iCpu = pVCpu->idCpu + 1U; iCpu < pVM->cCpus; iCpu++)
     1961        {
     1962            rc = RTSemEventSignal(pVM->vmm.s.pahEvtRendezvousEnterOrdered[iCpu]);
     1963            AssertLogRelRC(rc);
     1964        }
     1965    }
     1966    else if ((fFlags & VMMEMTRENDEZVOUS_FLAGS_TYPE_MASK) == VMMEMTRENDEZVOUS_FLAGS_TYPE_DESCENDING)
     1967    {
     1968        Assert(cLeft == pVCpu->idCpu);
     1969        for (VMCPUID iCpu = pVCpu->idCpu; iCpu > pVM->cCpus; iCpu--)
     1970        {
     1971            rc = RTSemEventSignal(pVM->vmm.s.pahEvtRendezvousEnterOrdered[iCpu - 1U]);
     1972            AssertLogRelRC(rc);
     1973        }
     1974    }
     1975    else
     1976        AssertLogRelFailedReturn(VERR_INTERNAL_ERROR_4);
     1977
     1978    rc = RTSemEventMultiSignal(pVM->vmm.s.hEvtMulRendezvousDone);
     1979    AssertLogRelRC(rc);
     1980    rc = RTSemEventSignal(pVM->vmm.s.hEvtRendezvousDoneCaller);
     1981    AssertLogRelRC(rc);
     1982
     1983
     1984    /*
     1985     * Wait for the EMTs to wake up and get out of the parent rendezvous code.
     1986     */
     1987    if (ASMAtomicIncU32(&pVM->vmm.s.cRendezvousEmtsRecursingPush) != pVM->cCpus)
     1988    {
     1989        rc = RTSemEventWait(pVM->vmm.s.hEvtRendezvousRecursionPushCaller, RT_INDEFINITE_WAIT);
     1990        AssertLogRelRC(rc);
     1991    }
     1992
     1993    ASMAtomicWriteBool(&pVM->vmm.s.fRendezvousRecursion, false);
     1994
     1995    /*
     1996     * Clear the slate and setup the new rendezvous.
     1997     */
     1998    for (VMCPUID i = 0; i < pVM->cCpus; i++)
     1999    {
     2000        rc = vmmR3HlpResetEvent(pVM->vmm.s.pahEvtRendezvousEnterOrdered[i]);
     2001        AssertLogRelMsg(rc == VERR_TIMEOUT, ("%Rrc\n", rc));
     2002    }
     2003    rc = vmmR3HlpResetEvent(pVM->vmm.s.hEvtRendezvousEnterOneByOne);        AssertLogRelMsg(rc == VERR_TIMEOUT, ("%Rrc\n", rc));
     2004    rc = RTSemEventMultiReset(pVM->vmm.s.hEvtMulRendezvousEnterAllAtOnce);  AssertLogRelRC(rc);
     2005    rc = RTSemEventMultiReset(pVM->vmm.s.hEvtMulRendezvousDone);            AssertLogRelRC(rc);
     2006    rc = vmmR3HlpResetEvent(pVM->vmm.s.hEvtRendezvousDoneCaller);           AssertLogRelMsg(rc == VERR_TIMEOUT, ("%Rrc\n", rc));
     2007
     2008    ASMAtomicWriteU32(&pVM->vmm.s.cRendezvousEmtsEntered, 0);
     2009    ASMAtomicWriteU32(&pVM->vmm.s.cRendezvousEmtsDone, 0);
     2010    ASMAtomicWriteU32(&pVM->vmm.s.cRendezvousEmtsReturned, 0);
     2011    ASMAtomicWriteS32(&pVM->vmm.s.i32RendezvousStatus, VINF_SUCCESS);
     2012    ASMAtomicWritePtr((void * volatile *)&pVM->vmm.s.pfnRendezvous, (void *)(uintptr_t)pfnRendezvous);
     2013    ASMAtomicWritePtr(&pVM->vmm.s.pvRendezvousUser, pvUser);
     2014    ASMAtomicWriteU32(&pVM->vmm.s.fRendezvousFlags, fFlags);
     2015    ASMAtomicIncU32(&pVM->vmm.s.cRendezvousRecursions);
     2016
     2017    /*
     2018     * We're ready to go now, do normal rendezvous processing.
     2019     */
     2020    rc = RTSemEventMultiSignal(pVM->vmm.s.hEvtMulRendezvousRecursionPush);
     2021    AssertLogRelRC(rc);
     2022
     2023    VBOXSTRICTRC rcStrict = vmmR3EmtRendezvousCommon(pVM, pVCpu, true /*fIsCaller*/, fFlags, pfnRendezvous, pvUser);
     2024
     2025    /*
     2026     * The caller waits for the other EMTs to be done, return and waiting on the
     2027     * pop semaphore.
     2028     */
     2029    for (;;)
     2030    {
     2031        rc = RTSemEventWait(pVM->vmm.s.hEvtRendezvousDoneCaller, RT_INDEFINITE_WAIT);
     2032        AssertLogRelRC(rc);
     2033        if (!pVM->vmm.s.fRendezvousRecursion)
     2034            break;
     2035        rcStrict = vmmR3EmtRendezvousCommonRecursion(pVM, pVCpu, rcStrict);
     2036    }
     2037
     2038    /*
     2039     * Get the return code and merge it with the above recursion status.
     2040     */
     2041    VBOXSTRICTRC rcStrict2 = pVM->vmm.s.i32RendezvousStatus;
     2042    if (    rcStrict2 != VINF_SUCCESS
     2043        &&  (   rcStrict == VINF_SUCCESS
     2044             || rcStrict > rcStrict2))
     2045        rcStrict = rcStrict2;
     2046
     2047    /*
     2048     * Restore the parent rendezvous state.
     2049     */
     2050    for (VMCPUID i = 0; i < pVM->cCpus; i++)
     2051    {
     2052        rc = vmmR3HlpResetEvent(pVM->vmm.s.pahEvtRendezvousEnterOrdered[i]);
     2053        AssertLogRelMsg(rc == VERR_TIMEOUT, ("%Rrc\n", rc));
     2054    }
     2055    rc = vmmR3HlpResetEvent(pVM->vmm.s.hEvtRendezvousEnterOneByOne);        AssertLogRelMsg(rc == VERR_TIMEOUT, ("%Rrc\n", rc));
     2056    rc = RTSemEventMultiReset(pVM->vmm.s.hEvtMulRendezvousEnterAllAtOnce);  AssertLogRelRC(rc);
     2057    rc = RTSemEventMultiReset(pVM->vmm.s.hEvtMulRendezvousDone);            AssertLogRelRC(rc);
     2058    rc = vmmR3HlpResetEvent(pVM->vmm.s.hEvtRendezvousDoneCaller);           AssertLogRelMsg(rc == VERR_TIMEOUT, ("%Rrc\n", rc));
     2059
     2060    ASMAtomicWriteU32(&pVM->vmm.s.cRendezvousEmtsEntered,   pVM->cCpus);
     2061    ASMAtomicWriteU32(&pVM->vmm.s.cRendezvousEmtsReturned,  0);
     2062    ASMAtomicWriteU32(&pVM->vmm.s.cRendezvousEmtsDone,      cParentDone);
     2063    ASMAtomicWriteS32(&pVM->vmm.s.i32RendezvousStatus,      iParentStatus);
     2064    ASMAtomicWriteU32(&pVM->vmm.s.fRendezvousFlags,         fParentFlags);
     2065    ASMAtomicWritePtr(&pVM->vmm.s.pvRendezvousUser,         pvParentUser);
     2066    ASMAtomicWritePtr((void * volatile *)&pVM->vmm.s.pfnRendezvous, (void *)(uintptr_t)pfnParent);
     2067
     2068    /*
     2069     * Usher the other EMTs back to their parent recursion routine, waiting
     2070     * for them to all get there before we return (makes sure they've been
     2071     * scheduled and are in position again - paranoia, shouldn't be needed).
     2072     */
     2073    rc = RTSemEventMultiSignal(pVM->vmm.s.hEvtMulRendezvousRecursionPush);
     2074    AssertLogRelRC(rc);
     2075
     2076    if (ASMAtomicIncU32(&pVM->vmm.s.cRendezvousEmtsRecursingPop) != pVM->cCpus)
     2077    {
     2078        rc = RTSemEventWait(pVM->vmm.s.hEvtRendezvousRecursionPopCaller, RT_INDEFINITE_WAIT);
     2079        AssertLogRelRC(rc);
     2080    }
     2081
     2082    ASMAtomicDecU32(&pVM->vmm.s.cRendezvousRecursions);
     2083
     2084    return rcStrict;
    17542085}
    17552086
     
    17642095 *          VINF_SUCCESS, or an EM scheduling status code.
    17652096 *
     2097 * @retval  VERR_DEADLOCK if recursion is attempted using a rendezvous type that
     2098 *          doesn't support it or if the recursion is too deep.
     2099 *
    17662100 * @param   pVM             The cross context VM structure.
    17672101 * @param   fFlags          Flags indicating execution methods. See
    1768  *                          grp_VMMR3EmtRendezvous_fFlags.
     2102 *                          grp_VMMR3EmtRendezvous_fFlags.  The one-by-one,
     2103 *                          descending and ascending rendezvous types support
     2104 *                          recursion.
    17692105 * @param   pfnRendezvous   The callback.
    17702106 * @param   pvUser          User argument for the callback.
     
    18072143    {
    18082144        /*
    1809          * Spin lock. If busy, wait for the other EMT to finish while keeping a
    1810          * lookout of the RENDEZVOUS FF.
     2145         * Spin lock. If busy, check for recursion, if not recursing wait for
     2146         * the other EMT to finish while keeping a lookout for the RENDEZVOUS FF.
    18112147         */
    18122148        int rc;
     
    18142150        if (RT_UNLIKELY(!ASMAtomicCmpXchgU32(&pVM->vmm.s.u32RendezvousLock, 0x77778888, 0)))
    18152151        {
    1816             AssertLogRelReturn(!pVCpu->vmm.s.fInRendezvous, VERR_DEADLOCK);
     2152            /* Allow recursion in some cases. */
     2153            if (   pVCpu->vmm.s.fInRendezvous
     2154                && (   (pVM->vmm.s.fRendezvousFlags & VMMEMTRENDEZVOUS_FLAGS_TYPE_MASK) == VMMEMTRENDEZVOUS_FLAGS_TYPE_ASCENDING
     2155                    || (pVM->vmm.s.fRendezvousFlags & VMMEMTRENDEZVOUS_FLAGS_TYPE_MASK) == VMMEMTRENDEZVOUS_FLAGS_TYPE_DESCENDING
     2156                    || (pVM->vmm.s.fRendezvousFlags & VMMEMTRENDEZVOUS_FLAGS_TYPE_MASK) == VMMEMTRENDEZVOUS_FLAGS_TYPE_ONE_BY_ONE
     2157                       ))
     2158                return VBOXSTRICTRC_TODO(vmmR3EmtRendezvousRecursive(pVM, pVCpu, fFlags, pfnRendezvous, pvUser));
     2159
     2160            AssertLogRelMsgReturn(!pVCpu->vmm.s.fInRendezvous, ("fRendezvousFlags=%#x\n", pVM->vmm.s.fRendezvousFlags),
     2161                                  VERR_DEADLOCK);
    18172162
    18182163            while (!ASMAtomicCmpXchgU32(&pVM->vmm.s.u32RendezvousLock, 0x77778888, 0))
     
    18352180
    18362181        /*
    1837          * Clear the slate. This is a semaphore ping-pong orgy. :-)
     2182         * Clear the slate and setup the rendezvous. This is a semaphore ping-pong orgy. :-)
    18382183         */
    18392184        for (VMCPUID i = 0; i < pVM->cCpus; i++)
     
    18632208         * Do the same ourselves.
    18642209         */
    1865         vmmR3EmtRendezvousCommon(pVM, pVCpu, true /* fIsCaller */, fFlags, pfnRendezvous, pvUser);
     2210        VBOXSTRICTRC rcStrict2 = vmmR3EmtRendezvousCommon(pVM, pVCpu, true /* fIsCaller */, fFlags, pfnRendezvous, pvUser);
    18662211
    18672212        /*
     
    18702215         * risk in the multiple release event semaphore code (hEvtRendezvousDoneCaller).
    18712216         */
    1872         rc = RTSemEventWait(pVM->vmm.s.hEvtRendezvousDoneCaller, RT_INDEFINITE_WAIT);
    1873         AssertLogRelRC(rc);
     2217        for (;;)
     2218        {
     2219            rc = RTSemEventWait(pVM->vmm.s.hEvtRendezvousDoneCaller, RT_INDEFINITE_WAIT);
     2220            AssertLogRelRC(rc);
     2221            if (!pVM->vmm.s.fRendezvousRecursion)
     2222                break;
     2223            rcStrict2 = vmmR3EmtRendezvousCommonRecursion(pVM, pVCpu, rcStrict2);
     2224        }
    18742225
    18752226        /*
    18762227         * Get the return code and clean up a little bit.
    18772228         */
    1878         int rcMy = pVM->vmm.s.i32RendezvousStatus;
     2229        VBOXSTRICTRC rcStrict3 = pVM->vmm.s.i32RendezvousStatus;
    18792230        ASMAtomicWriteNullPtr((void * volatile *)&pVM->vmm.s.pfnRendezvous);
    18802231
     
    18832234
    18842235        /*
    1885          * Merge rcStrict and rcMy.
     2236         * Merge rcStrict, rcStrict2 and rcStrict3.
    18862237         */
    18872238        AssertRC(VBOXSTRICTRC_VAL(rcStrict));
    1888         if (    rcMy != VINF_SUCCESS
     2239        AssertRC(VBOXSTRICTRC_VAL(rcStrict2));
     2240        if (    rcStrict2 != VINF_SUCCESS
    18892241            &&  (   rcStrict == VINF_SUCCESS
    1890                  || rcStrict > rcMy))
    1891             rcStrict = rcMy;
     2242                 || rcStrict > rcStrict2))
     2243            rcStrict = rcStrict2;
     2244        if (    rcStrict3 != VINF_SUCCESS
     2245            &&  (   rcStrict == VINF_SUCCESS
     2246                 || rcStrict > rcStrict3))
     2247            rcStrict = rcStrict3;
    18922248    }
    18932249
  • trunk/src/VBox/VMM/include/VMMInternal.h

    r58123 r59124  
    266266    /** Whether log flushing has been disabled or not. */
    267267    bool                        fRCLoggerFlushingDisabled;
    268     bool                        afAlignment[5]; /**< Alignment padding. */
     268    bool                        afAlignment1[5]; /**< Alignment padding. */
    269269    /** @} */
    270270
     
    296296    /** Semaphore the VMMR3EmtRendezvous caller waits on at the end. */
    297297    RTSEMEVENT                  hEvtRendezvousDoneCaller;
     298    /** Semaphore to wait on upon recursing. */
     299    RTSEMEVENTMULTI             hEvtMulRendezvousRecursionPush;
     300    /** Semaphore to wait on after done with recursion (caller restoring state). */
     301    RTSEMEVENTMULTI             hEvtMulRendezvousRecursionPop;
     302    /** Semaphore the initiator waits on while the EMTs are getting into position
     303     *  on hEvtMulRendezvousRecursionPush. */
     304    RTSEMEVENT                  hEvtRendezvousRecursionPushCaller;
     305    /** Semaphore the initiator waits on while the EMTs sitting on
     306     *  hEvtMulRendezvousRecursionPop wakes up and leave. */
     307    RTSEMEVENT                  hEvtRendezvousRecursionPopCaller;
    298308    /** Callback. */
    299309    R3PTRTYPE(PFNVMMEMTRENDEZVOUS) volatile pfnRendezvous;
     
    312322    /** Spin lock. */
    313323    volatile uint32_t           u32RendezvousLock;
     324    /** The recursion depth. */
     325    volatile uint32_t           cRendezvousRecursions;
     326    /** The number of EMTs that have entered the recursion routine. */
     327    volatile uint32_t           cRendezvousEmtsRecursingPush;
     328    /** The number of EMTs that have leaft the recursion routine. */
     329    volatile uint32_t           cRendezvousEmtsRecursingPop;
     330    /** Triggers rendezvous recursion in the other threads. */
     331    volatile bool               fRendezvousRecursion;
     332
    314333    /** @} */
    315 
    316 #if HC_ARCH_BITS == 32
    317     uint32_t                    u32Alignment; /**< Alignment padding. */
    318 #endif
     334    bool                        afAlignment2[HC_ARCH_BITS == 32 ? 7 : 3]; /**< Alignment padding. */
    319335
    320336    /** Buffer for storing the standard assertion message for a ring-0 assertion.
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