sqd
sqd

Reputation: 1535

Interrupt system calls on multiple threads

I have a bunch of pthreads, each blocking on a system call such as recv() and wait().

I want to interrupt them (and make them return with errno = EINTR) when a signal arrives, so I use sigaction() without SA_RESTART to set an interrupt handler. The end goal is to gracefully exit the whole program.

However, it seems that only the thread that handles the signal got interrupted, while the other threads keep blocking on their system calls.

How do I interrupt all of them?

Upvotes: 3

Views: 1187

Answers (2)

R.. GitHub STOP HELPING ICE
R.. GitHub STOP HELPING ICE

Reputation: 215193

In order to interrupt all of them, you need to use pthread_kill to signal them each individually, rather than signaling the process, which means you need to keep a list of the threads you may want to signal. Note that since it's always possible for the signal to arrive after the last check before the blocking syscall, but before the syscall is actually made, it's always necessary to repeat the signaling (with appropriate backoff) until the signaled thread responds in some way to indicate that it has accepted the interruption request. This is a race condition inherent in the original concept of interruption-by-signal, even without threads.

If it's your intent that the threads terminate shortly after interrupting the syscalls they're blocking in, you could use Thread Cancellation instead of signals. This does not require dealing with the problems of EINTR (the aforementioned race condition, among other things) but does require structuring your code around the possibility of cancellation. That means enabling/disabling cancellation according to whether the code executing is prepared to handle it, and setting up cancellation handlers to back out any inconsistent state, free resources, release locks, etc. as appropriate.

If you do use signals, volatile sigatomic_t objects should not play any role in the solution. The signal handler can and should be a completely empty function; its only purpose is to cause EINTR. The signaling thread and signaled thread should communicate via standard pthread synchronization primitives (mutexes, possibly condition variables, and/or semaphores) to indicate the request to abort the operation and to acknowledge action on the request.

Upvotes: 1

signal(7)-s are not friendly with pthreads(7) (which on Linux are implemented with clone(2))

Consider (like Qt does) having some event loop in every thread, and use signalfd(2). It is compatible with poll(2) so with socket(7).

Alternatively, set some global volatile sigatomic_t flag; in your signal handler, and test that flag in every thread. See also <stdatomic.h>

Be aware of the continuation passing style paradigm.

Upvotes: 3

Related Questions