Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

NativeAOT Thread Name #107943

Merged
merged 3 commits into from
Sep 29, 2024
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 @@ -162,7 +162,7 @@ public static void SpinWait(int iterations)
[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);
cshung marked this conversation as resolved.
Show resolved Hide resolved
#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 @@ -1393,6 +1393,9 @@ struct SuspendableThreadStubArguments
class Thread* Thread;
bool HasStarted;
CLREvent ThreadStartedEvent;
#ifdef __APPLE__
const WCHAR* name;
#endif //__APPLE__
};

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

namespace
Expand All @@ -1420,6 +1426,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 @@ -1445,6 +1454,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 @@ -1502,6 +1515,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 @@ -1512,6 +1528,10 @@ namespace
ThreadStubArguments* args = static_cast<ThreadStubArguments*>(argument);
assert(args != nullptr);

#ifdef __APPLE__
SetThreadName(GetCurrentThread(), args->name);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@cshung, I think we can use it on all targets #108370?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@cshung, I think we can use it on all targets #108370?

Yes we can, but that would just be extra work since for all other platforms we have already set the name earlier.

#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 @@ -289,8 +289,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