@@ -1635,200 +1635,203 @@ int ThreadWaitForEvents(int nEvents, CThreadEvent* const* pEvents, bool bWaitAll
16351635 }
16361636 ThreadPause ();
16371637 }
1638- // Second optimistic case: we can do an initial check to minimize contention
1639- if (!bRet && lPredSignaledAnyCheck ())
1638+ if (!bRet)
16401639 {
1641- // Check handles auto reset
1642- bRet = true ;
1643- }
1644- else if (!bRet)
1645- {
1646- // Lock all at the same time, to prevent race conditions.
1647- // Before, this was implemented by locking and checking for each one after the other, which caused a race condition.
1648- switch (nEvents)
1649- {
1650- case 2 :
1651- {
1652- CExtendedScopedLock<std::mutex, std::mutex> lock (pEvents[0 ]->m_Mutex , pEvents[1 ]->m_Mutex );
1653- // If we're already signaled, skip adding listeners
1654- if (lPredSignaledAny ())
1655- {
1656- bRet = true ;
1657- }
1658- else if (timeout != 0 )
1659- {
1660- std::shared_ptr<std::condition_variable_any> condition = std::make_shared<std::condition_variable_any>();
1661- for (int i = 0 ; i < nEvents; i++)
1662- {
1663- pEvents[i]->AddListenerNoLock (condition);
1664- }
1665-
1666- if (timeout == TT_INFINITE)
1667- {
1668- condition->wait (lock, lPredSignaledAny);
1669- bRet = true ;
1670- }
1671- else
1672- {
1673- bRet = condition->wait_for (lock, std::chrono::milliseconds (timeout), lPredSignaledAny);
1674- }
1675-
1676- // Clear out listeners
1677- for (int i = 0 ; i < nEvents; i++)
1678- {
1679- pEvents[i]->RemoveListenerNoLock (condition);
1680- }
1681- condition.reset ();
1682- }
1683-
1684- // Auto reset, since this function is a wait too!
1685- if (bRet)
1686- {
1687- if (pEvents[iEventIndex]->m_bAutoReset )
1688- {
1689- pEvents[iEventIndex]->m_bSignaled = false ;
1690- }
1691- }
1692- break ;
1693- }
1694- case 3 :
1695- {
1696- CExtendedScopedLock<std::mutex, std::mutex, std::mutex> lock (pEvents[0 ]->m_Mutex , pEvents[1 ]->m_Mutex , pEvents[2 ]->m_Mutex );
1697- // If we're already signaled, skip adding listeners
1698- if (lPredSignaledAny ())
1699- {
1700- bRet = true ;
1701- }
1702- else if (timeout != 0 )
1703- {
1704- std::shared_ptr<std::condition_variable_any> condition = std::make_shared<std::condition_variable_any>();
1705- for (int i = 0 ; i < nEvents; i++)
1706- {
1707- pEvents[i]->AddListenerNoLock (condition);
1708- }
1709-
1710- if (timeout == TT_INFINITE)
1711- {
1712- condition->wait (lock, lPredSignaledAny);
1713- bRet = true ;
1714- }
1715- else
1716- {
1717- bRet = condition->wait_for (lock, std::chrono::milliseconds (timeout), lPredSignaledAny);
1718- }
1719-
1720- // Clear out listeners
1721- for (int i = 0 ; i < nEvents; i++)
1722- {
1723- pEvents[i]->RemoveListenerNoLock (condition);
1724- }
1725- condition.reset ();
1726- }
1727-
1728- // Auto reset, since this function is a wait too!
1729- if (bRet)
1730- {
1731- if (pEvents[iEventIndex]->m_bAutoReset )
1732- {
1733- pEvents[iEventIndex]->m_bSignaled = false ;
1734- }
1735- }
1736- break ;
1737- }
1738- case 4 :
1739- {
1740- CExtendedScopedLock<std::mutex, std::mutex, std::mutex, std::mutex> lock (pEvents[0 ]->m_Mutex , pEvents[1 ]->m_Mutex , pEvents[2 ]->m_Mutex , pEvents[3 ]->m_Mutex );
1741- // If we're already signaled, skip adding listeners
1742- if (lPredSignaledAny ())
1743- {
1744- bRet = true ;
1745- }
1746- else if (timeout != 0 )
1747- {
1748- std::shared_ptr<std::condition_variable_any> condition = std::make_shared<std::condition_variable_any>();
1749- for (int i = 0 ; i < nEvents; i++)
1750- {
1751- pEvents[i]->AddListenerNoLock (condition);
1752- }
1753-
1754- if (timeout == TT_INFINITE)
1755- {
1756- condition->wait (lock, lPredSignaledAny);
1757- bRet = true ;
1758- }
1759- else
1760- {
1761- bRet = condition->wait_for (lock, std::chrono::milliseconds (timeout), lPredSignaledAny);
1762- }
1763-
1764- // Clear out listeners
1765- for (int i = 0 ; i < nEvents; i++)
1766- {
1767- pEvents[i]->RemoveListenerNoLock (condition);
1768- }
1769- condition.reset ();
1770- }
1771-
1772- // Auto reset, since this function is a wait too!
1773- if (bRet)
1774- {
1775- if (pEvents[iEventIndex]->m_bAutoReset )
1776- {
1777- pEvents[iEventIndex]->m_bSignaled = false ;
1778- }
1779- }
1780- break ;
1781- }
1782- case 5 :
1783- {
1784- CExtendedScopedLock<std::mutex, std::mutex, std::mutex, std::mutex, std::mutex> lock (pEvents[0 ]->m_Mutex , pEvents[1 ]->m_Mutex , pEvents[2 ]->m_Mutex , pEvents[3 ]->m_Mutex , pEvents[4 ]->m_Mutex );
1785- // If we're already signaled, skip adding listeners
1786- if (lPredSignaledAny ())
1787- {
1788- bRet = true ;
1789- }
1790- else if (timeout != 0 )
1791- {
1792- std::shared_ptr<std::condition_variable_any> condition = std::make_shared<std::condition_variable_any>();
1793- for (int i = 0 ; i < nEvents; i++)
1794- {
1795- pEvents[i]->AddListenerNoLock (condition);
1796- }
1797-
1798- if (timeout == TT_INFINITE)
1799- {
1800- condition->wait (lock, lPredSignaledAny);
1801- bRet = true ;
1802- }
1803- else
1804- {
1805- bRet = condition->wait_for (lock, std::chrono::milliseconds (timeout), lPredSignaledAny);
1806- }
1807-
1808- // Clear out listeners
1809- for (int i = 0 ; i < nEvents; i++)
1810- {
1811- pEvents[i]->RemoveListenerNoLock (condition);
1812- }
1813- condition.reset ();
1814- }
1815-
1816- // Auto reset, since this function is a wait too!
1817- if (bRet)
1818- {
1819- if (pEvents[iEventIndex]->m_bAutoReset )
1820- {
1821- pEvents[iEventIndex]->m_bSignaled = false ;
1822- }
1823- }
1824- break ;
1825- }
1826- default :
1827- {
1828- Assert (0 );
1829- break ;
1830- }
1831- }
1640+ // Second optimistic case: we can do an initial check to minimize contention
1641+ if (lPredSignaledAnyCheck ())
1642+ {
1643+ // Check handles auto reset
1644+ bRet = true ;
1645+ }
1646+ else
1647+ {
1648+ // Lock all at the same time, to prevent race conditions.
1649+ // Before, this was implemented by locking and checking for each one after the other, which caused a race condition.
1650+ switch (nEvents)
1651+ {
1652+ case 2 :
1653+ {
1654+ CExtendedScopedLock<std::mutex, std::mutex> lock (pEvents[0 ]->m_Mutex , pEvents[1 ]->m_Mutex );
1655+ // If we're already signaled, skip adding listeners
1656+ if (lPredSignaledAny ())
1657+ {
1658+ bRet = true ;
1659+ }
1660+ else if (timeout != 0 )
1661+ {
1662+ std::shared_ptr<std::condition_variable_any> condition = std::make_shared<std::condition_variable_any>();
1663+ for (int i = 0 ; i < nEvents; i++)
1664+ {
1665+ pEvents[i]->AddListenerNoLock (condition);
1666+ }
1667+
1668+ if (timeout == TT_INFINITE)
1669+ {
1670+ condition->wait (lock, lPredSignaledAny);
1671+ bRet = true ;
1672+ }
1673+ else
1674+ {
1675+ bRet = condition->wait_for (lock, std::chrono::milliseconds (timeout), lPredSignaledAny);
1676+ }
1677+
1678+ // Clear out listeners
1679+ for (int i = 0 ; i < nEvents; i++)
1680+ {
1681+ pEvents[i]->RemoveListenerNoLock (condition);
1682+ }
1683+ condition.reset ();
1684+ }
1685+
1686+ // Auto reset, since this function is a wait too!
1687+ if (bRet)
1688+ {
1689+ if (pEvents[iEventIndex]->m_bAutoReset )
1690+ {
1691+ pEvents[iEventIndex]->m_bSignaled = false ;
1692+ }
1693+ }
1694+ break ;
1695+ }
1696+ case 3 :
1697+ {
1698+ CExtendedScopedLock<std::mutex, std::mutex, std::mutex> lock (pEvents[0 ]->m_Mutex , pEvents[1 ]->m_Mutex , pEvents[2 ]->m_Mutex );
1699+ // If we're already signaled, skip adding listeners
1700+ if (lPredSignaledAny ())
1701+ {
1702+ bRet = true ;
1703+ }
1704+ else if (timeout != 0 )
1705+ {
1706+ std::shared_ptr<std::condition_variable_any> condition = std::make_shared<std::condition_variable_any>();
1707+ for (int i = 0 ; i < nEvents; i++)
1708+ {
1709+ pEvents[i]->AddListenerNoLock (condition);
1710+ }
1711+
1712+ if (timeout == TT_INFINITE)
1713+ {
1714+ condition->wait (lock, lPredSignaledAny);
1715+ bRet = true ;
1716+ }
1717+ else
1718+ {
1719+ bRet = condition->wait_for (lock, std::chrono::milliseconds (timeout), lPredSignaledAny);
1720+ }
1721+
1722+ // Clear out listeners
1723+ for (int i = 0 ; i < nEvents; i++)
1724+ {
1725+ pEvents[i]->RemoveListenerNoLock (condition);
1726+ }
1727+ condition.reset ();
1728+ }
1729+
1730+ // Auto reset, since this function is a wait too!
1731+ if (bRet)
1732+ {
1733+ if (pEvents[iEventIndex]->m_bAutoReset )
1734+ {
1735+ pEvents[iEventIndex]->m_bSignaled = false ;
1736+ }
1737+ }
1738+ break ;
1739+ }
1740+ case 4 :
1741+ {
1742+ CExtendedScopedLock<std::mutex, std::mutex, std::mutex, std::mutex> lock (pEvents[0 ]->m_Mutex , pEvents[1 ]->m_Mutex , pEvents[2 ]->m_Mutex , pEvents[3 ]->m_Mutex );
1743+ // If we're already signaled, skip adding listeners
1744+ if (lPredSignaledAny ())
1745+ {
1746+ bRet = true ;
1747+ }
1748+ else if (timeout != 0 )
1749+ {
1750+ std::shared_ptr<std::condition_variable_any> condition = std::make_shared<std::condition_variable_any>();
1751+ for (int i = 0 ; i < nEvents; i++)
1752+ {
1753+ pEvents[i]->AddListenerNoLock (condition);
1754+ }
1755+
1756+ if (timeout == TT_INFINITE)
1757+ {
1758+ condition->wait (lock, lPredSignaledAny);
1759+ bRet = true ;
1760+ }
1761+ else
1762+ {
1763+ bRet = condition->wait_for (lock, std::chrono::milliseconds (timeout), lPredSignaledAny);
1764+ }
1765+
1766+ // Clear out listeners
1767+ for (int i = 0 ; i < nEvents; i++)
1768+ {
1769+ pEvents[i]->RemoveListenerNoLock (condition);
1770+ }
1771+ condition.reset ();
1772+ }
1773+
1774+ // Auto reset, since this function is a wait too!
1775+ if (bRet)
1776+ {
1777+ if (pEvents[iEventIndex]->m_bAutoReset )
1778+ {
1779+ pEvents[iEventIndex]->m_bSignaled = false ;
1780+ }
1781+ }
1782+ break ;
1783+ }
1784+ case 5 :
1785+ {
1786+ CExtendedScopedLock<std::mutex, std::mutex, std::mutex, std::mutex, std::mutex> lock (pEvents[0 ]->m_Mutex , pEvents[1 ]->m_Mutex , pEvents[2 ]->m_Mutex , pEvents[3 ]->m_Mutex , pEvents[4 ]->m_Mutex );
1787+ // If we're already signaled, skip adding listeners
1788+ if (lPredSignaledAny ())
1789+ {
1790+ bRet = true ;
1791+ }
1792+ else if (timeout != 0 )
1793+ {
1794+ std::shared_ptr<std::condition_variable_any> condition = std::make_shared<std::condition_variable_any>();
1795+ for (int i = 0 ; i < nEvents; i++)
1796+ {
1797+ pEvents[i]->AddListenerNoLock (condition);
1798+ }
1799+
1800+ if (timeout == TT_INFINITE)
1801+ {
1802+ condition->wait (lock, lPredSignaledAny);
1803+ bRet = true ;
1804+ }
1805+ else
1806+ {
1807+ bRet = condition->wait_for (lock, std::chrono::milliseconds (timeout), lPredSignaledAny);
1808+ }
1809+
1810+ // Clear out listeners
1811+ for (int i = 0 ; i < nEvents; i++)
1812+ {
1813+ pEvents[i]->RemoveListenerNoLock (condition);
1814+ }
1815+ condition.reset ();
1816+ }
1817+
1818+ // Auto reset, since this function is a wait too!
1819+ if (bRet)
1820+ {
1821+ if (pEvents[iEventIndex]->m_bAutoReset )
1822+ {
1823+ pEvents[iEventIndex]->m_bSignaled = false ;
1824+ }
1825+ }
1826+ break ;
1827+ }
1828+ default :
1829+ {
1830+ Assert (0 );
1831+ break ;
1832+ }
1833+ }
1834+ }
18321835 }
18331836 }
18341837 if (bRet)
0 commit comments