Reputation: 764
I need to interrupt a syscall (recvfrom
in this case) after a timeout. For this I'm using alarm()
, however the resulting SIGALRM kills my process instead of only interrupting the syscall.
I've tried calling signal(SIGALRM, SIG_IGN)
to handle the SIGALRM, but this causes the syscall to not be interrupted at all! The only way I've got this to work is by creating a custom empty handler (signal(SIGALRM, alrm_handler)
) - the handler does nothing, but it still results in the recvfrom
being interrupted without the process being killed.
I understand that the default signal handler (SIG_DFL) will kill the process, but I expected SIG_IGN to ignore the signal but still interrupt the syscall. I strace
d a test program with SIG_IGN and with a custom empty handler, and they both end up calling rt_sigaction(SIGALRM...)
without SA_RESTART. As far as I know, if SA_RESTART was set then the syscall would be restarted automatically, but this is happening with SIG_IGN anyway!
Is there any cleaner way to interrupt a syscall with SIGALRM without needing a custom signal handler?
Upvotes: 1
Views: 1443
Reputation: 39551
When you tell the operating system to ignore a signal you shouldn't be surprised if when it's signaled it does nothing and ignores it. POSIX only allows recvfrom
to return EINTR if has been interrupted and it's only interrupted if a signal handler is called. When SIG_IGN
is set POSIX requires that "delivery of the signal will have no effect on the process."
A better way to to do timeouts on socket operations is to set a timeout on the socket using setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, ...)
. You'll get either an EAGAIN
or EWOULDBLOCK
error if it times out.
You might also want to look at select
which can potentially eliminate the need to use timeouts.
Upvotes: 3