I am writing a multi-threaded program where, among other things, I have a thread listening to a socket for incoming network connections. To allow this to be interrupted, I am using poll
in combination with signalfd
(rather than a raw await
call). However, I also have other threads that I need to be able to notify of potential interrupts, so I am using a sigwait
call in a dedicated thread to wait for signals. My attempt to get the race to occur is in the code below:
int main()
{
int sigval = 0;
sigset_t mask;
sigemptyset (&mask);
sigaddset (&mask, SIGINT);
pthread_sigmask(SIG_BLOCK, &mask, nullptr);
int sfd = signalfd(-1, &mask, SFD_NONBLOCK);
auto handler = std::thread([&] {
int signal;
sigwait(&mask, &signal);
sigval = signal;
});
pollfd pfd[1] = {{.fd=sfd, .events=POLLIN}};
int ret = poll(pfd, 1, -1);
std::cout << "Poll returned with revents = " << pfd[0].revents << std::endl;
handler.join();
std::cout << "Handled thread set sigval to: " << sigval << std::endl;
return 0;
}
Every time I run this and kill it with SIGINT
, it appears to work, in that the poll
call returns, and sigval
is set by the handler thread. However, my understanding is that sigwait
consumes the signal, while signalfd
does not. So, if somehow sigwait
was called before signalfd
received notification of the signal, this program could potentially hang forever (with poll waiting for a signal that isn't coming). I assume since I can't manage to get the program to hang that there is something on beneath the hood that prevents this from happening, but can I guarantee that this will always be true?
CodePudding user response:
I have looked into the linux source code, and have come up with an answer to my own question: there is no race condition, as the signalfd watchers are explicitly notified before the signal is sent, so they will always be notified before the signal is sent (and caught). Specifically, in linux/kernel/signal.c
, we see:
out_set:
signalfd_notify(t, sig); // <-- signalfd notified
sigaddset(&pending->signal, sig);
...
complete_signal(sig, t, type); // <-- sends the signal
so it is not possible for sigwait
to consume the signal before signalfd
is notified about the signal.