diff options
| author | lexprfuncall <carl.shapiro@gmail.com> | 2023-03-01 18:45:00 -0800 |
|---|---|---|
| committer | Rickard Green <rickard@erlang.org> | 2023-04-06 19:33:24 +0200 |
| commit | bc959f99652dbba79c60f7d062a127b48a276d0e (patch) | |
| tree | 97b4db9142d6fff9eea70650a58dbbd2046b87a7 /erts/lib_src/pthread | |
| parent | c21da689ff620509db45c3cc5f45d85ebdaa39be (diff) | |
| download | erlang-bc959f99652dbba79c60f7d062a127b48a276d0e.tar.gz | |
Avoid truncating thread names for better runtime observability
The Erlang runtime gives many of its threads descriptive names. When
those threads are part of a logical group, a unique ID is added to the
name for disambiguation. After construction, many thread names in
Erlang have a string length greater than 16 characters. To fit within
operating system limits, Erlang then truncates them from right to
left. To minimize confusion after truncation, the unique ID is always
placed at the left of a thread name so its information is not likely
to be lost.
The convention used by Erlang presents challenges to the use of thread
names as keys when reporting on thread activity at the operating
system level. The more common convention, used by other runtimes, is
to have the description followed by a unique ID. When followed,
sorting threads by name places like workers next to each other and the
unique ID can be dropped to create a grouping key. Placing the unique
ID first, as Erlang does, means that a different strategy needs to be
used for sorting the threads of an Erlang process. Furthermore, the
truncation necessitates a complicated strategy for analyzing the
description to identify a possible common substring to be used as a
grouping key.
This change switches the Erlang runtime to use the more common
convention in order to make reporting on the thread usage in an Erlang
process easier for tooling. To do so, it shortens the content of the
initial printf(3) format strings to ensure their output is always 16
or fewer characters so the name is never truncated. It also moves the
unique ID in the format string to the right of the description, so the
names of worker threads appear next to each other after sorting
alphabetically from left to right.
To prevent the accidental creation of long thread names in the future,
the silent truncation has been eliminated from the lowest-layer of
thread functionality. It now returns an EINVAL when given a long name
which will be caught when the runtime is started. This would break
the NIF and driver libraries so the silent truncation has moved up to
a higher layer in order to preserve compatibility. New unit tests have
been added to test setting and getting thread names.
Diffstat (limited to 'erts/lib_src/pthread')
| -rw-r--r-- | erts/lib_src/pthread/ethread.c | 22 |
1 files changed, 6 insertions, 16 deletions
diff --git a/erts/lib_src/pthread/ethread.c b/erts/lib_src/pthread/ethread.c index b17aa3a17f..bfacaa27d0 100644 --- a/erts/lib_src/pthread/ethread.c +++ b/erts/lib_src/pthread/ethread.c @@ -81,7 +81,7 @@ typedef struct { void *prep_func_res; size_t stacksize; char *name; - char name_buff[32]; + char name_buff[ETHR_THR_NAME_MAX + 1]; } ethr_thr_wrap_data__; static void *thr_wrapper(void *vtwd) @@ -334,21 +334,9 @@ ethr_thr_create(ethr_tid *tid, void * (*func)(void *), void *arg, twd.stacksize = 0; if (opts && opts->name) { - size_t nlen = sizeof(twd.name_buff); -#ifdef __HAIKU__ - if (nlen > B_OS_NAME_LENGTH) - nlen = B_OS_NAME_LENGTH; -#else - /* - * Length of 16 is known to work. At least pthread_setname_np() - * is documented to fail on too long name string, but documentation - * does not say what the limit is. Do not have the time to dig - * further into that now... - */ - if (nlen > 16) - nlen = 16; -#endif - snprintf(twd.name_buff, nlen, "%s", opts->name); + if (strlen(opts->name) >= sizeof(twd.name_buff)) + return EINVAL; + strcpy(twd.name_buff, opts->name); twd.name = twd.name_buff; } else twd.name = NULL; @@ -506,6 +494,8 @@ ethr_getname(ethr_tid tid, char *buf, size_t len) void ethr_setname(char *name) { + if (strlen(name) > ETHR_THR_NAME_MAX) + return; #if defined(ETHR_HAVE_PTHREAD_SETNAME_NP_2) pthread_setname_np(ethr_self(), name); #elif defined(ETHR_HAVE_PTHREAD_SET_NAME_NP_2) |
