Skip to content

Commit

Permalink
NativeAOT Thread Name (dotnet#107943)
Browse files Browse the repository at this point in the history
Co-authored-by: Jan Kotas <jkotas@microsoft.com>
  • Loading branch information
cshung and jkotas authored Sep 29, 2024
1 parent 4c53afd commit 2917e51
Show file tree
Hide file tree
Showing 14 changed files with 141 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ private void Initialize()
[MethodImpl(MethodImplOptions.InternalCall)]
private extern void InternalFinalize();

partial void ThreadNameChanged(string? value)
private void ThreadNameChanged(string? value)
{
InformThreadNameChange(GetNativeHandle(), value, value?.Length ?? 0);
GC.KeepAlive(this);
Expand Down
2 changes: 2 additions & 0 deletions src/coreclr/nativeaot/Runtime/FinalizerHelpers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ uint32_t WINAPI FinalizerStart(void* pContext)
{
HANDLE hFinalizerEvent = (HANDLE)pContext;

PalSetCurrentThreadName(".NET Finalizer");

ThreadStore::AttachCurrentThread();
Thread * pThread = ThreadStore::GetCurrentThread();

Expand Down
4 changes: 4 additions & 0 deletions src/coreclr/nativeaot/Runtime/PalRedhawk.h
Original file line number Diff line number Diff line change
Expand Up @@ -762,6 +762,10 @@ REDHAWK_PALIMPORT void REDHAWK_PALAPI PalSetHardwareExceptionHandler(PHARDWARE_E
#endif

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);
#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);
REDHAWK_PALIMPORT bool REDHAWK_PALAPI PalStartEventPipeHelperThread(_In_ BackgroundCallback callback, _In_opt_ void* pCallbackContext);
Expand Down
7 changes: 6 additions & 1 deletion src/coreclr/nativeaot/Runtime/eventpipe/ep-rt-aot.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,11 @@ ep_rt_aot_get_last_error (void)
return PalGetLastError();
}

void ep_rt_aot_set_server_name (void)
{
PalSetCurrentThreadName(".NET EventPipe");
}

bool
ep_rt_aot_thread_create (
void *thread_func,
Expand All @@ -361,7 +366,7 @@ ep_rt_aot_thread_create (

case EP_THREAD_TYPE_SERVER:
// Match CoreCLR and hardcode a null thread context in this case.
return PalStartEventPipeHelperThread(reinterpret_cast<BackgroundCallback>(thread_func), NULL);
return PalStartEventPipeHelperThread(reinterpret_cast<BackgroundCallback>(thread_func), nullptr);

case EP_THREAD_TYPE_SESSION:
case EP_THREAD_TYPE_SAMPLING:
Expand Down
4 changes: 3 additions & 1 deletion src/coreclr/nativeaot/Runtime/eventpipe/ep-rt-aot.h
Original file line number Diff line number Diff line change
Expand Up @@ -760,7 +760,9 @@ inline
void
ep_rt_set_server_name(void)
{
// This is optional, decorates the thread name with EventPipe specific information
extern void
ep_rt_aot_set_server_name (void);
ep_rt_aot_set_server_name ();
}


Expand Down
26 changes: 21 additions & 5 deletions src/coreclr/nativeaot/Runtime/gcenv.ee.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -534,18 +534,33 @@ struct ThreadStubArguments
void (*m_pRealStartRoutine)(void*);
void* m_pRealContext;
CLREventStatic m_ThreadStartedEvent;
const char* m_name;
};

static bool CreateNonSuspendableThread(void (*threadStart)(void*), void* arg, const char* name)
{
UNREFERENCED_PARAMETER(name);

ThreadStubArguments* threadStubArgs = new (nothrow) ThreadStubArguments();
if (!threadStubArgs)
return false;

threadStubArgs->m_pRealStartRoutine = threadStart;
threadStubArgs->m_pRealContext = arg;
if (name == nullptr)
{
threadStubArgs->m_name = nullptr;
}
else
{
size_t name_length = strlen(name);
char* name_copy = new (nothrow) char[name_length + 1];
if (name_copy == nullptr)
{
delete threadStubArgs;
return false;
}
strcpy(name_copy, name);
threadStubArgs->m_name = name_copy;
}

// Helper used to wrap the start routine of GC threads so we can do things like initialize the
// thread state which requires running in the new thread's context.
Expand All @@ -554,6 +569,7 @@ static bool CreateNonSuspendableThread(void (*threadStart)(void*), void* arg, co
ThreadStore::RawGetCurrentThread()->SetGCSpecial();

ThreadStubArguments* pStartContext = (ThreadStubArguments*)argument;
PalSetCurrentThreadName(pStartContext->m_name);
auto realStartRoutine = pStartContext->m_pRealStartRoutine;
void* realContext = pStartContext->m_pRealContext;
delete pStartContext;
Expand All @@ -567,6 +583,7 @@ static bool CreateNonSuspendableThread(void (*threadStart)(void*), void* arg, co

if (!PalStartBackgroundGCThread(threadStub, threadStubArgs))
{
delete[] threadStubArgs->m_name;
delete threadStubArgs;
return false;
}
Expand All @@ -576,14 +593,13 @@ static bool CreateNonSuspendableThread(void (*threadStart)(void*), void* arg, co

bool GCToEEInterface::CreateThread(void (*threadStart)(void*), void* arg, bool is_suspendable, const char* name)
{
UNREFERENCED_PARAMETER(name);

if (!is_suspendable)
return CreateNonSuspendableThread(threadStart, arg, name);

ThreadStubArguments threadStubArgs;
threadStubArgs.m_pRealStartRoutine = threadStart;
threadStubArgs.m_pRealContext = arg;
threadStubArgs.m_name = name;

if (!threadStubArgs.m_ThreadStartedEvent.CreateAutoEventNoThrow(false))
{
Expand All @@ -608,7 +624,7 @@ bool GCToEEInterface::CreateThread(void (*threadStart)(void*), void* arg, bool i

auto realStartRoutine = pStartContext->m_pRealStartRoutine;
void* realContext = pStartContext->m_pRealContext;

PalSetCurrentThreadName(pStartContext->m_name);
pStartContext->m_ThreadStartedEvent.Set();

STRESS_LOG_RESERVE_MEM(GC_STRESSLOG_MULTIPLY);
Expand Down
10 changes: 10 additions & 0 deletions src/coreclr/nativeaot/Runtime/thread.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1346,3 +1346,13 @@ FCIMPLEND
#endif //USE_PORTABLE_HELPERS

#endif // !DACCESS_COMPILE


EXTERN_C void QCALLTYPE RhSetCurrentThreadName(const TCHAR* name)
{
#ifdef TARGET_WINDOWS
PalSetCurrentThreadNameW(name);
#else
PalSetCurrentThreadName(name);
#endif
}
14 changes: 14 additions & 0 deletions src/coreclr/nativeaot/Runtime/unix/PalRedhawkUnix.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -716,6 +716,20 @@ REDHAWK_PALEXPORT bool REDHAWK_PALAPI PalStartBackgroundWork(_In_ BackgroundCall
return st == 0;
}

REDHAWK_PALIMPORT bool REDHAWK_PALAPI PalSetCurrentThreadName(const char* name)
{
const int MAX_THREAD_NAME_SIZE = 15;
char name_copy[MAX_THREAD_NAME_SIZE + 1];
strncpy(name_copy, name, MAX_THREAD_NAME_SIZE);
name_copy[MAX_THREAD_NAME_SIZE] = '\0';
#ifdef __APPLE__
pthread_setname_np(name_copy);
#else
pthread_setname_np(pthread_self(), name_copy);
#endif //__APPLE__
return true;
}

REDHAWK_PALEXPORT bool REDHAWK_PALAPI PalStartBackgroundGCThread(_In_ BackgroundCallback callback, _In_opt_ void* pCallbackContext)
{
return PalStartBackgroundWork(callback, pCallbackContext, UInt32_FALSE);
Expand Down
38 changes: 38 additions & 0 deletions src/coreclr/nativeaot/Runtime/windows/PalRedhawkMinWin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -883,6 +883,10 @@ REDHAWK_PALEXPORT void REDHAWK_PALAPI PalHijack(HANDLE hThread, _In_opt_ void* p
ResumeThread(hThread);
}

#define SET_THREAD_DESCRIPTION_UNINITIALIZED (pfnSetThreadDescription)-1
typedef HRESULT(WINAPI *pfnSetThreadDescription)(HANDLE hThread, PCWSTR lpThreadDescription);
static pfnSetThreadDescription g_pfnSetThreadDescription = SET_THREAD_DESCRIPTION_UNINITIALIZED;

REDHAWK_PALEXPORT bool REDHAWK_PALAPI PalStartBackgroundWork(_In_ BackgroundCallback callback, _In_opt_ void* pCallbackContext, BOOL highPriority)
{
HANDLE hThread = CreateThread(
Expand All @@ -906,6 +910,40 @@ REDHAWK_PALEXPORT bool REDHAWK_PALAPI PalStartBackgroundWork(_In_ BackgroundCall
return true;
}

REDHAWK_PALIMPORT bool REDHAWK_PALAPI PalSetCurrentThreadNameW(const WCHAR* name)
{
if (g_pfnSetThreadDescription == SET_THREAD_DESCRIPTION_UNINITIALIZED)
{
HMODULE hKernel32 = LoadKernel32dll();
g_pfnSetThreadDescription = (pfnSetThreadDescription)GetProcAddress(hKernel32, "SetThreadDescription");
}
if (!g_pfnSetThreadDescription)
{
return false;
}
HANDLE hThread = GetCurrentThread();
g_pfnSetThreadDescription(hThread, name);
return true;
}

REDHAWK_PALIMPORT bool REDHAWK_PALAPI PalSetCurrentThreadName(const char* name)
{
size_t len = strlen(name);
wchar_t* threadNameWide = new (nothrow) wchar_t[len + 1];
if (threadNameWide == nullptr)
{
return false;
}
if (MultiByteToWideChar(CP_UTF8, 0, name, -1, threadNameWide, (int)(len + 1)) == 0)
{
delete[] threadNameWide;
return false;
}
bool ret = PalSetCurrentThreadNameW(threadNameWide);
delete[] threadNameWide;
return ret;
}

REDHAWK_PALEXPORT bool REDHAWK_PALAPI PalStartBackgroundGCThread(_In_ BackgroundCallback callback, _In_opt_ void* pCallbackContext)
{
return PalStartBackgroundWork(callback, pCallbackContext, FALSE);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -877,5 +877,13 @@ internal static IntPtr RhGetModuleSection(TypeManagerHandle module, ReadyToRunSe
[LibraryImport(RuntimeLibrary)]
internal static unsafe partial void RhCpuIdEx(int* cpuInfo, int functionId, int subFunctionId);
#endif

#if TARGET_UNIX
[LibraryImport(RuntimeLibrary, StringMarshalling = StringMarshalling.Utf8)]
internal static partial void RhSetCurrentThreadName(string name);
#else
[LibraryImport(RuntimeLibrary, StringMarshalling = StringMarshalling.Utf16)]
internal static partial void RhSetCurrentThreadName(string name);
#endif
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -198,8 +198,19 @@ public int ManagedThreadId
get => _managedThreadId.Id;
}

// TODO: Inform the debugger and the profiler
// private void ThreadNameChanged(string? value) {}
// TODO: Support non-current thread
private void ThreadNameChanged(string? value)
{
if (Thread.CurrentThread != this)
{
return;
}
if (value == null)
{
return;
}
RuntimeImports.RhSetCurrentThreadName(value);
}

public ThreadPriority Priority
{
Expand Down
20 changes: 20 additions & 0 deletions src/coreclr/vm/gcenv.ee.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1395,6 +1395,9 @@ struct SuspendableThreadStubArguments
class Thread* Thread;
bool HasStarted;
CLREvent ThreadStartedEvent;
#ifdef __APPLE__
const WCHAR* name;
#endif //__APPLE__
};

struct ThreadStubArguments
Expand All @@ -1404,6 +1407,9 @@ struct ThreadStubArguments
HANDLE Thread;
bool HasStarted;
CLREvent ThreadStartedEvent;
#ifdef __APPLE__
const WCHAR* name;
#endif //__APPLE__
};

namespace
Expand All @@ -1422,6 +1428,9 @@ namespace
args.ThreadStart = threadStart;
args.Thread = nullptr;
args.HasStarted = false;
#ifdef __APPLE__
args.name = name;
#endif //__APPLE__
if (!args.ThreadStartedEvent.CreateAutoEventNoThrow(FALSE))
{
return false;
Expand All @@ -1447,6 +1456,10 @@ namespace
SuspendableThreadStubArguments* args = static_cast<SuspendableThreadStubArguments*>(argument);
assert(args != nullptr);

#ifdef __APPLE__
SetThreadName(GetCurrentThread(), args->name);
#endif //__APPLE__

ClrFlsSetThreadType(ThreadType_GC);
args->Thread->SetGCSpecial();
STRESS_LOG_RESERVE_MEM(GC_STRESSLOG_MULTIPLY);
Expand Down Expand Up @@ -1504,6 +1517,9 @@ namespace
args.Argument = argument;
args.ThreadStart = threadStart;
args.Thread = INVALID_HANDLE_VALUE;
#ifdef __APPLE__
args.name = name;
#endif //__APPLE__
if (!args.ThreadStartedEvent.CreateAutoEventNoThrow(FALSE))
{
return false;
Expand All @@ -1514,6 +1530,10 @@ namespace
ThreadStubArguments* args = static_cast<ThreadStubArguments*>(argument);
assert(args != nullptr);

#ifdef __APPLE__
SetThreadName(GetCurrentThread(), args->name);
#endif //__APPLE__

ClrFlsSetThreadType(ThreadType_GC);
STRESS_LOG_RESERVE_MEM(GC_STRESSLOG_MULTIPLY);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -298,8 +298,6 @@ private void SetCultureOnUnstartedThread(CultureInfo value, bool uiCulture)
}
}

partial void ThreadNameChanged(string? value);

public CultureInfo CurrentCulture
{
get
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,7 @@ private void StartCore()
[MethodImplAttribute(MethodImplOptions.InternalCall)]
private static extern void StartInternal(Thread runtimeThread, int stackSize);

partial void ThreadNameChanged(string? value)
private void ThreadNameChanged(string? value)
{
// TODO: Should only raise the events
SetName(this, value);
Expand Down

0 comments on commit 2917e51

Please sign in to comment.