summaryrefslogtreecommitdiff
path: root/erts/lib_src/pthread
diff options
context:
space:
mode:
authorlexprfuncall <carl.shapiro@gmail.com>2023-03-01 18:45:00 -0800
committerRickard Green <rickard@erlang.org>2023-04-06 19:33:24 +0200
commitbc959f99652dbba79c60f7d062a127b48a276d0e (patch)
tree97b4db9142d6fff9eea70650a58dbbd2046b87a7 /erts/lib_src/pthread
parentc21da689ff620509db45c3cc5f45d85ebdaa39be (diff)
downloaderlang-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.c22
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)