* Added SetThreadDescription to set the unmanaged thread name as well when a managed thread name was set.
This will show up in future debuggers which know how to read that information or in ETW traces in the Thread Name column.
* use printf instead of wprintf which exists on all platforms.
* Removed printf
Ensure that GetProceAddress is only called once to when the method is not present.
Potential perf hit should be negligible since setting a thread name can only happen once per managed thread.
* - Moved SetThreadName code to winfix.cpp as proposed
- Finalizer and threadpool threads get their name
- GCToEEInterface::CreateBackgroundThread is also named
- but regular GC threads have no name because when I included utilcode.h things did break apart.
* Fix for data race in g_pfnSetThreadDescription
* Fix string literals on unix builds.
* Fixed nits
Settled thread name on ".NET Core ThreadPool"
#define CLEAR_THREAD_TYPE_STACKWALKER() ClrFlsSetValue(TlsIdx_StackWalkerWalkingThread, NULL)
#endif // DACCESS_COMPILE
+HRESULT SetThreadName(HANDLE hThread, PCWSTR lpThreadDescription);
+
inline BOOL IsStackWalkerThread()
{
STATIC_CONTRACT_NOTHROW;
}
+typedef HRESULT(WINAPI *pfnSetThreadDescription)(HANDLE hThread, PCWSTR lpThreadDescription);
+extern pfnSetThreadDescription g_pfnSetThreadDescription;
+
+// Dummy method if windows version does not support it
+HRESULT SetThreadDescriptionDummy(HANDLE hThread, PCWSTR lpThreadDescription)
+{
+ return NOERROR;
+}
+
+HRESULT WINAPI InitializeSetThreadDescription(HANDLE hThread, PCWSTR lpThreadDescription)
+{
+ HMODULE hKernel32 = WszLoadLibrary(W("kernel32.dll"));
+
+ pfnSetThreadDescription pLocal = NULL;
+ if (hKernel32 != NULL)
+ {
+ // store to thread local variable to prevent data race
+ pLocal = (pfnSetThreadDescription)GetProcAddress(hKernel32, "SetThreadDescription");
+ }
+
+ if (pLocal == NULL) // method is only available with Windows 10 Creators Update or later
+ {
+ g_pfnSetThreadDescription = SetThreadDescriptionDummy;
+ }
+ else
+ {
+ g_pfnSetThreadDescription = pLocal;
+ }
+
+ return g_pfnSetThreadDescription(hThread, lpThreadDescription);
+}
+
+pfnSetThreadDescription g_pfnSetThreadDescription = &InitializeSetThreadDescription;
+
+// Set unmanaged thread name which will show up in ETW and Debuggers which know how to read this data.
+HRESULT SetThreadName(HANDLE hThread, PCWSTR lpThreadDescription)
+{
+ return g_pfnSetThreadDescription(hThread, lpThreadDescription);
+}
DWORD
WszGetWorkingSet()
#include "appdomain.hpp"
#include "appdomain.inl"
+#ifndef FEATURE_PAL
+#include "utilcode.h"
+#endif
+
#include "newapis.h"
// To include definition of CAPTURE_BUCKETS_AT_TRANSITION
QCALL_CONTRACT;
BEGIN_QCALL;
-
+
Thread* pThread = &(*thread);
+#ifndef FEATURE_PAL
+ // Set on Windows 10 Creators Update and later machines the unmanaged thread name as well. That will show up in ETW traces and debuggers which is very helpful
+ // if more and more threads get a meaningful name
+ if (len > 0 && name != NULL)
+ {
+ SetThreadName(pThread->GetThreadHandle(), name);
+ }
+#endif
+
#ifdef PROFILING_SUPPORTED
{
BEGIN_PIN_PROFILER(CORProfilerTrackThreads());
// actual thread terminates.
GetFinalizerThread()->IncExternalCount();
- if (GetFinalizerThread()->CreateNewThread(0, &FinalizerThreadStart, NULL))
+ if (GetFinalizerThread()->CreateNewThread(0, &FinalizerThreadStart, NULL, W("Finalizer")) )
{
DWORD dwRet = GetFinalizerThread()->StartThread();
return NULL;
}
- if (threadStubArgs.thread->CreateNewThread(0, (LPTHREAD_START_ROUTINE)BackgroundThreadStub, &threadStubArgs))
+ if (threadStubArgs.thread->CreateNewThread(0, (LPTHREAD_START_ROUTINE)BackgroundThreadStub, &threadStubArgs, W("Background GC")))
{
threadStubArgs.thread->SetBackground (TRUE, FALSE);
threadStubArgs.thread->StartThread();
// We don't want ::CreateThread() calls scattered throughout the source. So gather
// them all here.
-BOOL Thread::CreateNewThread(SIZE_T stackSize, LPTHREAD_START_ROUTINE start, void *args)
+BOOL Thread::CreateNewThread(SIZE_T stackSize, LPTHREAD_START_ROUTINE start, void *args, LPCWSTR pName)
{
CONTRACTL {
NOTHROW;
bRet = CreateNewOSThread(stackSize, start, args);
#ifndef FEATURE_PAL
UndoRevert(bReverted, token);
+ SetThreadName(m_ThreadHandle, pName);
#endif // !FEATURE_PAL
return bRet;
// Create all new threads here. The thread is created as suspended, so
// you must ::ResumeThread to kick it off. It is guaranteed to create the
// thread, or throw.
- BOOL CreateNewThread(SIZE_T stackSize, LPTHREAD_START_ROUTINE start, void *args);
+ BOOL CreateNewThread(SIZE_T stackSize, LPTHREAD_START_ROUTINE start, void *args, LPCWSTR pName=NULL);
enum StackSizeBucket
// CreateNewThread takes care of reverting any impersonation - so dont do anything here.
bOK = pThread->CreateNewThread(0, // default stack size
lpStartAddress,
- lpArgs //arguments
- );
+ lpArgs, //arguments
+ W(".NET Core ThreadPool"));
}
else {
#ifndef FEATURE_PAL