emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

master 0e19b5d: Support setting OS names of threads on MS-Windows


From: Eli Zaretskii
Subject: master 0e19b5d: Support setting OS names of threads on MS-Windows
Date: Fri, 20 Dec 2019 14:00:02 -0500 (EST)

branch: master
commit 0e19b5d757d88eedd23709a4ea40aa1512a1ff21
Author: Eli Zaretskii <address@hidden>
Commit: Eli Zaretskii <address@hidden>

    Support setting OS names of threads on MS-Windows
    
    * src/w32fns.c (setup_w32_kbdhook): Don't initialize
    is_debugger_present here...
    (globals_of_w32fns): ...initialize it here.  Also initialize
    the new global variable set_thread_description.
    * src/systhread.c: [WINDOWSNT] Include mbctype.h
    (w32_set_thread_name): New function.
    (MS_VC_EXCEPTION): New macro.
    (THREADNAME_INFO, IsDebuggerPresent_Proc)
    (SetThreadDescription_Proc): New typedefs.
    (w32_beginthread_wrapper): Call w32_set_thread_name to set the
    name of the new thread.
    * src/thread.h (struct thread_state): New member thread_name.
    * src/thread.c (Fmake_thread): Set the thread_name field of
    the new thread object.
    (run_thread): Free the thread_name member after the thread
    exits.
---
 src/systhread.c | 70 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 src/thread.c    |  6 +++++
 src/thread.h    |  4 ++++
 src/w32fns.c    | 16 +++++++++----
 4 files changed, 91 insertions(+), 5 deletions(-)

diff --git a/src/systhread.c b/src/systhread.c
index 6f4de53..baa3075 100644
--- a/src/systhread.c
+++ b/src/systhread.c
@@ -248,7 +248,8 @@ sys_thread_yield (void)
 
 #elif defined (WINDOWSNT)
 
-#include <w32term.h>
+#include <mbctype.h>
+#include "w32term.h"
 
 /* Cannot include <process.h> because of the local header by the same
    name, sigh.  */
@@ -390,6 +391,65 @@ sys_thread_equal (sys_thread_t t, sys_thread_t u)
   return t == u;
 }
 
+/* Special exception used to communicate with a debugger.  The name is
+   taken from example code shown on MSDN.  */
+#define MS_VC_EXCEPTION 0x406d1388UL
+
+/* Structure used to communicate thread name to a debugger.  */
+typedef struct _THREADNAME_INFO
+{
+  DWORD_PTR  type;
+  LPCSTR name;
+  DWORD_PTR  thread_id;
+  DWORD_PTR  reserved;
+} THREADNAME_INFO;
+
+typedef BOOL (WINAPI *IsDebuggerPresent_Proc) (void);
+extern IsDebuggerPresent_Proc is_debugger_present;
+extern int (WINAPI *pMultiByteToWideChar)(UINT,DWORD,LPCSTR,int,LPWSTR,int);
+typedef HRESULT (WINAPI *SetThreadDescription_Proc)
+  (HANDLE hThread, PCWSTR lpThreadDescription);
+extern SetThreadDescription_Proc set_thread_description;
+
+/* Set the name of the thread identified by its thread ID.  */
+static void
+w32_set_thread_name (DWORD thread_id, const char *name)
+{
+  if (!name || !*name)
+    return;
+
+  /* Use the new API provided since Windows 10, if available.  */
+  if (set_thread_description)
+    {
+      /* GDB pulls only the first 1024 characters of thread's name.  */
+      wchar_t name_w[1025];
+      /* The thread name is encoded in locale's encoding, but
+        SetThreadDescription wants a wchar_t string.  */
+      int codepage = _getmbcp ();
+      if (!codepage)
+       codepage = GetACP ();
+      int cnv_result = pMultiByteToWideChar (codepage, MB_ERR_INVALID_CHARS,
+                                            name, -1,
+                                            name_w, 1025);
+      if (cnv_result
+         && set_thread_description (GetCurrentThread (), name_w) == S_OK)
+       return;
+    }
+  /* We can only support this fallback method when Emacs is being
+     debugged.  */
+  if (!(is_debugger_present && is_debugger_present ()))
+    return;
+
+  THREADNAME_INFO tninfo;
+
+  tninfo.type = 0x1000;        /* magic constant */
+  tninfo.name = name;
+  tninfo.thread_id = thread_id;
+  tninfo.reserved = 0;
+  RaiseException (MS_VC_EXCEPTION, 0, sizeof (tninfo) / sizeof (ULONG_PTR),
+                 (ULONG_PTR *) &tninfo);
+}
+
 static thread_creation_function *thread_start_address;
 
 /* _beginthread wants a void function, while we are passed a function
@@ -398,6 +458,14 @@ static thread_creation_function *thread_start_address;
 static void ALIGN_STACK
 w32_beginthread_wrapper (void *arg)
 {
+  /* FIXME: This isn't very clean: systhread.c is not supposed to know
+     that ARG is a pointer to a thread_state object, or be familiar
+     with thread_state object's structure in general.  */
+  struct thread_state *this_thread = arg;
+
+  if (this_thread->thread_name)
+    w32_set_thread_name (GetCurrentThreadId (), this_thread->thread_name);
+
   (void)thread_start_address (arg);
 }
 
diff --git a/src/thread.c b/src/thread.c
index e2deadd..42c2bf5 100644
--- a/src/thread.c
+++ b/src/thread.c
@@ -756,6 +756,8 @@ run_thread (void *state)
       }
   }
 
+  xfree (self->thread_name);
+
   current_thread = NULL;
   sys_cond_broadcast (&self->thread_condvar);
 
@@ -825,6 +827,10 @@ If NAME is given, it must be a string; it names the new 
thread.  */)
   all_threads = new_thread;
 
   char const *c_name = !NILP (name) ? SSDATA (ENCODE_UTF_8 (name)) : NULL;
+  if (c_name)
+    new_thread->thread_name = xstrdup (c_name);
+  else
+    new_thread->thread_name = NULL;
   sys_thread_t thr;
   if (! sys_thread_create (&thr, c_name, run_thread, new_thread))
     {
diff --git a/src/thread.h b/src/thread.h
index 498b990..2b85f08 100644
--- a/src/thread.h
+++ b/src/thread.h
@@ -169,6 +169,10 @@ struct thread_state
      interrupter should broadcast to this condition.  */
   sys_cond_t *wait_condvar;
 
+  /* Thread's name in the locale encoding.  Actually used only on
+     WINDOWSNT.  */
+  char *thread_name;
+
   /* This thread might have released the global lock.  If so, this is
      non-zero.  When a thread runs outside thread_select with this
      flag non-zero, it means it has been interrupted by SIGINT while
diff --git a/src/w32fns.c b/src/w32fns.c
index 4ef075f..bf2a7a3 100644
--- a/src/w32fns.c
+++ b/src/w32fns.c
@@ -178,6 +178,10 @@ typedef BOOL (WINAPI * EnumDisplayMonitors_Proc)
 typedef BOOL (WINAPI * GetTitleBarInfo_Proc)
   (IN HWND hwnd, OUT TITLEBAR_INFO* info);
 
+typedef BOOL (WINAPI *IsDebuggerPresent_Proc) (void);
+typedef HRESULT (WINAPI *SetThreadDescription_Proc)
+  (HANDLE hThread, PCWSTR lpThreadDescription);
+
 TrackMouseEvent_Proc track_mouse_event_fn = NULL;
 ImmGetCompositionString_Proc get_composition_string_fn = NULL;
 ImmGetContext_Proc get_ime_context_fn = NULL;
@@ -188,6 +192,8 @@ GetMonitorInfo_Proc get_monitor_info_fn = NULL;
 MonitorFromWindow_Proc monitor_from_window_fn = NULL;
 EnumDisplayMonitors_Proc enum_display_monitors_fn = NULL;
 GetTitleBarInfo_Proc get_title_bar_info_fn = NULL;
+IsDebuggerPresent_Proc is_debugger_present = NULL;
+SetThreadDescription_Proc set_thread_description = NULL;
 
 extern AppendMenuW_Proc unicode_append_menu;
 
@@ -284,8 +290,6 @@ static struct
 } kbdhook;
 typedef HWND (WINAPI *GetConsoleWindow_Proc) (void);
 
-typedef BOOL (WINAPI *IsDebuggerPresent_Proc) (void);
-
 /* stdin, from w32console.c */
 extern HANDLE keyboard_handle;
 
@@ -2737,8 +2741,6 @@ setup_w32_kbdhook (void)
      hook if the process is being debugged. */
   if (w32_kbdhook_active)
     {
-      IsDebuggerPresent_Proc is_debugger_present = (IsDebuggerPresent_Proc)
-       get_proc_addr (GetModuleHandle ("kernel32.dll"), "IsDebuggerPresent");
       if (is_debugger_present && is_debugger_present ())
        return;
     }
@@ -11031,6 +11033,12 @@ globals_of_w32fns (void)
       get_proc_addr (imm32_lib, "ImmSetCompositionWindow");
   }
 
+  HMODULE hm_kernel32 = GetModuleHandle ("kernel32.dll");
+  is_debugger_present = (IsDebuggerPresent_Proc)
+    get_proc_addr (hm_kernel32, "IsDebuggerPresent");
+  set_thread_description = (SetThreadDescription_Proc)
+    get_proc_addr (hm_kernel32, "SetThreadDescription");
+
   except_code = 0;
   except_addr = 0;
 #ifndef CYGWIN



reply via email to

[Prev in Thread] Current Thread [Next in Thread]