- Timestamp:
- Dec 14, 2015 2:59:46 PM (9 years ago)
- Location:
- trunk/src/VBox/VMM
- Files:
-
- 2 edited
-
VMMR3/VMM.cpp (modified) (23 diffs)
-
include/VMMInternal.h (modified) (3 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/VMM/VMMR3/VMM.cpp
r58397 r59124 165 165 static DECLCALLBACK(int) vmmR3Load(PVM pVM, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass); 166 166 static DECLCALLBACK(void) vmmR3YieldEMT(PVM pVM, PTMTIMER pTimer, void *pvUser); 167 static VBOXSTRICTRC vmmR3EmtRendezvousCommon(PVM pVM, PVMCPU pVCpu, bool fIsCaller, 168 uint32_t fFlags, PFNVMMEMTRENDEZVOUS pfnRendezvous, void *pvUser); 167 169 static int vmmR3ServiceCallRing3Request(PVM pVM, PVMCPU pVCpu); 168 170 static DECLCALLBACK(void) vmmR3InfoFF(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs); … … 195 197 pVM->vmm.s.hEvtMulRendezvousDone = NIL_RTSEMEVENTMULTI; 196 198 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; 197 203 198 204 /** @cfgm{/YieldEMTInterval, uint32_t, 1, UINT32_MAX, 23, ms} … … 236 242 AssertRCReturn(rc, rc); 237 243 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); 238 252 AssertRCReturn(rc, rc); 239 253 … … 814 828 RTSemEventDestroy(pVM->vmm.s.hEvtRendezvousDoneCaller); 815 829 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; 816 838 817 839 #ifdef VBOX_STRICT_VMM_STACK … … 1534 1556 1535 1557 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 */ 1567 static 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 1536 1617 /** 1537 1618 * Count returns and have the last non-caller EMT wake up the caller. … … 1540 1621 * will be returned here, those are for the caller only. 1541 1622 * 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 */ 1628 DECL_FORCE_INLINE(VBOXSTRICTRC) vmmR3EmtRendezvousNonCallerReturn(PVM pVM, VBOXSTRICTRC rcStrict) 1629 { 1630 VBOXSTRICTRC rcStrict2 = ASMAtomicReadS32(&pVM->vmm.s.i32RendezvousStatus); 1631 1547 1632 uint32_t cReturned = ASMAtomicIncU32(&pVM->vmm.s.cRendezvousEmtsReturned); 1548 1633 if (cReturned == pVM->cCpus - 1U) … … 1552 1637 } 1553 1638 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)), 1557 1645 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; 1559 1655 } 1560 1656 … … 1575 1671 * @param pvUser The user argument for the callback. 1576 1672 */ 1577 static intvmmR3EmtRendezvousCommon(PVM pVM, PVMCPU pVCpu, bool fIsCaller,1578 uint32_t fFlags, PFNVMMEMTRENDEZVOUS pfnRendezvous, void *pvUser)1673 static VBOXSTRICTRC vmmR3EmtRendezvousCommon(PVM pVM, PVMCPU pVCpu, bool fIsCaller, 1674 uint32_t fFlags, PFNVMMEMTRENDEZVOUS pfnRendezvous, void *pvUser) 1579 1675 { 1580 1676 int rc; 1677 VBOXSTRICTRC rcStrictRecursion = VINF_SUCCESS; 1581 1678 1582 1679 /* … … 1589 1686 { 1590 1687 /* 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 } 1593 1696 } 1594 1697 else if ((fFlags & VMMEMTRENDEZVOUS_FLAGS_TYPE_MASK) == VMMEMTRENDEZVOUS_FLAGS_TYPE_ALL_AT_ONCE) … … 1597 1700 rc = RTSemEventMultiWait(pVM->vmm.s.hEvtMulRendezvousEnterAllAtOnce, RT_INDEFINITE_WAIT); 1598 1701 AssertLogRelRC(rc); 1702 Assert(!pVM->vmm.s.fRendezvousRecursion); 1599 1703 } 1600 1704 else if ( (fFlags & VMMEMTRENDEZVOUS_FLAGS_TYPE_MASK) == VMMEMTRENDEZVOUS_FLAGS_TYPE_ASCENDING … … 1602 1706 { 1603 1707 /* 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 } 1606 1716 } 1607 1717 else … … 1621 1731 rc = RTSemEventMultiWait(pVM->vmm.s.hEvtMulRendezvousDone, RT_INDEFINITE_WAIT); 1622 1732 AssertLogRelRC(rc); 1623 1624 return vmmR3EmtRendezvousNonCallerReturn(pVM); 1733 Assert(!pVM->vmm.s.fRendezvousRecursion); 1734 1735 return vmmR3EmtRendezvousNonCallerReturn(pVM, rcStrictRecursion); 1625 1736 } 1626 1737 return VINF_SUCCESS; … … 1667 1778 || RT_SUCCESS(ASMAtomicUoReadS32(&pVM->vmm.s.i32RendezvousStatus)) ) 1668 1779 { 1669 VBOXSTRICTRC rcStrict = pfnRendezvous(pVM, pVCpu, pvUser);1670 if (rcStrict != VINF_SUCCESS)1671 { 1672 AssertLogRelMsg( rcStrict <= VINF_SUCCESS1673 || (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))); 1675 1786 int32_t i32RendezvousStatus; 1676 1787 do 1677 1788 { 1678 1789 i32RendezvousStatus = ASMAtomicUoReadS32(&pVM->vmm.s.i32RendezvousStatus); 1679 if ( rcStrict == i32RendezvousStatus1790 if ( rcStrict2 == i32RendezvousStatus 1680 1791 || RT_FAILURE(i32RendezvousStatus) 1681 1792 || ( i32RendezvousStatus != VINF_SUCCESS 1682 && rcStrict > i32RendezvousStatus))1793 && rcStrict2 > i32RendezvousStatus)) 1683 1794 break; 1684 } while (!ASMAtomicCmpXchgS32(&pVM->vmm.s.i32RendezvousStatus, VBOXSTRICTRC_VAL(rcStrict ), i32RendezvousStatus));1795 } while (!ASMAtomicCmpXchgS32(&pVM->vmm.s.i32RendezvousStatus, VBOXSTRICTRC_VAL(rcStrict2), i32RendezvousStatus)); 1685 1796 } 1686 1797 } … … 1716 1827 if (!fIsCaller) 1717 1828 { 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 } 1720 1837 } 1721 1838 } … … 1728 1845 1729 1846 if (!fIsCaller) 1730 return vmmR3EmtRendezvousNonCallerReturn(pVM );1731 return VINF_SUCCESS;1847 return vmmR3EmtRendezvousNonCallerReturn(pVM, rcStrictRecursion); 1848 return rcStrictRecursion; 1732 1849 } 1733 1850 … … 1748 1865 Assert(!pVCpu->vmm.s.fInRendezvous); 1749 1866 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); 1752 1869 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 */ 1880 static 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 */ 1907 static 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; 1754 2085 } 1755 2086 … … 1764 2095 * VINF_SUCCESS, or an EM scheduling status code. 1765 2096 * 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 * 1766 2100 * @param pVM The cross context VM structure. 1767 2101 * @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. 1769 2105 * @param pfnRendezvous The callback. 1770 2106 * @param pvUser User argument for the callback. … … 1807 2143 { 1808 2144 /* 1809 * Spin lock. If busy, wait for the other EMT to finish while keeping a1810 * lookout ofthe 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. 1811 2147 */ 1812 2148 int rc; … … 1814 2150 if (RT_UNLIKELY(!ASMAtomicCmpXchgU32(&pVM->vmm.s.u32RendezvousLock, 0x77778888, 0))) 1815 2151 { 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); 1817 2162 1818 2163 while (!ASMAtomicCmpXchgU32(&pVM->vmm.s.u32RendezvousLock, 0x77778888, 0)) … … 1835 2180 1836 2181 /* 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. :-) 1838 2183 */ 1839 2184 for (VMCPUID i = 0; i < pVM->cCpus; i++) … … 1863 2208 * Do the same ourselves. 1864 2209 */ 1865 vmmR3EmtRendezvousCommon(pVM, pVCpu, true /* fIsCaller */, fFlags, pfnRendezvous, pvUser);2210 VBOXSTRICTRC rcStrict2 = vmmR3EmtRendezvousCommon(pVM, pVCpu, true /* fIsCaller */, fFlags, pfnRendezvous, pvUser); 1866 2211 1867 2212 /* … … 1870 2215 * risk in the multiple release event semaphore code (hEvtRendezvousDoneCaller). 1871 2216 */ 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 } 1874 2225 1875 2226 /* 1876 2227 * Get the return code and clean up a little bit. 1877 2228 */ 1878 int rcMy= pVM->vmm.s.i32RendezvousStatus;2229 VBOXSTRICTRC rcStrict3 = pVM->vmm.s.i32RendezvousStatus; 1879 2230 ASMAtomicWriteNullPtr((void * volatile *)&pVM->vmm.s.pfnRendezvous); 1880 2231 … … 1883 2234 1884 2235 /* 1885 * Merge rcStrict and rcMy.2236 * Merge rcStrict, rcStrict2 and rcStrict3. 1886 2237 */ 1887 2238 AssertRC(VBOXSTRICTRC_VAL(rcStrict)); 1888 if ( rcMy != VINF_SUCCESS 2239 AssertRC(VBOXSTRICTRC_VAL(rcStrict2)); 2240 if ( rcStrict2 != VINF_SUCCESS 1889 2241 && ( 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; 1892 2248 } 1893 2249 -
trunk/src/VBox/VMM/include/VMMInternal.h
r58123 r59124 266 266 /** Whether log flushing has been disabled or not. */ 267 267 bool fRCLoggerFlushingDisabled; 268 bool afAlignment [5]; /**< Alignment padding. */268 bool afAlignment1[5]; /**< Alignment padding. */ 269 269 /** @} */ 270 270 … … 296 296 /** Semaphore the VMMR3EmtRendezvous caller waits on at the end. */ 297 297 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; 298 308 /** Callback. */ 299 309 R3PTRTYPE(PFNVMMEMTRENDEZVOUS) volatile pfnRendezvous; … … 312 322 /** Spin lock. */ 313 323 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 314 333 /** @} */ 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. */ 319 335 320 336 /** Buffer for storing the standard assertion message for a ring-0 assertion.
Note:
See TracChangeset
for help on using the changeset viewer.

