I can wait for one of several network connections using select
or epoll
. I can wait for a signal using sigwaitinfo
, or add a handler to run on receipt of the signal.
How do I wait for either a network socket to have incoming traffic, or for a specific signal (SIGWINCH, in my case)?
One idea that occurs to me is to have the signal handler send "loopback" traffic to some open file descriptor, so epoll
can await it. But I'd rather not actually make any file. Maybe there's a way to create two new file descriptors which are directly connected to one another?
I can wait for one of several network connections using select
or epoll
. I can wait for a signal using sigwaitinfo
, or add a handler to run on receipt of the signal.
How do I wait for either a network socket to have incoming traffic, or for a specific signal (SIGWINCH, in my case)?
One idea that occurs to me is to have the signal handler send "loopback" traffic to some open file descriptor, so epoll
can await it. But I'd rather not actually make any file. Maybe there's a way to create two new file descriptors which are directly connected to one another?
2 Answers
Reset to default 4On Linux, I'd do this with signalfd(2)
, which creates a file descriptor that polls as readable when given signals are delivered (and can be read from to find out information about the signal). That descriptor can be added to the ones monitored by epoll
, along with the sockets.
You should block SIGWINCH
first with sigprocmask(2)
so it doesn't get handled by normal signal handlers.
One idea that occurs to me is to have the signal handler send "loopback" traffic to some open file descriptor, so epoll can await it. But I'd rather not actually make any file. Maybe there's a way to create two new file descriptors which are directly connected to one another?
You can use pipe(2)
to create a pair of connected descriptors for that style; it's a common technique for this sort of scenario in older and/or portable code bases. With Linux I generally prefer the lighter weight eventfd(2)
for asynchronous notifications, though.
You've several options for a single thread to respond to both signals and I/O.
1. Turn the signals into I/O
This is the approach you'd thought of, and which another answer covers well. You've got the old (and portable) self-pipe trick and the Linux-specific signalfd
.
This is what I would do, and I'd suggest upvoting and accepting that other answer.
2. Turn the I/O into signals
For completeness it bears mentioning that you can use fcntl
to manage signals, using F_SETOWN and O_ASYNC to get a SIGIO delivered when a descriptor is ready for reading or writing.
With SA_SIGINFO and, on Linux, an explicit F_SETSIG, you'll be able to tell which descriptor is ready and why.
Definitely more awkward than #1 and perhaps inappropriate if some of your descriptors are perpetually writeable, for example. But it might work well for, e.g., waiting for incoming connections on a bound socket.
3. Handle signals and I/O separately, with atomic masking
POSIX's pselect
and Linux's ppoll
let you use I/O multiplexing without "missing" a signal fire, by atomically unblocking desired signals only during the multiplexing call.
Importantly, select
and poll
are race-prone here, which other questions on this site cover.
EINTR
if any signal arrives while they are waiting (you should handle the signal you're interested in and atomically set a flag there or something). So is that already the answer or is there something that prevents you from using that? (e.g. you're multithreaded and your signals are delivered to weird threads...) – teapot418 Commented 2 days agopselect
and masking are one mitigation, though turning a signal into an i/o event is a better approach in my opinion. – pilcrow Commented yesterday