[Python-Dev] Signal-resistant code (was: Two random and nearly unrelated ideas)

Guido van Rossum guido@python.org
Wed, 04 Sep 2002 16:24:04 -0400

> > What if the operation is a select() call?  Is restarting the right
> > thing?  How to take into account the consumed portion of the timeout,
> > if given?
> Some versions of select update the timeout structure to the remainder if 
> they are interrupted by a signal. It's probably not a good idea to rely 
> on this so gettimeofday could be used to calculate the remainder.

I like Neil's suggestion: simply return.  The timeout is a hint.

> > Or is this a stdio problem?  I believe that calls like fgets() and
> > getchar() don't lose data, but maybe I misunderstand your observation.
> This is not the point - even if Python I/O calls were fully restartable
> would you actually expect people to check for EINTR and restart for
> *every* I/O operation in the program just in case some module happens to
> use signals?
> Instead of
>     for line in file:
>         do_something_with(line)
> we would need to write
>     while 1:
>         try:
>             line = file.next()
>         except IOError, exc:
>             if exc.errno == errno.EINTR:
>                 continue
>             else:
>                 raise
>         except StopIteration:
>             break
>         do_something_with(line)

OK, but you're changing your tune here.  I agree that this is bad, but
I still don't believe (or understand) your previous remark about
readline losing track of buffering.  But let's forget about this, I
trust that you really meant what you showed here.

> > As I said before, I'm very skeptical that making the I/O ops
> > EINTR-safe would be enough to allow the use of signals as
> > suggested by Skip
> If it's good enough for other purposes it should be good enough for
> Skip's proposal, too.

Well, it has to be *perfect* for Skip's proposal, since it means we'd
be generating signals probably at a rate of 100 per second.

> > Skip, but that might still be useful for other purposes, *if* we can
> > decide when to honor EINTR and when not.
> Only low-level functions like os.read and os.write that map directly
> to stdio functions should ever return EINTR.

Um, os.read/write are the ones that *don't* map to stdio.  Maybe you
meant "that map directly to file descriptors"?  But I doubt this would
be acceptable -- if we were generating 100 signals per second,
os.read/write become much harder to use if they could raise EINTR
(currently they only raise EINTR if the app uses signal handlers,
which isn't that common).

> To make Python signal-safe all other calls that can return EINTR
> should have a retry loop. On EINTR they should check if there are
> things to do and if so grab the GIL, make pending calls, release the
> GIL and retry the operation (unless an exception has been raised by
> the signal handler, of course).
> This way I could finally write a Python daemon that reloads its 
> configuration files on getting the customary SIGHUP :-)

If you really want that, maybe you could see if you can produce a
working design and patch?  Even if it's not perfect enough to use
signals to replace the ticker, people who like to use signals would
probably be happy.

--Guido van Rossum (home page: http://www.python.org/~guido/)