Fix BSD and macOS builds w.r.t. pthread_setname_np (bug#38632)

pthread_setname_np takes only a single argument on BSD and macOS,
and affects the current thread only.

* configure.ac: Add check for single-argument pthread_setname_np
* src/systhread.c (sys_thread_set_name): New (w32 and pthread versions).
(sys_thread_create): Remove name argument and name-setting.
(w32_beginthread_wrapper): Remove name-setting.
* src/systhread.h (sys_thread_create, sys_thread_set_name):
Update prototypes.
* src/thread.c (run_thread): Call sys_thread_set_name.
(Fmake_thread): Adapt call to sys_thread_create.
* src/thread.h (struct thread_state): Adjust comment.
This commit is contained in:
Mattias Engdegård 2020-01-07 17:08:25 +01:00
parent f54b24304d
commit 73fd8a4b53
5 changed files with 55 additions and 33 deletions

View file

@ -4183,6 +4183,23 @@ getpwent endpwent getgrent endgrent \
cfmakeraw cfsetspeed __executable_start log2 pthread_setname_np) cfmakeraw cfsetspeed __executable_start log2 pthread_setname_np)
LIBS=$OLD_LIBS LIBS=$OLD_LIBS
if test "$ac_cv_func_pthread_setname_np" = "yes"; then
AC_CACHE_CHECK(
[whether pthread_setname_np takes a single argument],
[emacs_cv_pthread_setname_np_1arg],
[AC_COMPILE_IFELSE(
[AC_LANG_PROGRAM(
[[#include <pthread.h>]],
[[pthread_setname_np ("a");]])],
[emacs_cv_pthread_setname_np_1arg=yes],
[emacs_cv_pthread_setname_np_1arg=no])])
if test "$emacs_cv_pthread_setname_np_1arg" = "yes"; then
AC_DEFINE(
HAVE_PTHREAD_SETNAME_NP_1ARG, 1,
[Define to 1 if pthread_setname_np takes a single argument.])
fi
fi
dnl No need to check for posix_memalign if aligned_alloc works. dnl No need to check for posix_memalign if aligned_alloc works.
AC_CHECK_FUNCS([aligned_alloc posix_memalign], [break]) AC_CHECK_FUNCS([aligned_alloc posix_memalign], [break])
AC_CHECK_DECLS([aligned_alloc], [], [], [[#include <stdlib.h>]]) AC_CHECK_DECLS([aligned_alloc], [], [], [[#include <stdlib.h>]])

View file

@ -200,9 +200,28 @@ sys_thread_equal (sys_thread_t t, sys_thread_t u)
return pthread_equal (t, u); return pthread_equal (t, u);
} }
void
sys_thread_set_name (const char *name)
{
#ifdef HAVE_PTHREAD_SETNAME_NP
/* We need to truncate here otherwise pthread_setname_np
fails to set the name. TASK_COMM_LEN is what the length
is called in the Linux kernel headers (Bug#38632). */
#define TASK_COMM_LEN 16
char p_name[TASK_COMM_LEN];
strncpy (p_name, name, TASK_COMM_LEN - 1);
p_name[TASK_COMM_LEN - 1] = '\0';
#ifdef HAVE_PTHREAD_SETNAME_NP_1ARG
pthread_setname_np (p_name);
#else
pthread_setname_np (pthread_self (), p_name);
#endif
#endif
}
bool bool
sys_thread_create (sys_thread_t *thread_ptr, const char *name, sys_thread_create (sys_thread_t *thread_ptr, thread_creation_function *func,
thread_creation_function *func, void *arg) void *arg)
{ {
pthread_attr_t attr; pthread_attr_t attr;
bool result = false; bool result = false;
@ -221,22 +240,7 @@ sys_thread_create (sys_thread_t *thread_ptr, const char *name,
} }
if (!pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED)) if (!pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED))
{ result = pthread_create (thread_ptr, &attr, func, arg) == 0;
result = pthread_create (thread_ptr, &attr, func, arg) == 0;
#ifdef HAVE_PTHREAD_SETNAME_NP
if (result && name != NULL)
{
/* We need to truncate here otherwise pthread_setname_np
fails to set the name. TASK_COMM_LEN is what the length
is called in the Linux kernel headers (Bug#38632). */
#define TASK_COMM_LEN 16
char p_name[TASK_COMM_LEN];
strncpy (p_name, name, TASK_COMM_LEN - 1);
p_name[TASK_COMM_LEN - 1] = '\0';
pthread_setname_np (*thread_ptr, p_name);
}
#endif
}
out: ; out: ;
int error = pthread_attr_destroy (&attr); int error = pthread_attr_destroy (&attr);
@ -457,26 +461,24 @@ w32_set_thread_name (DWORD thread_id, const char *name)
static thread_creation_function *thread_start_address; static thread_creation_function *thread_start_address;
void
sys_thread_set_name (const char *name)
{
w32_set_thread_name (GetCurrentThreadId (), name);
}
/* _beginthread wants a void function, while we are passed a function /* _beginthread wants a void function, while we are passed a function
that returns a pointer. So we use a wrapper. See the command in that returns a pointer. So we use a wrapper. See the command in
w32term.h about the need for ALIGN_STACK attribute. */ w32term.h about the need for ALIGN_STACK attribute. */
static void ALIGN_STACK static void ALIGN_STACK
w32_beginthread_wrapper (void *arg) 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); (void)thread_start_address (arg);
} }
bool bool
sys_thread_create (sys_thread_t *thread_ptr, const char *name, sys_thread_create (sys_thread_t *thread_ptr, thread_creation_function *func,
thread_creation_function *func, void *arg) void *arg)
{ {
/* FIXME: Do threads that run Lisp require some minimum amount of /* FIXME: Do threads that run Lisp require some minimum amount of
stack? Zero here means each thread will get the same amount as stack? Zero here means each thread will get the same amount as

View file

@ -112,10 +112,11 @@ extern sys_thread_t sys_thread_self (void)
extern bool sys_thread_equal (sys_thread_t, sys_thread_t) extern bool sys_thread_equal (sys_thread_t, sys_thread_t)
ATTRIBUTE_WARN_UNUSED_RESULT; ATTRIBUTE_WARN_UNUSED_RESULT;
extern bool sys_thread_create (sys_thread_t *, const char *, extern bool sys_thread_create (sys_thread_t *, thread_creation_function *,
thread_creation_function *, void *) void *)
ATTRIBUTE_WARN_UNUSED_RESULT; ATTRIBUTE_WARN_UNUSED_RESULT;
extern void sys_thread_yield (void); extern void sys_thread_yield (void);
extern void sys_thread_set_name (const char *);
#endif /* SYSTHREAD_H */ #endif /* SYSTHREAD_H */

View file

@ -725,6 +725,9 @@ run_thread (void *state)
self->m_stack_bottom = self->stack_top = (char *) &stack_pos; self->m_stack_bottom = self->stack_top = (char *) &stack_pos;
self->thread_id = sys_thread_self (); self->thread_id = sys_thread_self ();
if (self->thread_name)
sys_thread_set_name (self->thread_name);
acquire_global_lock (self); acquire_global_lock (self);
/* Put a dummy catcher at top-level so that handlerlist is never NULL. /* Put a dummy catcher at top-level so that handlerlist is never NULL.
@ -832,7 +835,7 @@ If NAME is given, it must be a string; it names the new thread. */)
else else
new_thread->thread_name = NULL; new_thread->thread_name = NULL;
sys_thread_t thr; sys_thread_t thr;
if (! sys_thread_create (&thr, c_name, run_thread, new_thread)) if (! sys_thread_create (&thr, run_thread, new_thread))
{ {
/* Restore the previous situation. */ /* Restore the previous situation. */
all_threads = all_threads->next_thread; all_threads = all_threads->next_thread;

View file

@ -169,8 +169,7 @@ struct thread_state
interrupter should broadcast to this condition. */ interrupter should broadcast to this condition. */
sys_cond_t *wait_condvar; sys_cond_t *wait_condvar;
/* Thread's name in the locale encoding. Actually used only on /* Thread's name in the locale encoding. */
WINDOWSNT. */
char *thread_name; char *thread_name;
/* This thread might have released the global lock. If so, this is /* This thread might have released the global lock. If so, this is