diff --git a/src/include/86box/plat.h b/src/include/86box/plat.h index 0d5b17a3c..1f5f2b695 100644 --- a/src/include/86box/plat.h +++ b/src/include/86box/plat.h @@ -149,6 +149,7 @@ extern uint32_t plat_language_code(char *langcode); extern void plat_language_code_r(uint32_t lcid, char *outbuf, int len); extern void plat_get_cpu_string(char *outbuf, uint8_t len); extern double plat_get_dpi(void); +extern void plat_set_thread_name(void *thread, const char *name); /* Resource management. */ extern void set_language(uint32_t id); diff --git a/src/include/86box/thread.h b/src/include/86box/thread.h index 4d5584787..a71d03913 100644 --- a/src/include/86box/thread.h +++ b/src/include/86box/thread.h @@ -28,7 +28,7 @@ extern "C" { # define event_t plat_event_t # define mutex_t plat_mutex_t -# define thread_create plat_thread_create +# define thread_create_named plat_thread_create_named # define thread_wait plat_thread_wait # define thread_create_event plat_thread_create_event # define thread_set_event plat_thread_set_event @@ -48,7 +48,8 @@ typedef void thread_t; typedef void event_t; typedef void mutex_t; -extern thread_t *thread_create(void (*thread_func)(void *param), void *param); +#define thread_create(thread_func, param) thread_create_named((thread_func), (param), #thread_func) +extern thread_t *thread_create_named(void (*thread_func)(void *param), void *param, const char *name); extern int thread_wait(thread_t *arg); extern event_t *thread_create_event(void); extern void thread_set_event(event_t *arg); diff --git a/src/qt/qt_main.cpp b/src/qt/qt_main.cpp index 409a63248..4d02e2601 100644 --- a/src/qt/qt_main.cpp +++ b/src/qt/qt_main.cpp @@ -94,6 +94,7 @@ main_thread_fn() int frames; QThread::currentThread()->setPriority(QThread::HighestPriority); + plat_set_thread_name(NULL, "main_thread_fn"); framecountx = 0; // title_update = 1; old_time = elapsed_timer.elapsed(); diff --git a/src/qt/qt_platform.cpp b/src/qt/qt_platform.cpp index 7ea28a4ce..62325e780 100644 --- a/src/qt/qt_platform.cpp +++ b/src/qt/qt_platform.cpp @@ -50,6 +50,7 @@ #include "qt_util.hpp" #ifdef Q_OS_UNIX +# include # include #endif @@ -742,3 +743,47 @@ plat_get_dpi(void) { return util::screenOfWidget(main_window)->devicePixelRatio(); } + +void +plat_set_thread_name(void *thread, const char *name) +{ +#ifdef Q_OS_WINDOWS + /* SetThreadDescription was added in 14393. Revisit if we ever start requiring 10. */ + static void *kernel32_handle = NULL; + static HRESULT(WINAPI *pSetThreadDescription)(HANDLE hThread, PCWSTR lpThreadDescription) = NULL; + static dllimp_t kernel32_imports[] = { + // clang-format off + { "SetThreadDescription", &pSetThreadDescription }, + { NULL, NULL } + // clang-format on + }; + + if (!kernel32_handle) { + kernel32_handle = dynld_module("kernel32.dll", kernel32_imports); + if (!kernel32_handle) { + kernel32_handle = kernel32_imports; /* dummy pointer to store that we tried */ + pSetThreadDescription = NULL; + } + } + + if (pSetThreadDescription) { + size_t len = strlen(name) + 1; + wchar_t wname[len]; + mbstowcs(wname, name, len); + pSetThreadDescription(thread ? (HANDLE) thread : GetCurrentThread(), wname); + } +#else +# ifdef Q_OS_DARWIN + char truncated[64]; +# else + char truncated[16]; +# endif + strncpy(truncated, name, sizeof(truncated) - 1); +# ifdef Q_OS_DARWIN + if (!thread) + pthread_setname_np(truncated); +# else + pthread_setname_np(thread ? (pthread_t) thread : pthread_self(), truncated); +# endif +#endif +} diff --git a/src/thread.cpp b/src/thread.cpp index 1b4311f37..f2a0ceaf0 100644 --- a/src/thread.cpp +++ b/src/thread.cpp @@ -14,9 +14,10 @@ struct event_cpp11_t { extern "C" { thread_t * -thread_create(void (*thread_rout)(void *param), void *param) +thread_create_named(void (*thread_rout)(void *param), void *param, const char *name) { - auto thread = new std::thread([thread_rout, param] { + auto thread = new std::thread([thread_rout, param, name] { + plat_set_thread_name(NULL, name); thread_rout(param); }); return thread; diff --git a/src/unix/unix.c b/src/unix/unix.c index cfa824313..bbf7556ba 100644 --- a/src/unix/unix.c +++ b/src/unix/unix.c @@ -45,6 +45,9 @@ #include <86box/ui.h> #include <86box/gdbstub.h> +#define __USE_GNU 1 /* shouldn't be done, yet it is */ +#include + static int first_use = 1; static uint64_t StartingTime; static uint64_t Frequency; @@ -1379,6 +1382,23 @@ plat_get_cpu_string(char *outbuf, uint8_t len) { strncpy(outbuf, cpu_string, len); } +void +plat_set_thread_name(void *thread, const char *name) +{ +#ifdef __APPLE__ + char truncated[64]; +#else + char truncated[16]; +#endif + strncpy(truncated, name, sizeof(truncated) - 1); +#ifdef __APPLE__ + if (!thread) + pthread_setname_np(truncated); +#else + pthread_setname_np(thread ? (pthread_t) thread : pthread_self(), truncated); +#endif +} + /* Converts back the language code to LCID */ void plat_language_code_r(uint32_t lcid, char *outbuf, int len) diff --git a/src/unix/unix_thread.c b/src/unix/unix_thread.c index 0c2e9bf6b..a73d23225 100644 --- a/src/unix/unix_thread.c +++ b/src/unix/unix_thread.c @@ -32,7 +32,7 @@ thread_run_wrapper(thread_param *arg) } thread_t * -thread_create(void (*thread_rout)(void *param), void *param) +thread_create(void (*thread_rout)(void *param), void *param, const char *name) { pthread_t *thread = malloc(sizeof(pthread_t)); thread_param *thrparam = malloc(sizeof(thread_param)); @@ -40,6 +40,7 @@ thread_create(void (*thread_rout)(void *param), void *param) thrparam->param = param; pthread_create(thread, NULL, (void *(*) (void *) ) thread_run_wrapper, thrparam); + plat_set_thread_name(thread, name); return thread; } diff --git a/src/win/win.c b/src/win/win.c index 21ff6646c..7e752f90f 100644 --- a/src/win/win.c +++ b/src/win/win.c @@ -51,6 +51,7 @@ #include <86box/path.h> #define GLOBAL #include <86box/plat.h> +#include <86box/plat_dynld.h> #include <86box/thread.h> #include <86box/ui.h> #ifdef USE_VNC @@ -1276,6 +1277,35 @@ plat_get_cpu_string(char *outbuf, uint8_t len) { strncpy(outbuf, cpu_string, len); } +void +plat_set_thread_name(void *thread, const char *name) +{ + /* SetThreadDescription was added in 14393. Revisit if we ever start requiring 10. */ + static void *kernel32_handle = NULL; + static HRESULT(WINAPI *pSetThreadDescription)(HANDLE hThread, PCWSTR lpThreadDescription) = NULL; + static dllimp_t kernel32_imports[] = { + // clang-format off + { "SetThreadDescription", &pSetThreadDescription }, + { NULL, NULL } + // clang-format on + }; + + if (!kernel32_handle) { + kernel32_handle = dynld_module("kernel32.dll", kernel32_imports); + if (!kernel32_handle) { + kernel32_handle = kernel32_imports; /* dummy pointer to store that we tried */ + pSetThreadDescription = NULL; + } + } + + if (pSetThreadDescription) { + size_t len = strlen(name) + 1; + wchar_t wname[len]; + mbstowcs(wname, name, len); + pSetThreadDescription(thread ? (HANDLE) thread : GetCurrentThread(), wname); + } +} + void take_screenshot(void) { diff --git a/src/win/win_thread.c b/src/win/win_thread.c index faacca74f..db86e9204 100644 --- a/src/win/win_thread.c +++ b/src/win/win_thread.c @@ -37,9 +37,10 @@ typedef struct { } win_event_t; thread_t * -thread_create(void (*func)(void *param), void *param) +thread_create(void (*func)(void *param), void *param, const char *name) { uintptr_t bt = _beginthread(func, 0, param); + plat_set_thread_name(bt, name); return ((thread_t *) bt); }