Event Loop Support: signalfd()
#
Basic Operation#
#include <sys/signalfd.h>
int signalfd(int fd, const sigset_t *mask, int flags);
Signals received as events, via file descriptor
⟶ Perfect fit for event loop programming
If
fd == -1
, a new file descriptor is createdIf
fd >= 0
(another signal FD), its mask is replaced with the suppliedmask
flags
:SFD_NONBLOCK
,SFD_CLOEXEC
read()
on thefd
into an array ofsignalfd_siginfo
structuresBest to choose array size according to number of handled signals ⟶ read all possible pending signals in one swoop
Different for realtime signals: these are queued
Example: A Better sigwaitinfo()
#
Show normal operation
Suspend process
Demonstrate how
SIGUSR1
andSIGUSR2
are received together with one call toread()
Two instances of say
SIGUSR1
overwrite each other (standard signals vs. realtime signals)
#include <unistd.h>
#include <sys/signalfd.h>
#include <signal.h>
#include <print>
int main()
{
std::println("PID={}", getpid());
sigset_t interest;
sigemptyset(&interest);
sigaddset(&interest, SIGTERM);
sigaddset(&interest, SIGINT);
sigaddset(&interest, SIGUSR1);
sigaddset(&interest, SIGUSR2);
int rv = sigprocmask(SIG_BLOCK, &interest, nullptr);
if (rv == -1) {
perror("sigprocmask");
return 1;
}
int fd = signalfd(-1, &interest, 0); // <-- new fd, no flags
bool quit = false;
while (!quit) {
signalfd_siginfo signals[4]; // <-- we handle 4 different signals
ssize_t nread = read(fd, // <-- read max 4 signals
signals, sizeof(signals));
if (nread == -1) {
perror("read");
return 1;
}
for (size_t i=0; i<sizeof(signals)/sizeof(signalfd_siginfo); i++) {
switch (signals[i].ssi_signo) { // <-- disregard other structure members
case SIGTERM:
case SIGINT:
std::println("terminating");
quit = true;
break;
case SIGUSR1:
std::println("doing this");
break;
case SIGUSR2:
std::println("doing that");
break;
}
}
}
return 0;
}