summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/systhread.c70
-rw-r--r--src/thread.c6
-rw-r--r--src/thread.h4
-rw-r--r--src/w32fns.c16
4 files changed, 91 insertions, 5 deletions
diff --git a/src/systhread.c b/src/systhread.c
index 6f4de536fba..baa30751c79 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 e2deadd7a83..42c2bf52d28 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 498b9909c9f..2b85f0893e7 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 4ef075f715b..bf2a7a3e54e 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