Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,6 @@ internal static class __Finalizer
[UnmanagedCallersOnly(EntryPoint = "ProcessFinalizers")]
public static void ProcessFinalizers()
{
#if INPLACE_RUNTIME
System.Runtime.FinalizerInitRunner.DoInitialize();
#endif

while (true)
{
// Wait until there's some work to be done. If true is returned we should finalize objects,
Expand Down
30 changes: 25 additions & 5 deletions src/coreclr/nativeaot/Runtime/FinalizerHelpers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,30 @@ CLREventStatic g_FinalizerDoneEvent;

static HANDLE g_lowMemoryNotification = NULL;

#ifdef TARGET_WINDOWS
static bool g_ComAndFlsInitSucceeded = false;
#endif

EXTERN_C void QCALLTYPE ProcessFinalizers();

// Unmanaged front-end to the finalizer thread. We require this because at the point the GC creates the
// finalizer thread we can't run managed code. Instead this method waits
// Unmanaged front-end to the finalizer thread. We require this because at the point when this thread is
// created we can't run managed code. Instead this method waits
// for the first finalization request (by which time everything must be up and running) and kicks off the
// managed portion of the thread at that point
uint32_t WINAPI FinalizerStart(void* pContext)
{
#ifdef TARGET_WINDOWS
g_ComAndFlsInitSucceeded = PalInitComAndFlsSlot();
// handshake with EE initialization, as now we can attach Thread objects to native threads.
UInt32_BOOL res = PalSetEvent(g_FinalizerDoneEvent.GetOSEvent());
ASSERT(res);

// if FLS initialization failed do not attach the current thread and just exit instead.
// we are going to fail the runtime initialization.
if (!g_ComAndFlsInitSucceeded)
return 0;
#endif // DEBUG

HANDLE hFinalizerEvent = (HANDLE)pContext;

PalSetCurrentThreadName(".NET Finalizer");
Expand Down Expand Up @@ -86,12 +102,16 @@ bool RhInitializeFinalization()
return true;
}

void RhEnableFinalization()
#ifdef TARGET_WINDOWS
bool RhWaitForFinalizerThreadStart()
{
g_FinalizerEvent.Set();
g_FinalizerDoneEvent.Wait(INFINITE,FALSE);
g_FinalizerDoneEvent.Reset();
return g_ComAndFlsInitSucceeded;
}
#endif

EXTERN_C void QCALLTYPE RhInitializeFinalizerThread()
void RhEnableFinalization()
{
g_FinalizerEvent.Set();
}
Expand Down
17 changes: 14 additions & 3 deletions src/coreclr/nativeaot/Runtime/GCHelpers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,18 @@ GPTR_DECL(MethodTable, g_pFreeObjectEEType);
GPTR_IMPL(Thread, g_pFinalizerThread);

bool RhInitializeFinalization();
#ifdef TARGET_WINDOWS
bool RhWaitForFinalizerThreadStart();
#endif

// Perform any runtime-startup initialization needed by the GC, HandleTable or environmental code in gcenv.ee.
// Returns true on success or false if a subsystem failed to initialize.
bool InitializeGC()
{
// Give some headstart to the finalizer thread by launching it early.
if (!RhInitializeFinalization())
return false;

// Initialize the special MethodTable used to mark free list entries in the GC heap.
g_FreeObjectEEType.InitializeAsGcFreeType();
g_pFreeObjectEEType = &g_FreeObjectEEType;
Expand Down Expand Up @@ -78,13 +85,17 @@ bool InitializeGC()
if (FAILED(hr))
return false;

if (!RhInitializeFinalization())
return false;

// Initialize HandleTable.
if (!GCHandleUtilities::GetGCHandleManager()->Initialize())
return false;

#ifdef TARGET_WINDOWS
// By now finalizer thread should have initialized FLS slot for thread cleanup notifications.
// And ensured that COM is initialized (must happen before allocating FLS slot).
// Make sure that this was done.
if (!RhWaitForFinalizerThreadStart())
return false;
#endif
return true;
}

Expand Down
2 changes: 1 addition & 1 deletion src/coreclr/nativeaot/Runtime/PalRedhawk.h
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,7 @@ typedef uint32_t (__stdcall *BackgroundCallback)(_In_opt_ void* pCallbackContext
REDHAWK_PALIMPORT bool REDHAWK_PALAPI PalSetCurrentThreadName(const char* name);
#ifdef TARGET_WINDOWS
REDHAWK_PALIMPORT bool REDHAWK_PALAPI PalSetCurrentThreadNameW(const WCHAR* name);
REDHAWK_PALIMPORT bool REDHAWK_PALAPI PalInitComAndFlsSlot();
#endif
REDHAWK_PALIMPORT bool REDHAWK_PALAPI PalStartBackgroundGCThread(_In_ BackgroundCallback callback, _In_opt_ void* pCallbackContext);
REDHAWK_PALIMPORT bool REDHAWK_PALAPI PalStartFinalizerThread(_In_ BackgroundCallback callback, _In_opt_ void* pCallbackContext);
Expand All @@ -321,7 +322,6 @@ REDHAWK_PALIMPORT uint32_t REDHAWK_PALAPI PalCompatibleWaitAny(UInt32_BOOL alert
REDHAWK_PALIMPORT HANDLE PalCreateLowMemoryResourceNotification();

REDHAWK_PALIMPORT void REDHAWK_PALAPI PalAttachThread(void* thread);
REDHAWK_PALIMPORT bool REDHAWK_PALAPI PalDetachThread(void* thread);

REDHAWK_PALIMPORT uint64_t PalGetCurrentOSThreadId();

Expand Down
1 change: 0 additions & 1 deletion src/coreclr/nativeaot/Runtime/amd64/AsmMacros.inc
Original file line number Diff line number Diff line change
Expand Up @@ -329,7 +329,6 @@ TAILJMP_RAX TEXTEQU <DB 048h, 0FFh, 0E0h>
;;
;; CONSTANTS -- INTEGER
;;
TSF_Attached equ 01h
TSF_SuppressGcStress equ 08h
TSF_DoNotTriggerGc equ 10h

Expand Down
2 changes: 0 additions & 2 deletions src/coreclr/nativeaot/Runtime/arm64/AsmMacros.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,11 @@
;;
;; CONSTANTS -- INTEGER
;;
TSF_Attached equ 0x01
TSF_SuppressGcStress equ 0x08
TSF_DoNotTriggerGc equ 0x10
TSF_SuppressGcStress__OR__TSF_DoNotTriggerGC equ 0x18

;; Bit position for the flags above, to be used with tbz/tbnz instructions
TSF_Attached_Bit equ 0
TSF_SuppressGcStress_Bit equ 3
TSF_DoNotTriggerGc_Bit equ 4

Expand Down
1 change: 0 additions & 1 deletion src/coreclr/nativeaot/Runtime/i386/AsmMacros.inc
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,6 @@ endm
;;
;; CONSTANTS -- INTEGER
;;
TSF_Attached equ 01h
TSF_SuppressGcStress equ 08h
TSF_DoNotTriggerGc equ 10h

Expand Down
3 changes: 3 additions & 0 deletions src/coreclr/nativeaot/Runtime/thread.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1096,7 +1096,10 @@ bool Thread::IsDetached()
void Thread::SetDetached()
{
ASSERT(!IsStateSet(TSF_Detached));
ASSERT(IsStateSet(TSF_Attached));

SetState(TSF_Detached);
ClearState(TSF_Attached);
}

bool Thread::IsActivationPending()
Expand Down
4 changes: 3 additions & 1 deletion src/coreclr/nativeaot/Runtime/thread.h
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,9 @@ class Thread : private RuntimeThreadLocals
{
TSF_Unknown = 0x00000000, // Threads are created in this state
TSF_Attached = 0x00000001, // Thread was inited by first U->M transition on this thread
TSF_Detached = 0x00000002, // Thread was detached by DllMain
// ...Prior to setting this bit the state is TSF_Unknown.
TSF_Detached = 0x00000002, // Thread was detached and no longer can run managed code.
// ...TSF_Attached is cleared when TSF_Detached is set.
TSF_SuppressGcStress = 0x00000008, // Do not allow gc stress on this thread, used in DllMain
// ...and on the Finalizer thread
TSF_DoNotTriggerGc = 0x00000010, // Do not allow hijacking of this thread, also intended to
Expand Down
17 changes: 10 additions & 7 deletions src/coreclr/nativeaot/Runtime/threadstore.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -110,9 +110,16 @@ void ThreadStore::AttachCurrentThread(bool fAcquireThreadStoreLock)
// we want to avoid at construction time because the loader lock is held then.
Thread * pAttachingThread = RawGetCurrentThread();

// The thread was already initialized, so it is already attached
if (pAttachingThread->IsDetached())
{
ASSERT_UNCONDITIONALLY("Attempt to execute managed code after the .NET runtime thread state has been destroyed.");
RhFailFast();
}

// The thread was already initialized, so it is already attached.
if (pAttachingThread->IsInitialized())
{
ASSERT((pAttachingThread->m_ThreadStateFlags & Thread::TSF_Attached) != 0);
return;
}

Expand Down Expand Up @@ -156,12 +163,8 @@ void ThreadStore::DetachCurrentThread()
return;
}

// Unregister from OS notifications
// This can return false if a thread did not register for OS notification.
if (!PalDetachThread(pDetachingThread))
{
return;
}
// detach callback should not call us twice
ASSERT(!pDetachingThread->IsDetached());

// Run pre-mortem callbacks while we still can run managed code and not holding locks.
// NOTE: background GC threads are attached/suspendable threads, but should not run ordinary
Expand Down
11 changes: 0 additions & 11 deletions src/coreclr/nativeaot/Runtime/unix/PalRedhawkUnix.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -517,17 +517,6 @@ extern "C" void PalAttachThread(void* thread)
UnmaskActivationSignal();
}

// Detach thread from OS notifications.
// Parameters:
// thread - thread to detach
// Return:
// true if the thread was detached, false if there was no attached thread
extern "C" bool PalDetachThread(void* thread)
{
UNREFERENCED_PARAMETER(thread);
return true;
}

#if !defined(USE_PORTABLE_HELPERS) && !defined(FEATURE_RX_THUNKS)

REDHAWK_PALEXPORT UInt32_BOOL REDHAWK_PALAPI PalAllocateThunksFromTemplate(HANDLE hTemplateModule, uint32_t templateRva, size_t templateSize, void** newThunksOut)
Expand Down
96 changes: 37 additions & 59 deletions src/coreclr/nativeaot/Runtime/windows/PalRedhawkMinWin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,13 +53,47 @@ static uint32_t g_flsIndex = FLS_OUT_OF_INDEXES;
void __stdcall FiberDetachCallback(void* lpFlsData)
{
ASSERT(g_flsIndex != FLS_OUT_OF_INDEXES);
ASSERT(g_flsIndex != NULL);
ASSERT(lpFlsData == FlsGetValue(g_flsIndex));

if (lpFlsData != NULL)
// The current fiber is the home fiber of a thread, so the thread is shutting down
RuntimeThreadShutdown(lpFlsData);
}

REDHAWK_PALEXPORT bool REDHAWK_PALAPI PalInitComAndFlsSlot()
{
ASSERT(g_flsIndex == FLS_OUT_OF_INDEXES);

// Making finalizer thread MTA early ensures that COM is initialized before we initialize our thread
// termination callback.
HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
if (FAILED(hr))
return false;

// We use fiber detach callbacks to run our thread shutdown code because the fiber detach
// callback is made without the OS loader lock
g_flsIndex = FlsAlloc(FiberDetachCallback);
return g_flsIndex != FLS_OUT_OF_INDEXES;
}

// Register the thread with OS to be notified when thread is about to be destroyed
// It fails fast if a different thread was already registered with the current fiber.
// Parameters:
// thread - thread to attach
REDHAWK_PALEXPORT void REDHAWK_PALAPI PalAttachThread(void* thread)
{
void* threadFromCurrentFiber = FlsGetValue(g_flsIndex);

if (threadFromCurrentFiber != NULL)
{
// The current fiber is the home fiber of a thread, so the thread is shutting down
RuntimeThreadShutdown(lpFlsData);
ASSERT_UNCONDITIONALLY("Multiple threads encountered from a single fiber");
RhFailFast();
}

// Associate the current fiber with the current thread. This makes the current fiber the thread's "home"
// fiber. This fiber is the only fiber allowed to execute managed code on this thread. When this fiber
// is destroyed, we consider the thread to be destroyed.
FlsSetValue(g_flsIndex, thread);
}

static HMODULE LoadKernel32dll()
Expand Down Expand Up @@ -159,14 +193,6 @@ void InitializeCurrentProcessCpuCount()
// initialization and false on failure.
REDHAWK_PALEXPORT bool REDHAWK_PALAPI PalInit()
{
// We use fiber detach callbacks to run our thread shutdown code because the fiber detach
// callback is made without the OS loader lock
g_flsIndex = FlsAlloc(FiberDetachCallback);
if (g_flsIndex == FLS_OUT_OF_INDEXES)
{
return false;
}

GCConfig::Initialize();

if (!GCToOSInterface::Initialize())
Expand All @@ -179,54 +205,6 @@ REDHAWK_PALEXPORT bool REDHAWK_PALAPI PalInit()
return true;
}

// Register the thread with OS to be notified when thread is about to be destroyed
// It fails fast if a different thread was already registered with the current fiber.
// Parameters:
// thread - thread to attach
REDHAWK_PALEXPORT void REDHAWK_PALAPI PalAttachThread(void* thread)
{
void* threadFromCurrentFiber = FlsGetValue(g_flsIndex);

if (threadFromCurrentFiber != NULL)
{
ASSERT_UNCONDITIONALLY("Multiple threads encountered from a single fiber");
RhFailFast();
}

// Associate the current fiber with the current thread. This makes the current fiber the thread's "home"
// fiber. This fiber is the only fiber allowed to execute managed code on this thread. When this fiber
// is destroyed, we consider the thread to be destroyed.
FlsSetValue(g_flsIndex, thread);
}

// Detach thread from OS notifications.
// It fails fast if some other thread value was attached to the current fiber.
// Parameters:
// thread - thread to detach
// Return:
// true if the thread was detached, false if there was no attached thread
REDHAWK_PALEXPORT bool REDHAWK_PALAPI PalDetachThread(void* thread)
{
ASSERT(g_flsIndex != FLS_OUT_OF_INDEXES);
void* threadFromCurrentFiber = FlsGetValue(g_flsIndex);

if (threadFromCurrentFiber == NULL)
{
// we've seen this thread, but not this fiber. It must be a "foreign" fiber that was
// borrowing this thread.
return false;
}

if (threadFromCurrentFiber != thread)
{
ASSERT_UNCONDITIONALLY("Detaching a thread from the wrong fiber");
RhFailFast();
}

FlsSetValue(g_flsIndex, NULL);
return true;
}

extern "C" uint64_t PalQueryPerformanceCounter()
{
return GCToOSInterface::QueryPerformanceCounter();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,6 @@
<Compile Include="System\Runtime\GCSettings.NativeAot.cs" />
<Compile Include="System\Runtime\TypeLoaderExports.cs" />
<Compile Include="System\Runtime\ThunkPool.cs" />
<Compile Include="System\Runtime\InitializeFinalizerThread.cs" />
<Compile Include="System\Runtime\InteropServices\ComEventsHelper.NativeAot.cs" Condition="'$(FeatureCominterop)' == 'true'" />
<Compile Include="System\Runtime\InteropServices\ComWrappers.NativeAot.cs" Condition="'$(FeatureComWrappers)' == 'true'" />
<Compile Include="System\Runtime\InteropServices\GCHandle.NativeAot.cs" />
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -94,9 +94,6 @@ internal static void RhWaitForPendingFinalizers(bool allowReentrantWait)
RhWaitForPendingFinalizers(allowReentrantWait ? 1 : 0);
}

[LibraryImport(RuntimeLibrary)]
internal static partial void RhInitializeFinalizerThread();

// Get maximum GC generation number.
[MethodImplAttribute(MethodImplOptions.InternalCall)]
[RuntimeImport(RuntimeLibrary, "RhGetMaxGcGeneration")]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -137,10 +137,6 @@ private static bool SetApartmentStateUnchecked(ApartmentState state, bool throwO

partial void InitializeComOnNewThread();

internal static void InitializeComForFinalizerThread()
{
}

public void DisableComObjectEagerCleanup() { }

public void Interrupt() => WaitSubsystem.Interrupt(this);
Expand Down
Loading