windows: first shot at naming threads with SetThreadDescription().
authorRyan C. Gordon <icculus@icculus.org>
Fri, 27 Jan 2017 20:50:30 -0500
changeset 10857d2843a5e3d3a
parent 10856 486aa38c6a88
child 10858 917613c45753
windows: first shot at naming threads with SetThreadDescription().

This is a bleeding edge API, added to Windows 10 Anniversary Edition (build
1607, specifically).

https://msdn.microsoft.com/en-us/library/windows/desktop/mt774976(v=vs.85).aspx

Nothing supports this yet, including WinDbg, Visual Studio, minidumps, etc,
so we still need to also use the RaiseException hack. But presumably tools
will use this API as a more robust and universal way to get thread names
sooner or later, so we'll start broadcasting to it now.
src/thread/windows/SDL_systhread.c
     1.1 --- a/src/thread/windows/SDL_systhread.c	Fri Jan 27 06:05:50 2017 -0800
     1.2 +++ b/src/thread/windows/SDL_systhread.c	Fri Jan 27 20:50:30 2017 -0500
     1.3 @@ -164,26 +164,53 @@
     1.4  } THREADNAME_INFO;
     1.5  #pragma pack(pop)
     1.6  
     1.7 +
     1.8 +typedef HRESULT (WINAPI *pfnSetThreadDescription)(HANDLE, PCWSTR);
     1.9 +
    1.10  void
    1.11  SDL_SYS_SetupThread(const char *name)
    1.12  {
    1.13 -    if ((name != NULL) && IsDebuggerPresent()) {
    1.14 -        THREADNAME_INFO inf;
    1.15 +    if (name != NULL) {
    1.16 +        static HMODULE kernel32 = 0;
    1.17 +        static pfnSetThreadDescription pSetThreadDescription = NULL;
    1.18  
    1.19 -        /* C# and friends will try to catch this Exception, let's avoid it. */
    1.20 -        if (SDL_GetHintBoolean(SDL_HINT_WINDOWS_DISABLE_THREAD_NAMING, SDL_FALSE)) {
    1.21 -            return;
    1.22 +        if (!kernel32) {
    1.23 +            kernel32 = LoadLibrary(L"kernel32.dll");
    1.24 +            if (kernel32) {
    1.25 +                pSetThreadDescription = (pfnSetThreadDescription) GetProcAddress(kernel32, "SetThreadDescription");
    1.26 +            }
    1.27 +        }
    1.28 +
    1.29 +        if (pSetThreadDescription != NULL) {
    1.30 +            WCHAR *strw = WIN_UTF8ToString(name);
    1.31 +            if (strw) {
    1.32 +                pSetThreadDescription(GetCurrentThread(), strw);
    1.33 +                SDL_free(strw);
    1.34 +            }
    1.35          }
    1.36  
    1.37 -        /* This magic tells the debugger to name a thread if it's listening. */
    1.38 -        SDL_zero(inf);
    1.39 -        inf.dwType = 0x1000;
    1.40 -        inf.szName = name;
    1.41 -        inf.dwThreadID = (DWORD) -1;
    1.42 -        inf.dwFlags = 0;
    1.43 +        /* Presumably some version of Visual Studio will understand SetThreadDescription(),
    1.44 +           but we still need to deal with older OSes and debuggers. Set it with the arcane
    1.45 +           exception magic, too. */
    1.46 +
    1.47 +        if (IsDebuggerPresent()) {
    1.48 +            THREADNAME_INFO inf;
    1.49  
    1.50 -        /* The debugger catches this, renames the thread, continues on. */
    1.51 -        RaiseException(0x406D1388, 0, sizeof(inf) / sizeof(ULONG), (const ULONG_PTR*) &inf);
    1.52 +            /* C# and friends will try to catch this Exception, let's avoid it. */
    1.53 +            if (SDL_GetHintBoolean(SDL_HINT_WINDOWS_DISABLE_THREAD_NAMING, SDL_FALSE)) {
    1.54 +                return;
    1.55 +            }
    1.56 +
    1.57 +            /* This magic tells the debugger to name a thread if it's listening. */
    1.58 +            SDL_zero(inf);
    1.59 +            inf.dwType = 0x1000;
    1.60 +            inf.szName = name;
    1.61 +            inf.dwThreadID = (DWORD) -1;
    1.62 +            inf.dwFlags = 0;
    1.63 +
    1.64 +            /* The debugger catches this, renames the thread, continues on. */
    1.65 +            RaiseException(0x406D1388, 0, sizeof(inf) / sizeof(ULONG), (const ULONG_PTR*) &inf);
    1.66 +        }
    1.67      }
    1.68  }
    1.69