aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorEli Zaretskii2019-12-20 20:59:07 +0200
committerEli Zaretskii2019-12-20 20:59:07 +0200
commit0e19b5d757d88eedd23709a4ea40aa1512a1ff21 (patch)
tree5ab479668337f979c29e41e9254fa609d463391c /src
parent85a60da92d4db5c87ecfa152501d246425550fc3 (diff)
downloademacs-0e19b5d757d88eedd23709a4ea40aa1512a1ff21.tar.gz
emacs-0e19b5d757d88eedd23709a4ea40aa1512a1ff21.zip
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.
Diffstat (limited to 'src')
-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)
248 248
249#elif defined (WINDOWSNT) 249#elif defined (WINDOWSNT)
250 250
251#include <w32term.h> 251#include <mbctype.h>
252#include "w32term.h"
252 253
253/* Cannot include <process.h> because of the local header by the same 254/* Cannot include <process.h> because of the local header by the same
254 name, sigh. */ 255 name, sigh. */
@@ -390,6 +391,65 @@ sys_thread_equal (sys_thread_t t, sys_thread_t u)
390 return t == u; 391 return t == u;
391} 392}
392 393
394/* Special exception used to communicate with a debugger. The name is
395 taken from example code shown on MSDN. */
396#define MS_VC_EXCEPTION 0x406d1388UL
397
398/* Structure used to communicate thread name to a debugger. */
399typedef struct _THREADNAME_INFO
400{
401 DWORD_PTR type;
402 LPCSTR name;
403 DWORD_PTR thread_id;
404 DWORD_PTR reserved;
405} THREADNAME_INFO;
406
407typedef BOOL (WINAPI *IsDebuggerPresent_Proc) (void);
408extern IsDebuggerPresent_Proc is_debugger_present;
409extern int (WINAPI *pMultiByteToWideChar)(UINT,DWORD,LPCSTR,int,LPWSTR,int);
410typedef HRESULT (WINAPI *SetThreadDescription_Proc)
411 (HANDLE hThread, PCWSTR lpThreadDescription);
412extern SetThreadDescription_Proc set_thread_description;
413
414/* Set the name of the thread identified by its thread ID. */
415static void
416w32_set_thread_name (DWORD thread_id, const char *name)
417{
418 if (!name || !*name)
419 return;
420
421 /* Use the new API provided since Windows 10, if available. */
422 if (set_thread_description)
423 {
424 /* GDB pulls only the first 1024 characters of thread's name. */
425 wchar_t name_w[1025];
426 /* The thread name is encoded in locale's encoding, but
427 SetThreadDescription wants a wchar_t string. */
428 int codepage = _getmbcp ();
429 if (!codepage)
430 codepage = GetACP ();
431 int cnv_result = pMultiByteToWideChar (codepage, MB_ERR_INVALID_CHARS,
432 name, -1,
433 name_w, 1025);
434 if (cnv_result
435 && set_thread_description (GetCurrentThread (), name_w) == S_OK)
436 return;
437 }
438 /* We can only support this fallback method when Emacs is being
439 debugged. */
440 if (!(is_debugger_present && is_debugger_present ()))
441 return;
442
443 THREADNAME_INFO tninfo;
444
445 tninfo.type = 0x1000; /* magic constant */
446 tninfo.name = name;
447 tninfo.thread_id = thread_id;
448 tninfo.reserved = 0;
449 RaiseException (MS_VC_EXCEPTION, 0, sizeof (tninfo) / sizeof (ULONG_PTR),
450 (ULONG_PTR *) &tninfo);
451}
452
393static thread_creation_function *thread_start_address; 453static thread_creation_function *thread_start_address;
394 454
395/* _beginthread wants a void function, while we are passed a function 455/* _beginthread wants a void function, while we are passed a function
@@ -398,6 +458,14 @@ static thread_creation_function *thread_start_address;
398static void ALIGN_STACK 458static void ALIGN_STACK
399w32_beginthread_wrapper (void *arg) 459w32_beginthread_wrapper (void *arg)
400{ 460{
461 /* FIXME: This isn't very clean: systhread.c is not supposed to know
462 that ARG is a pointer to a thread_state object, or be familiar
463 with thread_state object's structure in general. */
464 struct thread_state *this_thread = arg;
465
466 if (this_thread->thread_name)
467 w32_set_thread_name (GetCurrentThreadId (), this_thread->thread_name);
468
401 (void)thread_start_address (arg); 469 (void)thread_start_address (arg);
402} 470}
403 471
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)
756 } 756 }
757 } 757 }
758 758
759 xfree (self->thread_name);
760
759 current_thread = NULL; 761 current_thread = NULL;
760 sys_cond_broadcast (&self->thread_condvar); 762 sys_cond_broadcast (&self->thread_condvar);
761 763
@@ -825,6 +827,10 @@ If NAME is given, it must be a string; it names the new thread. */)
825 all_threads = new_thread; 827 all_threads = new_thread;
826 828
827 char const *c_name = !NILP (name) ? SSDATA (ENCODE_UTF_8 (name)) : NULL; 829 char const *c_name = !NILP (name) ? SSDATA (ENCODE_UTF_8 (name)) : NULL;
830 if (c_name)
831 new_thread->thread_name = xstrdup (c_name);
832 else
833 new_thread->thread_name = NULL;
828 sys_thread_t thr; 834 sys_thread_t thr;
829 if (! sys_thread_create (&thr, c_name, run_thread, new_thread)) 835 if (! sys_thread_create (&thr, c_name, run_thread, new_thread))
830 { 836 {
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
169 interrupter should broadcast to this condition. */ 169 interrupter should broadcast to this condition. */
170 sys_cond_t *wait_condvar; 170 sys_cond_t *wait_condvar;
171 171
172 /* Thread's name in the locale encoding. Actually used only on
173 WINDOWSNT. */
174 char *thread_name;
175
172 /* This thread might have released the global lock. If so, this is 176 /* This thread might have released the global lock. If so, this is
173 non-zero. When a thread runs outside thread_select with this 177 non-zero. When a thread runs outside thread_select with this
174 flag non-zero, it means it has been interrupted by SIGINT while 178 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)
178typedef BOOL (WINAPI * GetTitleBarInfo_Proc) 178typedef BOOL (WINAPI * GetTitleBarInfo_Proc)
179 (IN HWND hwnd, OUT TITLEBAR_INFO* info); 179 (IN HWND hwnd, OUT TITLEBAR_INFO* info);
180 180
181typedef BOOL (WINAPI *IsDebuggerPresent_Proc) (void);
182typedef HRESULT (WINAPI *SetThreadDescription_Proc)
183 (HANDLE hThread, PCWSTR lpThreadDescription);
184
181TrackMouseEvent_Proc track_mouse_event_fn = NULL; 185TrackMouseEvent_Proc track_mouse_event_fn = NULL;
182ImmGetCompositionString_Proc get_composition_string_fn = NULL; 186ImmGetCompositionString_Proc get_composition_string_fn = NULL;
183ImmGetContext_Proc get_ime_context_fn = NULL; 187ImmGetContext_Proc get_ime_context_fn = NULL;
@@ -188,6 +192,8 @@ GetMonitorInfo_Proc get_monitor_info_fn = NULL;
188MonitorFromWindow_Proc monitor_from_window_fn = NULL; 192MonitorFromWindow_Proc monitor_from_window_fn = NULL;
189EnumDisplayMonitors_Proc enum_display_monitors_fn = NULL; 193EnumDisplayMonitors_Proc enum_display_monitors_fn = NULL;
190GetTitleBarInfo_Proc get_title_bar_info_fn = NULL; 194GetTitleBarInfo_Proc get_title_bar_info_fn = NULL;
195IsDebuggerPresent_Proc is_debugger_present = NULL;
196SetThreadDescription_Proc set_thread_description = NULL;
191 197
192extern AppendMenuW_Proc unicode_append_menu; 198extern AppendMenuW_Proc unicode_append_menu;
193 199
@@ -284,8 +290,6 @@ static struct
284} kbdhook; 290} kbdhook;
285typedef HWND (WINAPI *GetConsoleWindow_Proc) (void); 291typedef HWND (WINAPI *GetConsoleWindow_Proc) (void);
286 292
287typedef BOOL (WINAPI *IsDebuggerPresent_Proc) (void);
288
289/* stdin, from w32console.c */ 293/* stdin, from w32console.c */
290extern HANDLE keyboard_handle; 294extern HANDLE keyboard_handle;
291 295
@@ -2737,8 +2741,6 @@ setup_w32_kbdhook (void)
2737 hook if the process is being debugged. */ 2741 hook if the process is being debugged. */
2738 if (w32_kbdhook_active) 2742 if (w32_kbdhook_active)
2739 { 2743 {
2740 IsDebuggerPresent_Proc is_debugger_present = (IsDebuggerPresent_Proc)
2741 get_proc_addr (GetModuleHandle ("kernel32.dll"), "IsDebuggerPresent");
2742 if (is_debugger_present && is_debugger_present ()) 2744 if (is_debugger_present && is_debugger_present ())
2743 return; 2745 return;
2744 } 2746 }
@@ -11031,6 +11033,12 @@ globals_of_w32fns (void)
11031 get_proc_addr (imm32_lib, "ImmSetCompositionWindow"); 11033 get_proc_addr (imm32_lib, "ImmSetCompositionWindow");
11032 } 11034 }
11033 11035
11036 HMODULE hm_kernel32 = GetModuleHandle ("kernel32.dll");
11037 is_debugger_present = (IsDebuggerPresent_Proc)
11038 get_proc_addr (hm_kernel32, "IsDebuggerPresent");
11039 set_thread_description = (SetThreadDescription_Proc)
11040 get_proc_addr (hm_kernel32, "SetThreadDescription");
11041
11034 except_code = 0; 11042 except_code = 0;
11035 except_addr = 0; 11043 except_addr = 0;
11036#ifndef CYGWIN 11044#ifndef CYGWIN