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.
This commit is contained in:
parent
85a60da92d
commit
0e19b5d757
4 changed files with 91 additions and 5 deletions
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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))
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
|
16
src/w32fns.c
16
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
|
||||
|
|
Loading…
Add table
Reference in a new issue