@@ -1701,6 +1701,125 @@ BOOL STDMETHODCALLTYPE EEDllMain( // TRUE on success, FALSE on error.
1701
1701
1702
1702
#endif // !defined(CORECLR_EMBEDDED)
1703
1703
1704
+ static void RuntimeThreadShutdown (void * thread)
1705
+ {
1706
+ Thread* pThread = (Thread*)thread;
1707
+ _ASSERTE (pThread == GetThreadNULLOk ());
1708
+
1709
+ if (pThread)
1710
+ {
1711
+ #ifdef FEATURE_COMINTEROP
1712
+ // reset the CoInitialize state
1713
+ // so we don't call CoUninitialize during thread detach
1714
+ pThread->ResetCoInitialized ();
1715
+ #endif // FEATURE_COMINTEROP
1716
+ // For case where thread calls ExitThread directly, we need to reset the
1717
+ // frame pointer. Otherwise stackwalk would AV. We need to do it in cooperative mode.
1718
+ // We need to set m_GCOnTransitionsOK so this thread won't trigger GC when toggle GC mode
1719
+ if (pThread->m_pFrame != FRAME_TOP)
1720
+ {
1721
+ #ifdef _DEBUG
1722
+ pThread->m_GCOnTransitionsOK = FALSE ;
1723
+ #endif
1724
+ GCX_COOP_NO_DTOR ();
1725
+ pThread->m_pFrame = FRAME_TOP;
1726
+ GCX_COOP_NO_DTOR_END ();
1727
+ }
1728
+
1729
+ pThread->DetachThread (TRUE );
1730
+ }
1731
+ else
1732
+ {
1733
+ // Since we don't actually cleanup the TLS data along this path, verify that it is already cleaned up
1734
+ AssertThreadStaticDataFreed ();
1735
+ }
1736
+
1737
+ ThreadDetaching ();
1738
+ }
1739
+
1740
+ #ifdef TARGET_WINDOWS
1741
+
1742
+ // Index for the fiber local storage of the attached thread pointer
1743
+ static uint32_t g_flsIndex = FLS_OUT_OF_INDEXES;
1744
+
1745
+ // This is called when each *fiber* is destroyed. When the home fiber of a thread is destroyed,
1746
+ // it means that the thread itself is destroyed.
1747
+ // Since we receive that notification outside of the Loader Lock, it allows us to safely acquire
1748
+ // the ThreadStore lock in the RuntimeThreadShutdown.
1749
+ static void __stdcall FiberDetachCallback (void * lpFlsData)
1750
+ {
1751
+ ASSERT (g_flsIndex != FLS_OUT_OF_INDEXES);
1752
+ ASSERT (lpFlsData == FlsGetValue (g_flsIndex));
1753
+
1754
+ if (lpFlsData != NULL )
1755
+ {
1756
+ // The current fiber is the home fiber of a thread, so the thread is shutting down
1757
+ RuntimeThreadShutdown (lpFlsData);
1758
+ }
1759
+ }
1760
+
1761
+ void InitFlsSlot ()
1762
+ {
1763
+ // We use fiber detach callbacks to run our thread shutdown code because the fiber detach
1764
+ // callback is made without the OS loader lock
1765
+ g_flsIndex = FlsAlloc (FiberDetachCallback);
1766
+ if (g_flsIndex == FLS_OUT_OF_INDEXES)
1767
+ {
1768
+ COMPlusThrowWin32 ();
1769
+ }
1770
+ }
1771
+
1772
+ // Register the thread with OS to be notified when thread is about to be destroyed
1773
+ // It fails fast if a different thread was already registered with the current fiber.
1774
+ // Parameters:
1775
+ // thread - thread to attach
1776
+ static void OsAttachThread (void * thread)
1777
+ {
1778
+ void * threadFromCurrentFiber = FlsGetValue (g_flsIndex);
1779
+
1780
+ if (threadFromCurrentFiber != NULL )
1781
+ {
1782
+ _ASSERTE_ALL_BUILDS (!" Multiple threads encountered from a single fiber" );
1783
+ }
1784
+
1785
+ // Associate the current fiber with the current thread. This makes the current fiber the thread's "home"
1786
+ // fiber. This fiber is the only fiber allowed to execute managed code on this thread. When this fiber
1787
+ // is destroyed, we consider the thread to be destroyed.
1788
+ FlsSetValue (g_flsIndex, thread);
1789
+ }
1790
+
1791
+ // Detach thread from OS notifications.
1792
+ // It fails fast if some other thread value was attached to the current fiber.
1793
+ // Parameters:
1794
+ // thread - thread to detach
1795
+ // Return:
1796
+ // true if the thread was detached, false if there was no attached thread
1797
+ void OsDetachThread (void * thread)
1798
+ {
1799
+ ASSERT (g_flsIndex != FLS_OUT_OF_INDEXES);
1800
+ void * threadFromCurrentFiber = FlsGetValue (g_flsIndex);
1801
+
1802
+ if (threadFromCurrentFiber == NULL )
1803
+ {
1804
+ // we've seen this thread, but not this fiber. It must be a "foreign" fiber that was
1805
+ // borrowing this thread.
1806
+ return ;
1807
+ }
1808
+
1809
+ if (threadFromCurrentFiber != thread)
1810
+ {
1811
+ _ASSERTE_ALL_BUILDS (!" Detaching a thread from the wrong fiber" );
1812
+ }
1813
+
1814
+ FlsSetValue (g_flsIndex, NULL );
1815
+ }
1816
+
1817
+ void EnsureTlsDestructionMonitor ()
1818
+ {
1819
+ OsAttachThread (GetThread ());
1820
+ }
1821
+
1822
+ #else
1704
1823
struct TlsDestructionMonitor
1705
1824
{
1706
1825
bool m_activated = false ;
@@ -1714,36 +1833,7 @@ struct TlsDestructionMonitor
1714
1833
{
1715
1834
if (m_activated)
1716
1835
{
1717
- Thread* thread = GetThreadNULLOk ();
1718
- if (thread)
1719
- {
1720
- #ifdef FEATURE_COMINTEROP
1721
- // reset the CoInitialize state
1722
- // so we don't call CoUninitialize during thread detach
1723
- thread->ResetCoInitialized ();
1724
- #endif // FEATURE_COMINTEROP
1725
- // For case where thread calls ExitThread directly, we need to reset the
1726
- // frame pointer. Otherwise stackwalk would AV. We need to do it in cooperative mode.
1727
- // We need to set m_GCOnTransitionsOK so this thread won't trigger GC when toggle GC mode
1728
- if (thread->m_pFrame != FRAME_TOP)
1729
- {
1730
- #ifdef _DEBUG
1731
- thread->m_GCOnTransitionsOK = FALSE ;
1732
- #endif
1733
- GCX_COOP_NO_DTOR ();
1734
- thread->m_pFrame = FRAME_TOP;
1735
- GCX_COOP_NO_DTOR_END ();
1736
- }
1737
-
1738
- thread->DetachThread (TRUE );
1739
- }
1740
- else
1741
- {
1742
- // Since we don't actually cleanup the TLS data along this path, verify that it is already cleaned up
1743
- AssertThreadStaticDataFreed ();
1744
- }
1745
-
1746
- ThreadDetaching ();
1836
+ RuntimeThreadShutdown (GetThreadNULLOk ());
1747
1837
}
1748
1838
}
1749
1839
};
@@ -1757,6 +1847,8 @@ void EnsureTlsDestructionMonitor()
1757
1847
tls_destructionMonitor.Activate ();
1758
1848
}
1759
1849
1850
+ #endif
1851
+
1760
1852
#ifdef DEBUGGING_SUPPORTED
1761
1853
//
1762
1854
// InitializeDebugger initialized the Runtime-side COM+ Debugging Services
0 commit comments