Document number: N2419
Submitter: Kamil Rytarowski
Submission Date: September 3, 2019
Subject: Add methods for setting and getting the thread name

Context

The §5.1.2 Execution environments section specifies two defined execution environments: freestanding and hosted. In the hosted environment as defined in §5.1.2.2.1 Program startup paragraph 2 there is specified the concept of the program name as represented by the string pointed to by argv[0].

The program name is available on a broad range of Operating Systems, including but not limited to the following:

The C language as specified by ISO/IEC 9899:2011 introduced multi-threading support (<threads.h>). In hosted environments, Operating Systems typically store descriptive thread name, as this information is useful for process monitors and debuggers.

An example of this feature is the process of attaching GDB to a running Firefox on NetBSD/amd64:

$ gdb -p `pgrep firefox`
[...]
(gdb) info threads 
  Id   Target Id                                 Frame 
* 1    process 130 ""                            0x00007920234a76aa in ___lwp_park60 () from /usr/lib/libc.so.12
  2    LWP 5453 of process 130 "IndexedDB #1064" 0x00007920234a76aa in ___lwp_park60 () from /usr/lib/libc.so.12
  3    LWP 5452 of process 130 "IndexedDB #1063" 0x00007920234a76aa in ___lwp_park60 () from /usr/lib/libc.so.12
  4    LWP 5449 of process 130 "StreamTrans #30" 0x00007920234a76aa in ___lwp_park60 () from /usr/lib/libc.so.12
  5    LWP 5448 of process 130 "DNS Resolver #7" 0x00007920234a76aa in ___lwp_park60 () from /usr/lib/libc.so.12
  6    LWP 5445 of process 130 "SSL Cert #410"   0x00007920234a76aa in ___lwp_park60 () from /usr/lib/libc.so.12
  7    LWP 5443 of process 130 "IndexedDB #1061" 0x00007920234a76aa in ___lwp_park60 () from /usr/lib/libc.so.12
  8    LWP 5440 of process 130 "SubtleCrypto #3" 0x00007920234a76aa in ___lwp_park60 () from /usr/lib/libc.so.12
  9    LWP 5400 of process 130 "DNS Resolver #7" 0x00007920234a76aa in ___lwp_park60 () from /usr/lib/libc.so.12
  10   LWP 5065 of process 130 "ImgDecoder #4"   0x00007920234a76aa in ___lwp_park60 () from /usr/lib/libc.so.12
  11   LWP 4387 of process 130 "DOM Worker"      0x00007920234a76aa in ___lwp_park60 () from /usr/lib/libc.so.12
  12   LWP 4383 of process 130 "DOM Worker"      0x00007920234a76aa in ___lwp_park60 () from /usr/lib/libc.so.12
  13   LWP 4374 of process 130 "DOM Worker"      0x00007920234a76aa in ___lwp_park60 () from /usr/lib/libc.so.12
  14   LWP 4232 of process 130 "DOM Worker"      0x00007920234a76aa in ___lwp_park60 () from /usr/lib/libc.so.12
  15   LWP 4101 of process 130 "DOM Worker"      0x00007920234a76aa in ___lwp_park60 () from /usr/lib/libc.so.12
[..]
  69   LWP 3 of process 130 "JS Watchdog"        0x00007920234a76aa in ___lwp_park60 () from /usr/lib/libc.so.12
  70   LWP 2 of process 130 "Gecko_IOThread"     0x000079202343ff3a in _sys___kevent50 () from /usr/lib/libc.so.12
  71   LWP 1 of process 130 ""                   0x000079202343fdba in poll () from /usr/lib/libc.so.12

The relationship among thread and proces entities as well as the kernel and userland threading model differs with each mainstream Operating System. The C language implementors in multi-threaded environments define also slightly different semantics between the setting and getting the thread name. The C language implementors in multi-threaded environments also define slightly different semantics between the getting and setting the thread name.

Plan9 uses the threadgetname() and threadsetname() API. Haiku uses the rename_thread() API. Domain specific Operating Systems like RTEMS or QNX clone the thread name semantics from general purpose operating systems (typically Linux, NetBSD or FreeBSD).

Problem statement

Thread names are ubiquitous on hosted environments with threading support. Methods for accessing thread names are defined in the extension of current standards and are OS specific. The maximum length of a thread name can be defined either as an integer constant expression in the public headers (as in NetBSD), documented in manuals (as in Linux) or needs to be reverse engineered to discover the length of buffer (as in Windows).

Portable software such as LLVM or MESA must support conditional compilation branches for each OS separately:

static inline void u_thread_setname( const char *name )
{
#if defined(HAVE_PTHREAD)
#if DETECT_OS_LINUX || DETECT_OS_CYGWIN
   pthread_setname_np(pthread_self(), name);
#elif DETECT_OS_FREEBSD || DETECT_OS_OPENBSD
   pthread_set_name_np(pthread_self(), name);
#elif DETECT_OS_NETBSD
   pthread_setname_np(pthread_self(), "%s", (void *)name);
#elif DETECT_OS_APPLE
   pthread_setname_np(name);
#else
#error Not sure how to call pthread_setname_np
#endif
#endif
   (void)name;
}

-- MESA, src/util/u_thread.h rev. 0141b7c6b25cd1cb7b4073c3905839b3e5e07413

A more complete example is in LLVM rev. c4cdb2b38d8574e3c0f70066a3a59014d8b9f07d in the following files:

Solution

I propose the following steps:


Suggested Changes

Add the following paragraph §5.1.2.4 Multi-threaded executions and data races Thread functions after the 1st paragraph:

2. Each thread has an associated thread name. It is implementation-defined what is the effect of the thread name methods on the environment.

Add the following change in §7.26.1 Introduction paragraph 3 adding the specification of THRD_MAX_NAMELEN.

The macros are

        thread_local
      
which expands to _Thread_local;
        ONCE_FLAG_INIT
      
which expands to a value that can be used to initialize an object of type once_flag; and
        TSS_DTOR_ITERATIONS
      
which expands to an integer constant expression representing the maximum number of times that destructors will be called when a thread terminates.; and
        THRD_MAX_NAMELEN
      
which expands to integer constant expression that can be used as the maximum length of a thread's name, including the terminating null character.

Add the following two subsections at the end of the §7.26.5 Thread functions section.

7.26.5.? The thrd_getname function

Synopsis
	#include <threads.h>

	int thrd_getname(thrd_t thr, char *name, size_t maxlen);
Description

The thrd_getname function obtains, at most the number of characters specified by maxlen and not larger than THRD_MAX_NAMELEN from the descriptive name of a thread, pointed to by thr into the array pointed to by name. The returned string is null terminated. No additional characters are read after the null character.

The returned value prior calling thrd_setname is implementation-defined.

Returns

The thrd_getname function returns thrd_success on success or thrd_error if the request could not be honored.

7.26.5.? The thrd_setname function

Synopsis
	#include <threads.h>

	int thrd_setname(thrd_t thr, const char *name);
Description

The thrd_setname function sets the descriptive name of a thread pointed to by thr. At most the number of characters specified by THRD_MAX_NAMELEN is read from the null-terminated array pointed by name.

Returns

The thrd_setname function returns thrd_success on success or thrd_error if the request could not be honored.