... Reading through more of the code, I realized that I greatly
underestimated the number of interruptible operations.

That said, the meta-question still applies: Are there things which are
generally intended *not* to be interruptible by signals, and if so, is
there some consistent way of indicating this?

On Wed, Jun 24, 2020 at 2:34 PM Yonatan Zunger <zun...@humu.com> wrote:

> Hi everyone,
>
> I'm in the process of writing some code to defer signals during critical
> regions, which has involved a good deal of reading through the CPython
> implementation to understand the behaviors. Something I've found is that
> there appears to be a lot of thoughtfulness about where the signal handlers
> can be triggered, but this thoughtfulness is largely undocumented. I've put
> together a working list of behaviors from staring at the code, but what I'd
> like to figure out is which of these behaviors the devs think of as
> intended to be invariants, versus which are just accidents of how the code
> currently works and might change unpredictably.
>
> And if there are things which are intended to be genuine invariants, would
> it be reasonable to document these formally and make them part of the
> language, not just for inside the CPython codebase?
>
> What appears to be true is this:
>
>    - Signal handlers are only invoked in the main thread (documented with
>    the signal library)
>    - High-level: Signal handlers may be invoked at any instruction
>    boundary. External C libraries *may* invoke them as well, but there
>    are no general guarantees. (Documented with the signal library)
>    - Low-level: Certain functions can be described as "interruptable,"
>    and signal handlers may be invoked whenever these functions are called.
>    - Signal handlers are thus partially reentrant: a signal handler may
>    be interrupted by another signal iff it invokes an interruptable function.
>
> In particular, the thing whose intentionality I'm not sure about is
> whether the notion of an interruptable function or instruction is meant to
> be an actual property of the language and/or of the CPython runtime, or
> whether it's actually intended that only the "high-level" rule above be
> true, and that all signal handlers should be considered to be fully
> reentrant at all times. The comments in sysmodule.c about avoiding
> triggering PyErr_CheckSignals() suggest that there definitely is some
> thinking about this within the CPython code itself.
>
> The reason it would be useful to document this is so that if I'm trying to
> write a fairly generic library that handles signals (like the one I'm doing
> now) I can reason about where I need to be defensive about an instruction
> being interrupted by yet another signal, and maybe avoid calls to certain
> functions which are known to be interruptable, much like I would avoid
> calling malloc() in a C signal handler.
>
> In the current implementation, the interruptable functions and
> instructions are:
>
> Big categories:
>
>    - Any function which calls PyErr_SetFromErrno, *if* errno == EINTR.
>    (Catalogue needs to be made of these -- it's a much smaller set than the
>    set of all calls to PyErr_SetFromErrno)
>    - Basically any open, read, or write method of a raw or buffered file
>    object.
>    - Likewise, any open, read, or write method on a socket.
>    - In any interactive console readline, or in input().
>    - object.__str__, object.__repr__, and PyObject_Print, and anything
>    that falls back to these.
>
> Specific instructions:
>
>    -
>    - Multiplication, division, or stringification of long integers.
>
> More specific functions:
>
>    - In `multiprocessing.shared_memory`, SharedMemory.__init__, .close,
>    and .unlink.
>    - In `multiprocessing.semaphore`, Semaphore.acquire. (But
>    interestingly, *not* threading.Semaphore.acquire)
>    - In `signal`, pause, signal, sigwaitinfo, sigtimedwait, pthread_kill,
>    and pthread_sigmask.
>    - In `fcntl`, fcntl and ioctl.
>    - In `traceback`, any of the print methods.
>    - In `faulthandler`, dump_traceback
>    - In `select`, all of the methods. (select, epoll, etc)
>    - In `time`, sleep.
>    - In `curses`, whenever you look for key input.
>    - In `tkinter`, during the main loop of a Tcl/Tk app.
>    - During an SSL handshake.
>
> --
>
> Yonatan Zunger
>
> Distinguished Engineer and Chief Ethics Officer
>
> He / Him
>
> zun...@humu.com
>
> 100 View St, Suite 101
>
> Mountain View, CA 94041
>
> Humu.com <https://www.humu.com>  · LinkedIn
> <https://www.linkedin.com/company/humuhq>  · Twitter
> <https://twitter.com/humuinc>
>


-- 

Yonatan Zunger

Distinguished Engineer and Chief Ethics Officer

He / Him

zun...@humu.com

100 View St, Suite 101

Mountain View, CA 94041

Humu.com <https://www.humu.com>  · LinkedIn
<https://www.linkedin.com/company/humuhq>  · Twitter
<https://twitter.com/humuinc>
_______________________________________________
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/2SRAKKKMGELEEQ5LG4CT4PWZZAGLB7S6/
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to