resolver un-conditionally restarts interrupted kevent
bde at zeta.org.au
Thu Jan 27 08:07:36 PST 2005
On Wed, 26 Jan 2005, Christian S.J. Peron wrote:
> On Thu, Jan 27, 2005 at 10:04:21AM +0800, David Xu wrote:
[On why the kernel changes ERESTART to EINTR for kevent() and a few
other interfaces like poll()]
> > Because they can not be simply restarted. those interfaces
> > have in/out parameters which may already be changed by kernel
> > before returning, also a timeout wait can not be restarted, you
> > told kernel to sleep 10 minutes, and at minute 9, it gets a signal
> > and is restarted, it will return to user code after totally 19
> > minutes.
Perhaps a more fundamental reason is that not restarting is part of
how these interfaces work. POSIX specifies it for poll() and select().
Changing signal handler[s] to restart automatically would be very bad
even if it worked for kevent(). It would break applications that want
other syscalls to not be restarted, and increase problems with
applications longjmping out of signal handlers.
> > > 2) why do we unconditionally restart kevent in our
> > > resolver code?
> > >
> > I think that's right because the code checks 'n < 0' first,
> > it got nothing and does timeout calculation by itself, that's OK.
I think it is mostly historical -- applications or perhaps the library
would not be prepared for __res_send() failing for any signal.
> The problem is this breaks many programs which use loops and conditions
> for program termination. Some examples are ping(8) and tcpdump(1).
> I.E. you go to ping some host or process some packets without -n and
> try to ctrl+c to interrupt the process, the program will not terminate
> because the resolver keeps restarting the kevent system call.
This problem for ping was noticed soon after ping.c:status() was changed
in rev.1.12 to just set a flag. It can't be easy to fix since it has
lived for 8 years since then.
Just setting flags in signal handlers is very hard to implement correctly.
SA_RESTART must not be used for any signal handler, and EINTR must be
handled for all syscalls and perhaps some library functions that would
otherwise be restarted. ping attempts this but doesn't succeed because
the resolver library doesn't cooperate. top's signal handling was
broken by changing its signal handler[s] to just set a flag without
even attempting this. So SIGINT doesn't kill top when top is blocked
> Does anyone think it would make sense to not un-conditionally restart
> the system call and have EINTR (or something to this effect) propogate
> back to the process through h_errno?
That is what should happen. I don't know if it is practical.
More information about the freebsd-arch