Skip to content
Merged
3 changes: 2 additions & 1 deletion src/coreclr/nativeaot/Bootstrap/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ void* PalGetModuleHandleFromPointer(void* pointer);

MANAGED_RUNTIME_EXPORT(GetRuntimeException)
MANAGED_RUNTIME_EXPORT(RuntimeFailFast)
MANAGED_RUNTIME_EXPORT(ThreadEntryPoint)
MANAGED_RUNTIME_EXPORT(AppendExceptionStackFrame)
MANAGED_RUNTIME_EXPORT(GetSystemArrayEEType)
MANAGED_RUNTIME_EXPORT(OnFirstChanceException)
Expand All @@ -141,7 +142,7 @@ typedef void (MANAGED_RUNTIME_EXPORT_CALLCONV *pfn)();
static const pfn c_classlibFunctions[] = {
&MANAGED_RUNTIME_EXPORT_NAME(GetRuntimeException),
&MANAGED_RUNTIME_EXPORT_NAME(RuntimeFailFast),
nullptr, // &UnhandledExceptionHandler,
&MANAGED_RUNTIME_EXPORT_NAME(ThreadEntryPoint),
&MANAGED_RUNTIME_EXPORT_NAME(AppendExceptionStackFrame),
nullptr, // &CheckStaticClassConstruction,
&MANAGED_RUNTIME_EXPORT_NAME(GetSystemArrayEEType),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ internal enum ClassLibFunctionId
{
GetRuntimeException = 0,
FailFast = 1,
// UnhandledExceptionHandler = 2, // unused
ThreadEntryPoint = 2,
AppendExceptionStackFrame = 3,
// unused = 4,
GetSystemArrayEEType = 5,
Expand Down
2 changes: 1 addition & 1 deletion src/coreclr/nativeaot/Runtime/ICodeManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ enum class ClasslibFunctionId
{
GetRuntimeException = 0,
FailFast = 1,
UnhandledExceptionHandler = 2,
ThreadEntryPoint = 2,
AppendExceptionStackFrame = 3,
// unused = 4,
GetSystemArrayEEType = 5,
Expand Down
39 changes: 39 additions & 0 deletions src/coreclr/nativeaot/Runtime/thread.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include "common.h"
#include "gcenv.h"
#include "gcheaputilities.h"
#include "gchandleutilities.h"

#include "CommonTypes.h"
#include "CommonMacros.h"
Expand Down Expand Up @@ -1278,6 +1279,44 @@ FCIMPL0(Object**, RhGetThreadStaticStorage)
}
FCIMPLEND

#ifdef TARGET_UNIX
#define NEWTHREAD_RETURN_TYPE size_t
#else
#define NEWTHREAD_RETURN_TYPE uint32_t
#endif

FCIMPL1(NEWTHREAD_RETURN_TYPE, RhThreadEntryPoint, void* pContext)
{
// We will attach the thread early so that when the managed thread entrypoint
// starts running and performs its reverse p/invoke transition, the thread is
// already attached.
//
// This avoids potential deadlocks with module initializers that may be running
// as part of runtime initialization (in non-EXE scenario) and creating new
// threads. When RhThreadEntryPoint runs, the runtime must already be initialized
// enough to be able to run managed code so we don't need to wait for it to
// finish.

ThreadStore::AttachCurrentThread();

Thread * pThread = ThreadStore::GetCurrentThread();
pThread->SetDeferredTransitionFrameForNativeHelperThread();
pThread->DisablePreemptiveMode();

Object * pThreadObject = ObjectFromHandle((OBJECTHANDLE)pContext);
MethodTable* pMT = pThreadObject->GetMethodTable();

pThread->EnablePreemptiveMode();

NEWTHREAD_RETURN_TYPE (*pFn)(void*) = (NEWTHREAD_RETURN_TYPE (*)(void*))
pMT->GetTypeManagerPtr()
->AsTypeManager()
->GetClasslibFunction(ClasslibFunctionId::ThreadEntryPoint);

return pFn(pContext);
}
FCIMPLEND

InlinedThreadStaticRoot* Thread::GetInlinedThreadStaticList()
{
return m_pInlinedThreadLocalStatics;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,18 @@ internal static partial class RuntimeImports
{
internal const string RuntimeLibrary = "*";

[MethodImplAttribute(MethodImplOptions.InternalCall)]
[RuntimeImport(RuntimeLibrary, "RhThreadEntryPoint")]
#if TARGET_UNIX
private static extern unsafe nint RhThreadEntryPoint(nint pContext);
internal static unsafe delegate* unmanaged<nint, nint> RhGetThreadEntryPointAddress()
=> (delegate* unmanaged<nint, nint>)(delegate*<nint, nint>)&RhThreadEntryPoint;
#else
private static extern unsafe uint RhThreadEntryPoint(nint pContext);
internal static unsafe delegate* unmanaged<nint, uint> RhGetThreadEntryPointAddress()
=> (delegate* unmanaged<nint, uint>)(delegate*<nint, uint>)&RhThreadEntryPoint;
#endif

[MethodImplAttribute(MethodImplOptions.InternalCall)]
[RuntimeImport(RuntimeLibrary, "RhGetCrashInfoBuffer")]
internal static extern unsafe byte* RhGetCrashInfoBuffer(out int cbMaxSize);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ private unsafe bool CreateThread(GCHandle<Thread> thisThreadHandle)
stackSize = RuntimeImports.RhGetDefaultStackSize();
}

if (!Interop.Sys.CreateThread(stackSize, &ThreadEntryPoint, GCHandle<Thread>.ToIntPtr(thisThreadHandle)))
if (!Interop.Sys.CreateThread(stackSize, RuntimeImports.RhGetThreadEntryPointAddress(), GCHandle<Thread>.ToIntPtr(thisThreadHandle)))
{
return false;
}
Expand All @@ -115,7 +115,7 @@ private unsafe bool CreateThread(GCHandle<Thread> thisThreadHandle)
/// <summary>
/// This is an entry point for managed threads created by application
/// </summary>
[UnmanagedCallersOnly]
[UnmanagedCallersOnly(EntryPoint = "ThreadEntryPoint")]
private static IntPtr ThreadEntryPoint(IntPtr parameter)
{
StartThread(parameter);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ private unsafe bool CreateThread(GCHandle<Thread> thisThreadHandle)
}

_osHandle = Interop.Kernel32.CreateThread(IntPtr.Zero, (IntPtr)stackSize,
&ThreadEntryPoint, GCHandle<Thread>.ToIntPtr(thisThreadHandle),
RuntimeImports.RhGetThreadEntryPointAddress(), GCHandle<Thread>.ToIntPtr(thisThreadHandle),
Interop.Kernel32.CREATE_SUSPENDED | Interop.Kernel32.STACK_SIZE_PARAM_IS_A_RESERVATION,
out _);

Expand All @@ -219,7 +219,7 @@ private unsafe bool CreateThread(GCHandle<Thread> thisThreadHandle)
/// <summary>
/// This is an entry point for managed threads created by application
/// </summary>
[UnmanagedCallersOnly]
[UnmanagedCallersOnly(EntryPoint = "ThreadEntryPoint")]
private static uint ThreadEntryPoint(IntPtr parameter)
{
StartThread(parameter);
Expand Down
16 changes: 15 additions & 1 deletion src/tests/nativeaot/SmokeTests/SharedLibrary/SharedLibrary.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,29 @@
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Threading;

namespace SharedLibrary
{
public class ClassLibrary
{
static Thread s_setterThread;
static int s_primitiveInt;

[ModuleInitializer]
public static void CreateThreadInModuleInitializer()
{
// Regression test for https://github.com/dotnet/runtime/issues/107699
// where creating threads in module initializer would lead to a deadlock.
s_setterThread = new Thread(() => { s_primitiveInt = 10; });
s_setterThread.Start();
}

[UnmanagedCallersOnly(EntryPoint = "ReturnsPrimitiveInt", CallConvs = new Type[] { typeof(CallConvStdcall) })]
public static int ReturnsPrimitiveInt()
{
return 10;
s_setterThread.Join();
return s_primitiveInt;
}

[UnmanagedCallersOnly(EntryPoint = "ReturnsPrimitiveBool", CallConvs = new Type[] { typeof(CallConvStdcall) })]
Expand Down