From b519a7d02bedcdd8c97e75ca3b930658fc21b558 Mon Sep 17 00:00:00 2001 From: Pieter-Jan Briers Date: Mon, 11 Nov 2019 13:30:18 +0100 Subject: [PATCH] Implement SetThreadName in PAL for Linux. (dotnet/coreclr#27182) * Implement SetThreadName in PAL for Linux. This means thread names will now show up in gdb, htop, etc... on Linux. I did not implement this for any other platforms: I did not have anything to test them with, and pthread_setname_np's API varies wildly. Commit migrated from https://github.com/dotnet/coreclr/commit/5f5f9606a6eef78256536f667c2df7b2495a8c3d --- .../src/dlls/mscordac/mscordac_unixexports.src | 1 + src/coreclr/src/pal/inc/pal.h | 61 +++++++++++ src/coreclr/src/pal/inc/rt/palrt.h | 53 ---------- src/coreclr/src/pal/src/include/pal/thread.hpp | 8 ++ src/coreclr/src/pal/src/thread/thread.cpp | 116 +++++++++++++++++++++ src/coreclr/src/utilcode/winfix.cpp | 7 ++ src/coreclr/src/vm/comsynchronizable.cpp | 3 +- src/coreclr/src/vm/threads.cpp | 5 +- src/coreclr/src/vm/win32threadpool.cpp | 3 +- 9 files changed, 197 insertions(+), 60 deletions(-) diff --git a/src/coreclr/src/dlls/mscordac/mscordac_unixexports.src b/src/coreclr/src/dlls/mscordac/mscordac_unixexports.src index b008114..22e8f78 100644 --- a/src/coreclr/src/dlls/mscordac/mscordac_unixexports.src +++ b/src/coreclr/src/dlls/mscordac/mscordac_unixexports.src @@ -170,6 +170,7 @@ nativeStringResourceTable_mscorrc_debug #SetFilePointer #SetLastError #SetErrorMode +#SetThreadDescription #Sleep #SleepEx #SwitchToThread diff --git a/src/coreclr/src/pal/inc/pal.h b/src/coreclr/src/pal/inc/pal.h index 0e1312d..9123500 100644 --- a/src/coreclr/src/pal/inc/pal.h +++ b/src/coreclr/src/pal/inc/pal.h @@ -2400,6 +2400,14 @@ GetThreadTimes( OUT LPFILETIME lpKernelTime, OUT LPFILETIME lpUserTime); +PALIMPORT +HRESULT +PALAPI +SetThreadDescription( + IN HANDLE hThread, + IN PCWSTR lpThreadDescription +); + #define TLS_OUT_OF_INDEXES ((DWORD)0xFFFFFFFF) PALIMPORT @@ -5086,6 +5094,59 @@ public: #define _O_TEXT 0x4000 #define _O_BINARY 0x8000 +/******************* HRESULT types ****************************************/ + +#define FACILITY_WINDOWS 8 +#define FACILITY_URT 19 +#define FACILITY_UMI 22 +#define FACILITY_SXS 23 +#define FACILITY_STORAGE 3 +#define FACILITY_SSPI 9 +#define FACILITY_SCARD 16 +#define FACILITY_SETUPAPI 15 +#define FACILITY_SECURITY 9 +#define FACILITY_RPC 1 +#define FACILITY_WIN32 7 +#define FACILITY_CONTROL 10 +#define FACILITY_NULL 0 +#define FACILITY_MSMQ 14 +#define FACILITY_MEDIASERVER 13 +#define FACILITY_INTERNET 12 +#define FACILITY_ITF 4 +#define FACILITY_DPLAY 21 +#define FACILITY_DISPATCH 2 +#define FACILITY_COMPLUS 17 +#define FACILITY_CERT 11 +#define FACILITY_ACS 20 +#define FACILITY_AAF 18 + +#define NO_ERROR 0L + +#define SEVERITY_SUCCESS 0 +#define SEVERITY_ERROR 1 + +#define SUCCEEDED(Status) ((HRESULT)(Status) >= 0) +#define FAILED(Status) ((HRESULT)(Status)<0) +#define IS_ERROR(Status) ((ULONG)(Status) >> 31 == SEVERITY_ERROR) // diff from win32 +#define HRESULT_CODE(hr) ((hr) & 0xFFFF) +#define SCODE_CODE(sc) ((sc) & 0xFFFF) +#define HRESULT_FACILITY(hr) (((hr) >> 16) & 0x1fff) +#define SCODE_FACILITY(sc) (((sc) >> 16) & 0x1fff) +#define HRESULT_SEVERITY(hr) (((hr) >> 31) & 0x1) +#define SCODE_SEVERITY(sc) (((sc) >> 31) & 0x1) + +// both macros diff from Win32 +#define MAKE_HRESULT(sev,fac,code) \ + ((HRESULT) (((ULONG)(sev)<<31) | ((ULONG)(fac)<<16) | ((ULONG)(code))) ) +#define MAKE_SCODE(sev,fac,code) \ + ((SCODE) (((ULONG)(sev)<<31) | ((ULONG)(fac)<<16) | ((LONG)(code))) ) + +#define FACILITY_NT_BIT 0x10000000 +#define HRESULT_FROM_WIN32(x) ((HRESULT)(x) <= 0 ? ((HRESULT)(x)) : ((HRESULT) (((x) & 0x0000FFFF) | (FACILITY_WIN32 << 16) | 0x80000000))) +#define __HRESULT_FROM_WIN32(x) HRESULT_FROM_WIN32(x) + +#define HRESULT_FROM_NT(x) ((HRESULT) ((x) | FACILITY_NT_BIT)) + #ifdef __cplusplus } #endif diff --git a/src/coreclr/src/pal/inc/rt/palrt.h b/src/coreclr/src/pal/inc/rt/palrt.h index 123d545..0122236 100644 --- a/src/coreclr/src/pal/inc/rt/palrt.h +++ b/src/coreclr/src/pal/inc/rt/palrt.h @@ -302,59 +302,6 @@ typedef union _ULARGE_INTEGER { ULONGLONG QuadPart; } ULARGE_INTEGER, *PULARGE_INTEGER; -/******************* HRESULT types ****************************************/ - -#define FACILITY_WINDOWS 8 -#define FACILITY_URT 19 -#define FACILITY_UMI 22 -#define FACILITY_SXS 23 -#define FACILITY_STORAGE 3 -#define FACILITY_SSPI 9 -#define FACILITY_SCARD 16 -#define FACILITY_SETUPAPI 15 -#define FACILITY_SECURITY 9 -#define FACILITY_RPC 1 -#define FACILITY_WIN32 7 -#define FACILITY_CONTROL 10 -#define FACILITY_NULL 0 -#define FACILITY_MSMQ 14 -#define FACILITY_MEDIASERVER 13 -#define FACILITY_INTERNET 12 -#define FACILITY_ITF 4 -#define FACILITY_DPLAY 21 -#define FACILITY_DISPATCH 2 -#define FACILITY_COMPLUS 17 -#define FACILITY_CERT 11 -#define FACILITY_ACS 20 -#define FACILITY_AAF 18 - -#define NO_ERROR 0L - -#define SEVERITY_SUCCESS 0 -#define SEVERITY_ERROR 1 - -#define SUCCEEDED(Status) ((HRESULT)(Status) >= 0) -#define FAILED(Status) ((HRESULT)(Status)<0) -#define IS_ERROR(Status) ((ULONG)(Status) >> 31 == SEVERITY_ERROR) // diff from win32 -#define HRESULT_CODE(hr) ((hr) & 0xFFFF) -#define SCODE_CODE(sc) ((sc) & 0xFFFF) -#define HRESULT_FACILITY(hr) (((hr) >> 16) & 0x1fff) -#define SCODE_FACILITY(sc) (((sc) >> 16) & 0x1fff) -#define HRESULT_SEVERITY(hr) (((hr) >> 31) & 0x1) -#define SCODE_SEVERITY(sc) (((sc) >> 31) & 0x1) - -// both macros diff from Win32 -#define MAKE_HRESULT(sev,fac,code) \ - ((HRESULT) (((ULONG)(sev)<<31) | ((ULONG)(fac)<<16) | ((ULONG)(code))) ) -#define MAKE_SCODE(sev,fac,code) \ - ((SCODE) (((ULONG)(sev)<<31) | ((ULONG)(fac)<<16) | ((LONG)(code))) ) - -#define FACILITY_NT_BIT 0x10000000 -#define HRESULT_FROM_WIN32(x) ((HRESULT)(x) <= 0 ? ((HRESULT)(x)) : ((HRESULT) (((x) & 0x0000FFFF) | (FACILITY_WIN32 << 16) | 0x80000000))) -#define __HRESULT_FROM_WIN32(x) HRESULT_FROM_WIN32(x) - -#define HRESULT_FROM_NT(x) ((HRESULT) ((x) | FACILITY_NT_BIT)) - /******************* OLE, BSTR, VARIANT *************************/ STDAPI_VIS(DLLEXPORT, LPVOID) CoTaskMemAlloc(SIZE_T cb); diff --git a/src/coreclr/src/pal/src/include/pal/thread.hpp b/src/coreclr/src/pal/src/include/pal/thread.hpp index d4cb96a..ad29486 100644 --- a/src/coreclr/src/pal/src/include/pal/thread.hpp +++ b/src/coreclr/src/pal/src/include/pal/thread.hpp @@ -201,6 +201,14 @@ namespace CorUnix friend PAL_ERROR + InternalSetThreadDescription( + CPalThread *, + HANDLE, + PCWSTR + ); + + friend + PAL_ERROR CreateThreadData( CPalThread **ppThread ); diff --git a/src/coreclr/src/pal/src/thread/thread.cpp b/src/coreclr/src/pal/src/thread/thread.cpp index 45c2a42..4c4b621 100644 --- a/src/coreclr/src/pal/src/thread/thread.cpp +++ b/src/coreclr/src/pal/src/thread/thread.cpp @@ -1578,7 +1578,123 @@ GetThreadTimes( return (retval); } +HRESULT +PALAPI +SetThreadDescription( + IN HANDLE hThread, + IN PCWSTR lpThreadDescription) +{ + CPalThread *pThread; + PAL_ERROR palError; + + PERF_ENTRY(SetThreadDescription); + ENTRY("SetThreadDescription(hThread=%p,lpThreadDescription=%p)\n", hThread, lpThreadDescription); + + pThread = InternalGetCurrentThread(); + + palError = InternalSetThreadDescription( + pThread, + hThread, + lpThreadDescription + ); + + if (NO_ERROR != palError) + { + pThread->SetLastError(palError); + } + + LOGEXIT("SetThreadDescription"); + PERF_EXIT(SetThreadDescription); + + return HRESULT_FROM_WIN32(palError); +} +PAL_ERROR +CorUnix::InternalSetThreadDescription( + CPalThread *pThread, + HANDLE hTargetThread, + PCWSTR lpThreadDescription +) +{ + PAL_ERROR palError = NO_ERROR; + CPalThread *pTargetThread = NULL; + IPalObject *pobjThread = NULL; + int error; + int nameSize; + char *nameBuf = NULL; + +// The exact API of pthread_setname_np varies very wildly depending on OS. +// For now, only Linux is implemented. +#if defined(__linux__) + + palError = InternalGetThreadDataFromHandle( + pThread, + hTargetThread, + &pTargetThread, + &pobjThread + ); + + if (NO_ERROR != palError) + { + goto InternalSetThreadDescriptionExit; + } + + pTargetThread->Lock(pThread); + + /* translate the wide char lpThreadDescription string to multibyte string */ + nameSize = WideCharToMultiByte(CP_ACP, 0, lpThreadDescription, -1, NULL, 0, NULL, NULL); + + if (0 == nameSize) + { + palError = ERROR_INTERNAL_ERROR; + goto InternalSetThreadDescriptionExit; + } + + nameBuf = (char *)PAL_malloc(nameSize); + if (nameBuf == NULL) + { + palError = ERROR_OUTOFMEMORY; + goto InternalSetThreadDescriptionExit; + } + + if (WideCharToMultiByte(CP_ACP, 0, lpThreadDescription, -1, nameBuf, nameSize, NULL, + NULL) != nameSize) + { + palError = ERROR_INTERNAL_ERROR; + goto InternalSetThreadDescriptionExit; + } + + // Null terminate early. + // pthread_setname_np only accepts up to 16 chars. + nameBuf[15] = '\0'; + + error = pthread_setname_np(pTargetThread->GetPThreadSelf(), nameBuf); + + if (error != 0) + { + palError = ERROR_INTERNAL_ERROR; + } + +InternalSetThreadDescriptionExit: + + if (NULL != pTargetThread) + { + pTargetThread->Unlock(pThread); + } + + if (NULL != pobjThread) + { + pobjThread->ReleaseReference(pThread); + } + + if (NULL != nameBuf) { + PAL_free(nameBuf); + } + +#endif // defined(__linux__) + + return palError; +} void * CPalThread::ThreadEntry( diff --git a/src/coreclr/src/utilcode/winfix.cpp b/src/coreclr/src/utilcode/winfix.cpp index 07c5c5e..785839e 100644 --- a/src/coreclr/src/utilcode/winfix.cpp +++ b/src/coreclr/src/utilcode/winfix.cpp @@ -292,4 +292,11 @@ HRESULT SetThreadName(HANDLE hThread, PCWSTR lpThreadDescription) return g_pfnSetThreadDescription(hThread, lpThreadDescription); } +#else //!FEATURE_PAL + +HRESULT SetThreadName(HANDLE hThread, PCWSTR lpThreadDescription) +{ + return SetThreadDescription(hThread, lpThreadDescription); +} + #endif //!FEATURE_PAL diff --git a/src/coreclr/src/vm/comsynchronizable.cpp b/src/coreclr/src/vm/comsynchronizable.cpp index b4cb088..a6b62fe 100644 --- a/src/coreclr/src/vm/comsynchronizable.cpp +++ b/src/coreclr/src/vm/comsynchronizable.cpp @@ -1283,14 +1283,13 @@ void QCALLTYPE ThreadNative::InformThreadNameChange(QCall::ThreadHandle thread, 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 + // Will also show up in Linux in gdb and such. if (len > 0 && name != NULL && pThread->GetThreadHandle() != INVALID_HANDLE_VALUE) { SetThreadName(pThread->GetThreadHandle(), name); } -#endif #ifdef PROFILING_SUPPORTED { diff --git a/src/coreclr/src/vm/threads.cpp b/src/coreclr/src/vm/threads.cpp index 23d9623..32aa0be 100644 --- a/src/coreclr/src/vm/threads.cpp +++ b/src/coreclr/src/vm/threads.cpp @@ -2064,9 +2064,9 @@ BOOL Thread::CreateNewThread(SIZE_T stackSize, LPTHREAD_START_ROUTINE start, voi bRet = CreateNewOSThread(stackSize, start, args); #ifndef FEATURE_PAL UndoRevert(bReverted, token); +#endif // !FEATURE_PAL if (pName != NULL) SetThreadName(m_ThreadHandle, pName); -#endif // !FEATURE_PAL return bRet; } @@ -2123,9 +2123,8 @@ HANDLE Thread::CreateUtilityThread(Thread::StackSizeBucket stackSizeBucket, LPTH DWORD threadId; HANDLE hThread = CreateThread(NULL, stackSize, start, args, flags, &threadId); -#ifndef FEATURE_PAL + SetThreadName(hThread, pName); -#endif // !FEATURE_PAL if (pThreadId) diff --git a/src/coreclr/src/vm/win32threadpool.cpp b/src/coreclr/src/vm/win32threadpool.cpp index 0f50ae8..8ee0b15 100644 --- a/src/coreclr/src/vm/win32threadpool.cpp +++ b/src/coreclr/src/vm/win32threadpool.cpp @@ -1824,9 +1824,8 @@ Thread* ThreadpoolMgr::CreateUnimpersonatedThread(LPTHREAD_START_ROUTINE lpStart lpThreadArgs, // arguments CREATE_SUSPENDED, &threadId); -#ifndef FEATURE_PAL + SetThreadName(threadHandle, W(".NET ThreadPool Worker")); -#endif // !FEATURE_PAL if (threadHandle != NULL) lpThreadArgs.SuppressRelease(); } -- 2.7.4