Is there any way to get the current thread ID from a signal handler in Linux? The getpid()
method does what I want, but it is not clear if it is async-safe. man 7 signal
provides a list of POSIX methods which are async safe, but this tells us nothing about non-POSIX methods such as getpid()
. Presumably some of the many non-POSIX methods Linux has added are async safe, but I can't find the list.
There is also this answer which claims that all direct (not multiplexed) syscalls are async safe, but provides no evidence.
The goal is to build some kind of async-safe thread local storage, since __thread
is not safe in the general case.
It doesn't have to be the "Linux thread ID" - any consistent thread ID would be fine. For example pthread_self
would be great, but there is nothing claiming that is async safe. If we examine the implementation of that method in glibc Linux, it defers to the THREAD_SELF macro, which looks like:
# define THREAD_SELF \
({ struct pthread *__self; \
asm ("movl %%gs:%c1,%0" : "=r" (__self) \
: "i" (offsetof (struct pthread, header.self))); \
__self;})
It seems to be that this should be async-safe, if the thread in question was created under a regime that populates the gs
resgister (perhaps all threads in Linux are, I'm not sure). Still looking at that header makes me pretty scared...
As mentioned in Async-signal-safe access to __thread variables from dlopen()ed libraries? you provided (emphasis is mine):
The __thread variables generally fit the bill (at least on Linux/x86), when the variable is in the main executable, or in a directly-linked DSO.
But when the DSO is dlopen()ed (and does not use initial-exec TLS model), the first access to TLS variable from a given thread triggers a call to malloc...
In other words, it only requires one access to that thread specific variable to bring it to life and make it available in signal handlers. E.g.:
pthread_create
.__thread
variable and unblock those interesting signals.I normally store the write end of a unix pipe in that tread-specific variable and the signal handler writes the signal number into that pipe. The read end of the pipe is registered with select/epoll
in that same thread, so that I can handle signals outside of the signal context. E.g.:
__thread int signal_pipe; // initialized at thread start
extern "C" void signal_handler(int signo, siginfo_t*, void*)
{
unsigned char signo_byte = static_cast<unsigned>(signo); // truncate
::write(signal_pipe, &signo_byte, 1); // standard unix self pipe trick
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With