How does ^C work in Python?
Dan Drown
dan-ntp at drown.org
Tue Sep 27 16:20:32 UTC 2016
Quoting Hal Murray <hmurray at megapathdsl.net>:
> Thanks. I assume "system call" includes library calls as well as kernel
> calls.
>
> So DNS lookups are non-interruptable, just like in c.
Yes. From the relevant python documentation:
Although Python signal handlers are called asynchronously as far as
the Python user is concerned, they can only occur between the “atomic”
instructions of the Python interpreter. This means that signals
arriving during long calculations implemented purely in C (such as
regular expression matches on large bodies of text) may be delayed for
an arbitrary amount of time.
[TL;DR - signal handlers need the interpreter to be in a sane state,
so they have to wait]
Some layer is re-issuing the poll call in a socket.getaddrinfo call
instead of exiting back to the python interpreter to handle the signal.
poll([{fd=3, events=POLLIN}], 1, 5000) = ? ERESTART_RESTARTBLOCK
(Interrupted by signal)
--- SIGINT {si_signo=SIGINT, si_code=SI_KERNEL} ---
rt_sigreturn({mask=[]}) = -1 EINTR (Interrupted system call)
poll([{fd=3, events=POLLIN}], 1, 3359) = ? ERESTART_RESTARTBLOCK
(Interrupted by signal)
--- SIGINT {si_signo=SIGINT, si_code=SI_KERNEL} ---
rt_sigreturn({mask=[]}) = -1 EINTR (Interrupted system call)
poll([{fd=3, events=POLLIN}], 1, 2192) = ? ERESTART_RESTARTBLOCK
(Interrupted by signal)
--- SIGINT {si_signo=SIGINT, si_code=SI_KERNEL} ---
rt_sigreturn({mask=[]}) = -1 EINTR (Interrupted system call)
poll([{fd=3, events=POLLIN}], 1, 1960) = 0 (Timeout)
I guess the good news is it eventually times out.
Perl's workaround for this problem by having the default sigint
handler be the simple C exit which doesn't need the interpreter state
to be sane. If you use a perl sigint handler, it has the same
problem. Does python have an option to just exit with the sigint
signal handler and not rely on the interpreter state?
== test /etc/resolv.conf ==
# needs an IP that doesn't respond at all
nameserver 192.0.2.1
== test python dns lookup ==
#!/usr/bin/env python
import socket
print(socket.getaddrinfo("example.com", "ntp", socket.AF_UNSPEC,
socket.SOCK_DGRAM, socket.IPPROTO_UDP, 0))
== test perl dns lookup ==
#!/usr/bin/perl
use Socket qw(getaddrinfo);
use Data::Dumper;
print Dumper(getaddrinfo("example.com", "ntp"));
More information about the devel
mailing list