using select() with pipe - this is what I am doing and now I need to catch SIGTERM
on that. how can I do it? Do I have to do it when select()
returns error ( < 0 ) ?
相关问题
- Multiple sockets for clients to connect to
- What is the best way to do a search in a large fil
- glDrawElements only draws half a quad
- Index of single bit in long integer (in C) [duplic
- Equivalent of std::pair in C
You can call
select()
in a loop. This is known as restarting the system call. Here is some pseudo-C.The answer is partly in one of the comment in the Q&A you point to;
> Interrupt will cause select() to return a -1 with errno set to EINTR
That is; for any interrupt(signal) caught the select will return, and the errno will be set to EINTR.
Now if you specifically want to catch SIGTERM, then you need to set that up with a call to
signal
, like this;where your catch function should be defined something like
So in summary, you have setup a signal handler
yourcatchfunction
and your program is currently in aselect()
call waiting for IO -- when a signal arrives, your catchfunction will be called and when you return from that the select call will return with the errno set to EINTR.However be aware that the SIGTERM can occur at any time so you may not be in the select call when it occur, in which case you will never see the EINTR but only a regular call of the
yourcatchfunction
Hence the select() returning with err and errno EINTR is just so you can take non-blocking action -- it is not what will catch the signal.
First,
SIGTERM
will kill your process if not caught, andselect()
will not return. Thus, you must install a signal handler forSIGTERM
. Do that usingsigaction()
.However, the
SIGTERM
signal can arrive at a moment where your thread is not blocked atselect()
. It would be a rare condition, if your process is mostly sleeping on the file descriptors, but it can otherwise happen. This means that either your signal handler must do something to inform the main routine of the interruption, namely, setting some flag variable (of typesig_atomic_t
), or you must guarantee thatSIGTERM
is only delivered when the process is sleeping onselect()
.I'll go with the latter approach, since it's simpler, albeit less flexible (see end of the post).
So, you block
SIGTERM
just before callingselect()
, and reblock it right away after the function returns, so that your process only receives the signal while sleeping insideselect()
. But note that this actually creates a race condition. If the signal arrives just after the unblock, but just beforeselect()
is called, the system call will not have been called yet and thus it will not return-1
. If the signal arrives just afterselect()
returns successfully, but just before the re-block, you have also lost the signal.Thus, you must use
pselect()
for that. It does the blocking/unblocking aroundselect()
atomically.First, block
SIGTERM
usingsigprocmask()
before entering thepselect()
loop. After that, just callpselect()
with the original mask returned bysigprocmask()
. This way you guarantee your process will only be interrupted while sleeping onselect()
.In summary:
SIGTERM
(that does nothing);pselect()
loop, blockSIGTERM
usingsigprocmask()
;pselect()
with the old signal mask returned bysigprocmask()
;pselect()
loop, now you can check safely whetherpselect()
returned-1
anderrno
isEINTR
.Please note that if, after
pselect()
returns successfully, you do a lot of work, you may experience bigger latency when responding toSIGTERM
(since the process must do all processing and return topselect()
before actually processing the signal). If this is a problem, you must use a flag variable inside the signal handler, so that you can check for this variable in a number of specific points in your code. Using a flag variable does not eliminate the race condition and does not eliminate the need forpselect()
, though.Remember: whenever you need to wait on some file descriptors or for the delivery of a signal, you must use
pselect()
(orppoll()
, for the systems that support it).Edit: nothing better than a code example to illustrate the usage.