From: Jay Krell Date: Thu, 1 Aug 2019 13:53:41 +0000 (-0700) Subject: Support proper Windows kernel Unicode thread names. (mono/mono#15919) X-Git-Tag: submit/tizen/20210909.063632~10331^2~5^2~879 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=fbba842459a3a6129a47495c3f4e79276559043a;p=platform%2Fupstream%2Fdotnet%2Fruntime.git Support proper Windows kernel Unicode thread names. (mono/mono#15919) These do not require a debugger, can be retrieved, appear in ETW, etc. Extracted from https://github.com/mono/mono/pull/15859. Commit migrated from https://github.com/mono/mono/commit/a7b74fc69c8c42911c5406bceca35220c87fccc4 --- diff --git a/src/mono/mono/metadata/sgen-mono.c b/src/mono/mono/metadata/sgen-mono.c index d5a95be..61d019d 100644 --- a/src/mono/mono/metadata/sgen-mono.c +++ b/src/mono/mono/metadata/sgen-mono.c @@ -2123,6 +2123,7 @@ sgen_client_thread_register_worker (void) { mono_thread_info_register_small_id (); mono_native_thread_set_name (mono_native_thread_id_get (), "SGen worker"); + mono_thread_set_name_windows (GetCurrentThread (), L"SGen worker"); } /* Variables holding start/end nursery so it won't have to be passed at every call */ diff --git a/src/mono/mono/metadata/threads-types.h b/src/mono/mono/metadata/threads-types.h index 172c48d..4e96f99 100644 --- a/src/mono/mono/metadata/threads-types.h +++ b/src/mono/mono/metadata/threads-types.h @@ -325,6 +325,20 @@ MONO_API MonoException* mono_thread_get_undeniable_exception (void); ICALL_EXPORT void ves_icall_thread_finish_async_abort (void); +#if HOST_WIN32 + +void +mono_thread_set_name_windows (HANDLE thread_handle, PCWSTR thread_name); + +#define MONO_THREAD_NAME_WINDOWS_CONSTANT(x) L ## x + +#else + +#define mono_thread_set_name_windows(thread_handle, thread_name) /* nothing */ + +#define MONO_THREAD_NAME_WINDOWS_CONSTANT(x) NULL + +#endif typedef enum { MonoSetThreadNameFlag_None = 0x0000, diff --git a/src/mono/mono/metadata/threads.c b/src/mono/mono/metadata/threads.c index 9584d05..00a9f27 100644 --- a/src/mono/mono/metadata/threads.c +++ b/src/mono/mono/metadata/threads.c @@ -1899,6 +1899,8 @@ mono_thread_set_name_internal (MonoInternalThread *this_obj, mono_native_thread_set_name (tid, tname); mono_free (tname); } + + mono_thread_set_name_windows (this_obj->native_handle, name ? mono_string_chars_internal (name) : NULL); } void diff --git a/src/mono/mono/metadata/w32subset.h b/src/mono/mono/metadata/w32subset.h index c3be134..d2035bd 100644 --- a/src/mono/mono/metadata/w32subset.h +++ b/src/mono/mono/metadata/w32subset.h @@ -210,3 +210,24 @@ #define HAVE_API_SUPPORT_WIN32_IS_WOW64_PROCESS 0 #endif #endif + +#ifndef HAVE_LOADLIBRARY +#if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT) +#define HAVE_LOADLIBRARY 1 +#else +#define HAVE_LOADLIBRARY 0 +#endif +#endif + +#ifndef HAVE_SET_THREAD_DESCRIPTION +#define HAVE_SET_THREAD_DESCRIPTION 0 +#endif + +#ifndef HAVE_SET_THREAD_NAME +// https://github.com/microsoft/xbox-live-api/blob/90b38b434d9c13ce4916c116cd28a98b239e38e2/InProgressSamples/Kits/ATGTK/ThreadHelpers.h#L21 +#if defined(_XBOX_ONE) && defined(_TITLE) +#define HAVE_SET_THREAD_NAME 1 +#else +#define HAVE_SET_THREAD_NAME 0 +#endif +#endif diff --git a/src/mono/mono/utils/Makefile.am b/src/mono/mono/utils/Makefile.am index 19a65eb..c870dac 100644 --- a/src/mono/mono/utils/Makefile.am +++ b/src/mono/mono/utils/Makefile.am @@ -41,9 +41,10 @@ endif if HOST_WIN32 win32_sources = \ - os-event-win32.c \ + mono-os-semaphore-win32.c \ mono-os-wait-win32.c \ - mono-os-semaphore-win32.c + mono-windows-thread-name.c \ + os-event-win32.c platform_sources = $(win32_sources) else diff --git a/src/mono/mono/utils/mono-threads-windows.c b/src/mono/mono/utils/mono-threads-windows.c index 4c0f162..5614f23 100644 --- a/src/mono/mono/utils/mono-threads-windows.c +++ b/src/mono/mono/utils/mono-threads-windows.c @@ -563,38 +563,6 @@ mono_thread_info_get_system_max_stack_size (void) return INT_MAX; } -#if defined(_MSC_VER) -const DWORD MS_VC_EXCEPTION=0x406D1388; -#pragma pack(push,8) -typedef struct tagTHREADNAME_INFO -{ - DWORD dwType; // Must be 0x1000. - LPCSTR szName; // Pointer to name (in user addr space). - DWORD dwThreadID; // Thread ID (-1=caller thread). - DWORD dwFlags; // Reserved for future use, must be zero. -} THREADNAME_INFO; -#pragma pack(pop) -#endif - -void -mono_native_thread_set_name (MonoNativeThreadId tid, const char *name) -{ -#if defined(_MSC_VER) - /* http://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx */ - THREADNAME_INFO info; - info.dwType = 0x1000; - info.szName = name; - info.dwThreadID = tid; - info.dwFlags = 0; - - __try { - RaiseException( MS_VC_EXCEPTION, 0, sizeof(info)/sizeof(ULONG_PTR), (ULONG_PTR*)&info ); - } - __except(EXCEPTION_EXECUTE_HANDLER) { - } -#endif -} - void mono_memory_barrier_process_wide (void) { diff --git a/src/mono/mono/utils/mono-windows-thread-name.c b/src/mono/mono/utils/mono-windows-thread-name.c new file mode 100644 index 0000000..efd42eb --- /dev/null +++ b/src/mono/mono/utils/mono-windows-thread-name.c @@ -0,0 +1,149 @@ +// mono-windows-thread-name.c +// +// There several ways to set thread name on Windows. +// +// Historically: Raise an exception with an ASCII string. +// This is visible only in a debugger. Only if a debugger +// is running when the exception is raised. There is +// no way to get the thread name and they do not appear in ETW traces. +// +// XboxOne: SetThreadName(thread handle, unicode) +// This works with or without a debugger and can be retrieved with GetThreadName. +// Sometimes an inline function SetThreadDescription for source compat with next. +// https://github.com/microsoft/xbox-live-api/blob/90b38b434d9c13ce4916c116cd28a98b239e38e2/InProgressSamples/Kits/ATGTK/ThreadHelpers.h#L21 +// +// Windows 10 1607 or newer (according to documentation, or Creators Update says https://randomascii.wordpress.com/2015/10/26/thread-naming-in-windows-time-for-something-better). +// SetThreadDescription(thread handle, unicode) +// This is like XboxOne -- works with or without debugger, can be retrieved +// with GetThreadDescription, and appears in ETW traces. +// See https://randomascii.wordpress.com/2015/10/26/thread-naming-in-windows-time-for-something-better. +// +// This is not called SetThreadName to avoid breaking compilation of C (but not C++) +// copied from http://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx. +// +// UWP: Also SetThreadDescription, but running prior to 1607 (or Creators Update per above). +// would require LoadLibrary / GetProcAddress, but LoadLibrary is not allowed. +// +// Author: +// Jay Krell (jaykrell@microsoft.com) +// +// Copyright 2019 Microsoft +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// +#include "config.h" +#include "mono-threads.h" + +#if HOST_WIN32 + +#include "mono/metadata/w32subset.h" + +// This is compiler specific because of the use of __try / __except. +#if _MSC_VER +const DWORD MS_VC_EXCEPTION = 0x406D1388; +#pragma pack(push,8) +typedef struct tagTHREADNAME_INFO +{ + DWORD dwType; // Must be 0x1000. + PCSTR szName; // Pointer to name (in user addr space). + DWORD dwThreadID; // Thread ID (-1=caller thread). + DWORD dwFlags; // Reserved for future use, must be zero. +} THREADNAME_INFO; +#pragma pack(pop) +#endif + +void +mono_native_thread_set_name (MonoNativeThreadId tid, const char *name) +{ +// This is compiler specific because of the use of __try / __except. +#if _MSC_VER + // http://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx + THREADNAME_INFO info = {0x1000, name, tid, 0}; + + // Checking for IsDebuggerPresent here would be reasonable, for + // efficiency, and would let this work with other compilers (without + // structured exception handling support), however + // there is a race condition then, in that a debugger + // can be detached (and attached) at any time. + // + // A vectored exception handler could also be used to handle this exception. + + __try { + RaiseException (MS_VC_EXCEPTION, 0, sizeof (info) / sizeof (ULONG_PTR), (ULONG_PTR*)&info); + } __except (EXCEPTION_EXECUTE_HANDLER) { + } +#endif +} + +#if HAVE_SET_THREAD_NAME + +void +mono_thread_set_name_windows (HANDLE thread_handle, PCWSTR thread_name) +{ + SetThreadName (thread_handle, thread_name); +} + +#elif HAVE_SET_THREAD_DESCRIPTION + +void +mono_thread_set_name_windows (HANDLE thread_handle, PCWSTR thread_name) +{ + SetThreadDescription (thread_handle, thread_name); +} + +#elif HAVE_LOADLIBRARY + +typedef +HRESULT +(__stdcall * MonoSetThreadDescription_t) (HANDLE thread_handle, PCWSTR thread_name); + +static +HRESULT +__stdcall +mono_thread_set_name_windows_fallback_nop (HANDLE thread_handle, PCWSTR thread_name) +{ + // This function is called on older systems, when LoadLibrary / GetProcAddress fail. + return 0; +} + +static +HRESULT +__stdcall +mono_thread_set_name_windows_init (HANDLE thread_handle, PCWSTR thread_name); + +static MonoSetThreadDescription_t set_thread_description = mono_thread_set_name_windows_init; + +static +HRESULT +__stdcall +mono_thread_set_name_windows_init (HANDLE thread_handle, PCWSTR thread_name) +{ + // This function is called the first time mono_thread_set_name_windows is called + // to LoadLibrary / GetProcAddress. + // + // Do not write NULL to global, that is racy. + MonoSetThreadDescription_t local = NULL; + const HMODULE kernel32 = LoadLibraryExW (L"kernel32.dll", NULL, LOAD_LIBRARY_SEARCH_SYSTEM32); + if (kernel32) + local = (MonoSetThreadDescription_t)GetProcAddress (kernel32, "SetThreadDescription"); + if (!local) + local = mono_thread_set_name_windows_fallback_nop; + set_thread_description = local; + return local (thread_handle, thread_name); +} + +void +mono_thread_set_name_windows (HANDLE thread_handle, PCWSTR thread_name) +{ + (void)set_thread_description (thread_handle, thread_name); +} + +#else // nothing + +void +mono_thread_set_name_windows (HANDLE thread_handle, PCWSTR thread_name) +{ +} + +#endif + +#endif // Win32 diff --git a/src/mono/msvc/libmonoutils-win32.targets b/src/mono/msvc/libmonoutils-win32.targets index 2c237d9..7691abc 100644 --- a/src/mono/msvc/libmonoutils-win32.targets +++ b/src/mono/msvc/libmonoutils-win32.targets @@ -4,5 +4,6 @@ + diff --git a/src/mono/msvc/libmonoutils-win32.targets.filters b/src/mono/msvc/libmonoutils-win32.targets.filters index eab5c88..197e374 100644 --- a/src/mono/msvc/libmonoutils-win32.targets.filters +++ b/src/mono/msvc/libmonoutils-win32.targets.filters @@ -10,6 +10,9 @@ Source Files$(MonoUtilsFilterSubFolder)\win32 + + Source Files$(MonoUtilsFilterSubFolder)\win32 +