CINXE.COM
PEP 475 – Retry system calls failing with EINTR | peps.python.org
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="color-scheme" content="light dark"> <title>PEP 475 – Retry system calls failing with EINTR | peps.python.org</title> <link rel="shortcut icon" href="../_static/py.png"> <link rel="canonical" href="https://peps.python.org/pep-0475/"> <link rel="stylesheet" href="../_static/style.css" type="text/css"> <link rel="stylesheet" href="../_static/mq.css" type="text/css"> <link rel="stylesheet" href="../_static/pygments.css" type="text/css" media="(prefers-color-scheme: light)" id="pyg-light"> <link rel="stylesheet" href="../_static/pygments_dark.css" type="text/css" media="(prefers-color-scheme: dark)" id="pyg-dark"> <link rel="alternate" type="application/rss+xml" title="Latest PEPs" href="https://peps.python.org/peps.rss"> <meta property="og:title" content='PEP 475 – Retry system calls failing with EINTR | peps.python.org'> <meta property="og:description" content="System call wrappers provided in the standard library should be retried automatically when they fail with EINTR, to relieve application code from the burden of doing so."> <meta property="og:type" content="website"> <meta property="og:url" content="https://peps.python.org/pep-0475/"> <meta property="og:site_name" content="Python Enhancement Proposals (PEPs)"> <meta property="og:image" content="https://peps.python.org/_static/og-image.png"> <meta property="og:image:alt" content="Python PEPs"> <meta property="og:image:width" content="200"> <meta property="og:image:height" content="200"> <meta name="description" content="System call wrappers provided in the standard library should be retried automatically when they fail with EINTR, to relieve application code from the burden of doing so."> <meta name="theme-color" content="#3776ab"> </head> <body> <svg xmlns="http://www.w3.org/2000/svg" style="display: none;"> <symbol id="svg-sun-half" viewBox="0 0 24 24" pointer-events="all"> <title>Following system colour scheme</title> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <circle cx="12" cy="12" r="9"></circle> <path d="M12 3v18m0-12l4.65-4.65M12 14.3l7.37-7.37M12 19.6l8.85-8.85"></path> </svg> </symbol> <symbol id="svg-moon" viewBox="0 0 24 24" pointer-events="all"> <title>Selected dark colour scheme</title> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <path stroke="none" d="M0 0h24v24H0z" fill="none"></path> <path d="M12 3c.132 0 .263 0 .393 0a7.5 7.5 0 0 0 7.92 12.446a9 9 0 1 1 -8.313 -12.454z"></path> </svg> </symbol> <symbol id="svg-sun" viewBox="0 0 24 24" pointer-events="all"> <title>Selected light colour scheme</title> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <circle cx="12" cy="12" r="5"></circle> <line x1="12" y1="1" x2="12" y2="3"></line> <line x1="12" y1="21" x2="12" y2="23"></line> <line x1="4.22" y1="4.22" x2="5.64" y2="5.64"></line> <line x1="18.36" y1="18.36" x2="19.78" y2="19.78"></line> <line x1="1" y1="12" x2="3" y2="12"></line> <line x1="21" y1="12" x2="23" y2="12"></line> <line x1="4.22" y1="19.78" x2="5.64" y2="18.36"></line> <line x1="18.36" y1="5.64" x2="19.78" y2="4.22"></line> </svg> </symbol> </svg> <script> document.documentElement.dataset.colour_scheme = localStorage.getItem("colour_scheme") || "auto" </script> <section id="pep-page-section"> <header> <h1>Python Enhancement Proposals</h1> <ul class="breadcrumbs"> <li><a href="https://www.python.org/" title="The Python Programming Language">Python</a> » </li> <li><a href="../pep-0000/">PEP Index</a> » </li> <li>PEP 475</li> </ul> <button id="colour-scheme-cycler" onClick="setColourScheme(nextColourScheme())"> <svg aria-hidden="true" class="colour-scheme-icon-when-auto"><use href="#svg-sun-half"></use></svg> <svg aria-hidden="true" class="colour-scheme-icon-when-dark"><use href="#svg-moon"></use></svg> <svg aria-hidden="true" class="colour-scheme-icon-when-light"><use href="#svg-sun"></use></svg> <span class="visually-hidden">Toggle light / dark / auto colour theme</span> </button> </header> <article> <section id="pep-content"> <h1 class="page-title">PEP 475 – Retry system calls failing with EINTR</h1> <dl class="rfc2822 field-list simple"> <dt class="field-odd">Author<span class="colon">:</span></dt> <dd class="field-odd">Charles-François Natali <cf.natali at gmail.com>, Victor Stinner <vstinner at python.org></dd> <dt class="field-even">BDFL-Delegate<span class="colon">:</span></dt> <dd class="field-even">Antoine Pitrou <solipsis at pitrou.net></dd> <dt class="field-odd">Status<span class="colon">:</span></dt> <dd class="field-odd"><abbr title="Accepted and implementation complete, or no longer active">Final</abbr></dd> <dt class="field-even">Type<span class="colon">:</span></dt> <dd class="field-even"><abbr title="Normative PEP with a new feature for Python, implementation change for CPython or interoperability standard for the ecosystem">Standards Track</abbr></dd> <dt class="field-odd">Created<span class="colon">:</span></dt> <dd class="field-odd">29-Jul-2014</dd> <dt class="field-even">Python-Version<span class="colon">:</span></dt> <dd class="field-even">3.5</dd> <dt class="field-odd">Resolution<span class="colon">:</span></dt> <dd class="field-odd"><a class="reference external" href="https://mail.python.org/pipermail/python-dev/2015-February/138018.html">Python-Dev message</a></dd> </dl> <hr class="docutils" /> <section id="contents"> <details><summary>Table of Contents</summary><ul class="simple"> <li><a class="reference internal" href="#abstract">Abstract</a></li> <li><a class="reference internal" href="#rationale">Rationale</a><ul> <li><a class="reference internal" href="#interrupted-system-calls">Interrupted system calls</a></li> <li><a class="reference internal" href="#status-in-python-3-4">Status in Python 3.4</a></li> <li><a class="reference internal" href="#use-case-1-don-t-bother-with-signals">Use Case 1: Don’t Bother With Signals</a></li> <li><a class="reference internal" href="#use-case-2-be-notified-of-signals-as-soon-as-possible">Use Case 2: Be notified of signals as soon as possible</a></li> </ul> </li> <li><a class="reference internal" href="#proposal">Proposal</a><ul> <li><a class="reference internal" href="#modified-functions">Modified functions</a></li> <li><a class="reference internal" href="#interruptederror-handling">InterruptedError handling</a></li> </ul> </li> <li><a class="reference internal" href="#backward-compatibility">Backward compatibility</a></li> <li><a class="reference internal" href="#appendix">Appendix</a><ul> <li><a class="reference internal" href="#wakeup-file-descriptor">Wakeup file descriptor</a></li> <li><a class="reference internal" href="#multithreading">Multithreading</a></li> <li><a class="reference internal" href="#signals-on-windows">Signals on Windows</a><ul> <li><a class="reference internal" href="#control-events">Control events</a></li> <li><a class="reference internal" href="#signals">Signals</a></li> <li><a class="reference internal" href="#sigint">SIGINT</a></li> </ul> </li> <li><a class="reference internal" href="#links">Links</a><ul> <li><a class="reference internal" href="#misc">Misc</a></li> <li><a class="reference internal" href="#python-issues-related-to-eintr">Python issues related to EINTR</a></li> <li><a class="reference internal" href="#python-issues-related-to-signals">Python issues related to signals</a></li> </ul> </li> </ul> </li> <li><a class="reference internal" href="#implementation">Implementation</a></li> <li><a class="reference internal" href="#copyright">Copyright</a></li> </ul> </details></section> <section id="abstract"> <h2><a class="toc-backref" href="#abstract" role="doc-backlink">Abstract</a></h2> <p>System call wrappers provided in the standard library should be retried automatically when they fail with <code class="docutils literal notranslate"><span class="pre">EINTR</span></code>, to relieve application code from the burden of doing so.</p> <p>By system calls, we mean the functions exposed by the standard C library pertaining to I/O or handling of other system resources.</p> </section> <section id="rationale"> <h2><a class="toc-backref" href="#rationale" role="doc-backlink">Rationale</a></h2> <section id="interrupted-system-calls"> <h3><a class="toc-backref" href="#interrupted-system-calls" role="doc-backlink">Interrupted system calls</a></h3> <p>On POSIX systems, signals are common. Code calling system calls must be prepared to handle them. Examples of signals:</p> <ul class="simple"> <li>The most common signal is <code class="docutils literal notranslate"><span class="pre">SIGINT</span></code>, the signal sent when CTRL+c is pressed. By default, Python raises a <code class="docutils literal notranslate"><span class="pre">KeyboardInterrupt</span></code> exception when this signal is received.</li> <li>When running subprocesses, the <code class="docutils literal notranslate"><span class="pre">SIGCHLD</span></code> signal is sent when a child process exits.</li> <li>Resizing the terminal sends the <code class="docutils literal notranslate"><span class="pre">SIGWINCH</span></code> signal to the applications running in the terminal.</li> <li>Putting the application in background (ex: press CTRL-z and then type the <code class="docutils literal notranslate"><span class="pre">bg</span></code> command) sends the <code class="docutils literal notranslate"><span class="pre">SIGCONT</span></code> signal.</li> </ul> <p>Writing a C signal handler is difficult: only “async-signal-safe” functions can be called (for example, <code class="docutils literal notranslate"><span class="pre">printf()</span></code> and <code class="docutils literal notranslate"><span class="pre">malloc()</span></code> are not async-signal safe), and there are issues with reentrancy. Therefore, when a signal is received by a process during the execution of a system call, the system call can fail with the <code class="docutils literal notranslate"><span class="pre">EINTR</span></code> error to give the program an opportunity to handle the signal without the restriction on signal-safe functions.</p> <p>This behaviour is system-dependent: on certain systems, using the <code class="docutils literal notranslate"><span class="pre">SA_RESTART</span></code> flag, some system calls are retried automatically instead of failing with <code class="docutils literal notranslate"><span class="pre">EINTR</span></code>. Regardless, Python’s <code class="docutils literal notranslate"><span class="pre">signal.signal()</span></code> function clears the <code class="docutils literal notranslate"><span class="pre">SA_RESTART</span></code> flag when setting the signal handler: all system calls will probably fail with <code class="docutils literal notranslate"><span class="pre">EINTR</span></code> in Python.</p> <p>Since receiving a signal is a non-exceptional occurrence, robust POSIX code must be prepared to handle <code class="docutils literal notranslate"><span class="pre">EINTR</span></code> (which, in most cases, means retry in a loop in the hope that the call eventually succeeds). Without special support from Python, this can make application code much more verbose than it needs to be.</p> </section> <section id="status-in-python-3-4"> <h3><a class="toc-backref" href="#status-in-python-3-4" role="doc-backlink">Status in Python 3.4</a></h3> <p>In Python 3.4, handling the <code class="docutils literal notranslate"><span class="pre">InterruptedError</span></code> exception (<code class="docutils literal notranslate"><span class="pre">EINTR</span></code>’s dedicated exception class) is duplicated at every call site on a case-by-case basis. Only a few Python modules actually handle this exception, and fixes usually took several years to cover a whole module. Example of code retrying <code class="docutils literal notranslate"><span class="pre">file.read()</span></code> on <code class="docutils literal notranslate"><span class="pre">InterruptedError</span></code>:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">while</span> <span class="kc">True</span><span class="p">:</span> <span class="k">try</span><span class="p">:</span> <span class="n">data</span> <span class="o">=</span> <span class="n">file</span><span class="o">.</span><span class="n">read</span><span class="p">(</span><span class="n">size</span><span class="p">)</span> <span class="k">break</span> <span class="k">except</span> <span class="ne">InterruptedError</span><span class="p">:</span> <span class="k">continue</span> </pre></div> </div> <p>List of Python modules in the standard library which handle <code class="docutils literal notranslate"><span class="pre">InterruptedError</span></code>:</p> <ul class="simple"> <li><code class="docutils literal notranslate"><span class="pre">asyncio</span></code></li> <li><code class="docutils literal notranslate"><span class="pre">asyncore</span></code></li> <li><code class="docutils literal notranslate"><span class="pre">io</span></code>, <code class="docutils literal notranslate"><span class="pre">_pyio</span></code></li> <li><code class="docutils literal notranslate"><span class="pre">multiprocessing</span></code></li> <li><code class="docutils literal notranslate"><span class="pre">selectors</span></code></li> <li><code class="docutils literal notranslate"><span class="pre">socket</span></code></li> <li><code class="docutils literal notranslate"><span class="pre">socketserver</span></code></li> <li><code class="docutils literal notranslate"><span class="pre">subprocess</span></code></li> </ul> <p>Other programming languages like Perl, Java and Go retry system calls failing with <code class="docutils literal notranslate"><span class="pre">EINTR</span></code> at a lower level, so that libraries and applications needn’t bother.</p> </section> <section id="use-case-1-don-t-bother-with-signals"> <h3><a class="toc-backref" href="#use-case-1-don-t-bother-with-signals" role="doc-backlink">Use Case 1: Don’t Bother With Signals</a></h3> <p>In most cases, you don’t want to be interrupted by signals and you don’t expect to get <code class="docutils literal notranslate"><span class="pre">InterruptedError</span></code> exceptions. For example, do you really want to write such complex code for a “Hello World” example?</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">while</span> <span class="kc">True</span><span class="p">:</span> <span class="k">try</span><span class="p">:</span> <span class="nb">print</span><span class="p">(</span><span class="s2">"Hello World"</span><span class="p">)</span> <span class="k">break</span> <span class="k">except</span> <span class="ne">InterruptedError</span><span class="p">:</span> <span class="k">continue</span> </pre></div> </div> <p><code class="docutils literal notranslate"><span class="pre">InterruptedError</span></code> can happen in unexpected places. For example, <code class="docutils literal notranslate"><span class="pre">os.close()</span></code> and <code class="docutils literal notranslate"><span class="pre">FileIO.close()</span></code> may raise <code class="docutils literal notranslate"><span class="pre">InterruptedError</span></code>: see the article <a class="reference external" href="http://alobbs.com/post/54503240599/close-and-eintr">close() and EINTR</a>.</p> <p>The <a class="reference internal" href="#python-issues-related-to-eintr">Python issues related to EINTR</a> section below gives examples of bugs caused by <code class="docutils literal notranslate"><span class="pre">EINTR</span></code>.</p> <p>The expectation in this use case is that Python hides the <code class="docutils literal notranslate"><span class="pre">InterruptedError</span></code> and retries system calls automatically.</p> </section> <section id="use-case-2-be-notified-of-signals-as-soon-as-possible"> <h3><a class="toc-backref" href="#use-case-2-be-notified-of-signals-as-soon-as-possible" role="doc-backlink">Use Case 2: Be notified of signals as soon as possible</a></h3> <p>Sometimes yet, you expect some signals and you want to handle them as soon as possible. For example, you may want to immediately quit a program using the <code class="docutils literal notranslate"><span class="pre">CTRL+c</span></code> keyboard shortcut.</p> <p>Besides, some signals are not interesting and should not disrupt the application. There are two options to interrupt an application on only <em>some</em> signals:</p> <ul class="simple"> <li>Set up a custom signal handler which raises an exception, such as <code class="docutils literal notranslate"><span class="pre">KeyboardInterrupt</span></code> for <code class="docutils literal notranslate"><span class="pre">SIGINT</span></code>.</li> <li>Use a I/O multiplexing function like <code class="docutils literal notranslate"><span class="pre">select()</span></code> together with Python’s signal wakeup file descriptor: see the function <code class="docutils literal notranslate"><span class="pre">signal.set_wakeup_fd()</span></code>.</li> </ul> <p>The expectation in this use case is for the Python signal handler to be executed timely, and the system call to fail if the handler raised an exception – otherwise restart.</p> </section> </section> <section id="proposal"> <h2><a class="toc-backref" href="#proposal" role="doc-backlink">Proposal</a></h2> <p>This PEP proposes to handle EINTR and retries at the lowest level, i.e. in the wrappers provided by the stdlib (as opposed to higher-level libraries and applications).</p> <p>Specifically, when a system call fails with <code class="docutils literal notranslate"><span class="pre">EINTR</span></code>, its Python wrapper must call the given signal handler (using <code class="docutils literal notranslate"><span class="pre">PyErr_CheckSignals()</span></code>). If the signal handler raises an exception, the Python wrapper bails out and fails with the exception.</p> <p>If the signal handler returns successfully, the Python wrapper retries the system call automatically. If the system call involves a timeout parameter, the timeout is recomputed.</p> <section id="modified-functions"> <h3><a class="toc-backref" href="#modified-functions" role="doc-backlink">Modified functions</a></h3> <p>Example of standard library functions that need to be modified to comply with this PEP:</p> <ul class="simple"> <li><code class="docutils literal notranslate"><span class="pre">open()</span></code>, <code class="docutils literal notranslate"><span class="pre">os.open()</span></code>, <code class="docutils literal notranslate"><span class="pre">io.open()</span></code></li> <li>functions of the <code class="docutils literal notranslate"><span class="pre">faulthandler</span></code> module</li> <li><code class="docutils literal notranslate"><span class="pre">os</span></code> functions:<ul> <li><code class="docutils literal notranslate"><span class="pre">os.fchdir()</span></code></li> <li><code class="docutils literal notranslate"><span class="pre">os.fchmod()</span></code></li> <li><code class="docutils literal notranslate"><span class="pre">os.fchown()</span></code></li> <li><code class="docutils literal notranslate"><span class="pre">os.fdatasync()</span></code></li> <li><code class="docutils literal notranslate"><span class="pre">os.fstat()</span></code></li> <li><code class="docutils literal notranslate"><span class="pre">os.fstatvfs()</span></code></li> <li><code class="docutils literal notranslate"><span class="pre">os.fsync()</span></code></li> <li><code class="docutils literal notranslate"><span class="pre">os.ftruncate()</span></code></li> <li><code class="docutils literal notranslate"><span class="pre">os.mkfifo()</span></code></li> <li><code class="docutils literal notranslate"><span class="pre">os.mknod()</span></code></li> <li><code class="docutils literal notranslate"><span class="pre">os.posix_fadvise()</span></code></li> <li><code class="docutils literal notranslate"><span class="pre">os.posix_fallocate()</span></code></li> <li><code class="docutils literal notranslate"><span class="pre">os.pread()</span></code></li> <li><code class="docutils literal notranslate"><span class="pre">os.pwrite()</span></code></li> <li><code class="docutils literal notranslate"><span class="pre">os.read()</span></code></li> <li><code class="docutils literal notranslate"><span class="pre">os.readv()</span></code></li> <li><code class="docutils literal notranslate"><span class="pre">os.sendfile()</span></code></li> <li><code class="docutils literal notranslate"><span class="pre">os.wait3()</span></code></li> <li><code class="docutils literal notranslate"><span class="pre">os.wait4()</span></code></li> <li><code class="docutils literal notranslate"><span class="pre">os.wait()</span></code></li> <li><code class="docutils literal notranslate"><span class="pre">os.waitid()</span></code></li> <li><code class="docutils literal notranslate"><span class="pre">os.waitpid()</span></code></li> <li><code class="docutils literal notranslate"><span class="pre">os.write()</span></code></li> <li><code class="docutils literal notranslate"><span class="pre">os.writev()</span></code></li> <li>special cases: <code class="docutils literal notranslate"><span class="pre">os.close()</span></code> and <code class="docutils literal notranslate"><span class="pre">os.dup2()</span></code> now ignore <code class="docutils literal notranslate"><span class="pre">EINTR</span></code> error, the syscall is not retried</li> </ul> </li> <li><code class="docutils literal notranslate"><span class="pre">select.select()</span></code>, <code class="docutils literal notranslate"><span class="pre">select.poll.poll()</span></code>, <code class="docutils literal notranslate"><span class="pre">select.epoll.poll()</span></code>, <code class="docutils literal notranslate"><span class="pre">select.kqueue.control()</span></code>, <code class="docutils literal notranslate"><span class="pre">select.devpoll.poll()</span></code></li> <li><code class="docutils literal notranslate"><span class="pre">socket.socket()</span></code> methods:<ul> <li><code class="docutils literal notranslate"><span class="pre">accept()</span></code></li> <li><code class="docutils literal notranslate"><span class="pre">connect()</span></code> (except for non-blocking sockets)</li> <li><code class="docutils literal notranslate"><span class="pre">recv()</span></code></li> <li><code class="docutils literal notranslate"><span class="pre">recvfrom()</span></code></li> <li><code class="docutils literal notranslate"><span class="pre">recvmsg()</span></code></li> <li><code class="docutils literal notranslate"><span class="pre">send()</span></code></li> <li><code class="docutils literal notranslate"><span class="pre">sendall()</span></code></li> <li><code class="docutils literal notranslate"><span class="pre">sendmsg()</span></code></li> <li><code class="docutils literal notranslate"><span class="pre">sendto()</span></code></li> </ul> </li> <li><code class="docutils literal notranslate"><span class="pre">signal.sigtimedwait()</span></code>, <code class="docutils literal notranslate"><span class="pre">signal.sigwaitinfo()</span></code></li> <li><code class="docutils literal notranslate"><span class="pre">time.sleep()</span></code></li> </ul> <p>(Note: the <code class="docutils literal notranslate"><span class="pre">selector</span></code> module already retries on <code class="docutils literal notranslate"><span class="pre">InterruptedError</span></code>, but it doesn’t recompute the timeout yet)</p> <p><code class="docutils literal notranslate"><span class="pre">os.close</span></code>, <code class="docutils literal notranslate"><span class="pre">close()</span></code> methods and <code class="docutils literal notranslate"><span class="pre">os.dup2()</span></code> are a special case: they will ignore <code class="docutils literal notranslate"><span class="pre">EINTR</span></code> instead of retrying. The reason is complex but involves behaviour under Linux and the fact that the file descriptor may really be closed even if EINTR is returned. See articles:</p> <ul class="simple"> <li><a class="reference external" href="http://lwn.net/Articles/576478/">Returning EINTR from close()</a></li> <li><a class="reference external" href="http://linux.derkeiler.com/Mailing-Lists/Kernel/2005-09/3000.html">(LKML) Re: [patch 7/7] uml: retry host close() on EINTR</a></li> <li><a class="reference external" href="http://alobbs.com/post/54503240599/close-and-eintr">close() and EINTR</a></li> </ul> <p>The <code class="docutils literal notranslate"><span class="pre">socket.socket.connect()</span></code> method does not retry <code class="docutils literal notranslate"><span class="pre">connect()</span></code> for non-blocking sockets if it is interrupted by a signal (fails with <code class="docutils literal notranslate"><span class="pre">EINTR</span></code>). The connection runs asynchronously in background. The caller is responsible to wait until the socket becomes writable (ex: using <code class="docutils literal notranslate"><span class="pre">select.select()</span></code>) and then call <code class="docutils literal notranslate"><span class="pre">socket.socket.getsockopt(socket.SOL_SOCKET,</span> <span class="pre">socket.SO_ERROR)</span></code> to check if the connection succeeded (<code class="docutils literal notranslate"><span class="pre">getsockopt()</span></code> returns <code class="docutils literal notranslate"><span class="pre">0</span></code>) or failed.</p> </section> <section id="interruptederror-handling"> <h3><a class="toc-backref" href="#interruptederror-handling" role="doc-backlink">InterruptedError handling</a></h3> <p>Since interrupted system calls are automatically retried, the <code class="docutils literal notranslate"><span class="pre">InterruptedError</span></code> exception should not occur anymore when calling those system calls. Therefore, manual handling of <code class="docutils literal notranslate"><span class="pre">InterruptedError</span></code> as described in <a class="reference internal" href="#status-in-python-3-4">Status in Python 3.4</a> can be removed, which will simplify standard library code.</p> </section> </section> <section id="backward-compatibility"> <h2><a class="toc-backref" href="#backward-compatibility" role="doc-backlink">Backward compatibility</a></h2> <p>Applications relying on the fact that system calls are interrupted with <code class="docutils literal notranslate"><span class="pre">InterruptedError</span></code> will hang. The authors of this PEP don’t think that such applications exist, since they would be exposed to other issues such as race conditions (there is an opportunity for deadlock if the signal comes before the system call). Besides, such code would be non-portable.</p> <p>In any case, those applications must be fixed to handle signals differently, to have a reliable behaviour on all platforms and all Python versions. A possible strategy is to set up a signal handler raising a well-defined exception, or use a wakeup file descriptor.</p> <p>For applications using event loops, <code class="docutils literal notranslate"><span class="pre">signal.set_wakeup_fd()</span></code> is the recommended option to handle signals. Python’s low-level signal handler will write signal numbers into the file descriptor and the event loop will be awaken to read them. The event loop can handle those signals without the restriction of signal handlers (for example, the loop can be woken up in any thread, not just the main thread).</p> </section> <section id="appendix"> <h2><a class="toc-backref" href="#appendix" role="doc-backlink">Appendix</a></h2> <section id="wakeup-file-descriptor"> <h3><a class="toc-backref" href="#wakeup-file-descriptor" role="doc-backlink">Wakeup file descriptor</a></h3> <p>Since Python 3.3, <code class="docutils literal notranslate"><span class="pre">signal.set_wakeup_fd()</span></code> writes the signal number into the file descriptor, whereas it only wrote a null byte before. It becomes possible to distinguish between signals using the wakeup file descriptor.</p> <p>Linux has a <code class="docutils literal notranslate"><span class="pre">signalfd()</span></code> system call which provides more information on each signal. For example, it’s possible to know the pid and uid who sent the signal. This function is not exposed in Python yet (see <a class="reference external" href="http://bugs.python.org/issue12304">issue 12304</a>).</p> <p>On Unix, the <code class="docutils literal notranslate"><span class="pre">asyncio</span></code> module uses the wakeup file descriptor to wake up its event loop.</p> </section> <section id="multithreading"> <h3><a class="toc-backref" href="#multithreading" role="doc-backlink">Multithreading</a></h3> <p>A C signal handler can be called from any thread, but Python signal handlers will always be called in the main Python thread.</p> <p>Python’s C API provides the <code class="docutils literal notranslate"><span class="pre">PyErr_SetInterrupt()</span></code> function which calls the <code class="docutils literal notranslate"><span class="pre">SIGINT</span></code> signal handler in order to interrupt the main Python thread.</p> </section> <section id="signals-on-windows"> <h3><a class="toc-backref" href="#signals-on-windows" role="doc-backlink">Signals on Windows</a></h3> <section id="control-events"> <h4><a class="toc-backref" href="#control-events" role="doc-backlink">Control events</a></h4> <p>Windows uses “control events”:</p> <ul class="simple"> <li><code class="docutils literal notranslate"><span class="pre">CTRL_BREAK_EVENT</span></code>: Break (<code class="docutils literal notranslate"><span class="pre">SIGBREAK</span></code>)</li> <li><code class="docutils literal notranslate"><span class="pre">CTRL_CLOSE_EVENT</span></code>: Close event</li> <li><code class="docutils literal notranslate"><span class="pre">CTRL_C_EVENT</span></code>: CTRL+C (<code class="docutils literal notranslate"><span class="pre">SIGINT</span></code>)</li> <li><code class="docutils literal notranslate"><span class="pre">CTRL_LOGOFF_EVENT</span></code>: Logoff</li> <li><code class="docutils literal notranslate"><span class="pre">CTRL_SHUTDOWN_EVENT</span></code>: Shutdown</li> </ul> <p>The <a class="reference external" href="http://msdn.microsoft.com/en-us/library/windows/desktop/ms686016%28v=vs.85%29.aspx">SetConsoleCtrlHandler() function</a> can be used to install a control handler.</p> <p>The <code class="docutils literal notranslate"><span class="pre">CTRL_C_EVENT</span></code> and <code class="docutils literal notranslate"><span class="pre">CTRL_BREAK_EVENT</span></code> events can be sent to a process using the <a class="reference external" href="http://msdn.microsoft.com/en-us/library/windows/desktop/ms683155%28v=vs.85%29.aspx">GenerateConsoleCtrlEvent() function</a>. This function is exposed in Python as <code class="docutils literal notranslate"><span class="pre">os.kill()</span></code>.</p> </section> <section id="signals"> <h4><a class="toc-backref" href="#signals" role="doc-backlink">Signals</a></h4> <p>The following signals are supported on Windows:</p> <ul class="simple"> <li><code class="docutils literal notranslate"><span class="pre">SIGABRT</span></code></li> <li><code class="docutils literal notranslate"><span class="pre">SIGBREAK</span></code> (<code class="docutils literal notranslate"><span class="pre">CTRL_BREAK_EVENT</span></code>): signal only available on Windows</li> <li><code class="docutils literal notranslate"><span class="pre">SIGFPE</span></code></li> <li><code class="docutils literal notranslate"><span class="pre">SIGILL</span></code></li> <li><code class="docutils literal notranslate"><span class="pre">SIGINT</span></code> (<code class="docutils literal notranslate"><span class="pre">CTRL_C_EVENT</span></code>)</li> <li><code class="docutils literal notranslate"><span class="pre">SIGSEGV</span></code></li> <li><code class="docutils literal notranslate"><span class="pre">SIGTERM</span></code></li> </ul> </section> <section id="sigint"> <h4><a class="toc-backref" href="#sigint" role="doc-backlink">SIGINT</a></h4> <p>The default Python signal handler for <code class="docutils literal notranslate"><span class="pre">SIGINT</span></code> sets a Windows event object: <code class="docutils literal notranslate"><span class="pre">sigint_event</span></code>.</p> <p><code class="docutils literal notranslate"><span class="pre">time.sleep()</span></code> is implemented with <code class="docutils literal notranslate"><span class="pre">WaitForSingleObjectEx()</span></code>, it waits for the <code class="docutils literal notranslate"><span class="pre">sigint_event</span></code> object using <code class="docutils literal notranslate"><span class="pre">time.sleep()</span></code> parameter as the timeout. So the sleep can be interrupted by <code class="docutils literal notranslate"><span class="pre">SIGINT</span></code>.</p> <p><code class="docutils literal notranslate"><span class="pre">_winapi.WaitForMultipleObjects()</span></code> automatically adds <code class="docutils literal notranslate"><span class="pre">sigint_event</span></code> to the list of watched handles, so it can also be interrupted.</p> <p><code class="docutils literal notranslate"><span class="pre">PyOS_StdioReadline()</span></code> also used <code class="docutils literal notranslate"><span class="pre">sigint_event</span></code> when <code class="docutils literal notranslate"><span class="pre">fgets()</span></code> failed to check if Ctrl-C or Ctrl-Z was pressed.</p> </section> </section> <section id="links"> <h3><a class="toc-backref" href="#links" role="doc-backlink">Links</a></h3> <section id="misc"> <h4><a class="toc-backref" href="#misc" role="doc-backlink">Misc</a></h4> <ul class="simple"> <li><a class="reference external" href="http://www.gnu.org/software/libc/manual/html_node/Interrupted-Primitives.html">glibc manual: Primitives Interrupted by Signals</a></li> <li><a class="reference external" href="https://rt.perl.org/Public/Bug/Display.html?id=119097">Bug #119097 for perl5: print returning EINTR in 5.14</a>.</li> </ul> </section> <section id="python-issues-related-to-eintr"> <h4><a class="toc-backref" href="#python-issues-related-to-eintr" role="doc-backlink">Python issues related to EINTR</a></h4> <p>The main issue is: <a class="reference external" href="http://bugs.python.org/issue18885">handle EINTR in the stdlib</a>.</p> <p>Open issues:</p> <ul class="simple"> <li><a class="reference external" href="http://bugs.python.org/issue22018">Add a new signal.set_wakeup_socket() function</a></li> <li><a class="reference external" href="http://bugs.python.org/issue22042">signal.set_wakeup_fd(fd): set the fd to non-blocking mode</a></li> <li><a class="reference external" href="http://bugs.python.org/issue22043">Use a monotonic clock to compute timeouts</a></li> <li><a class="reference external" href="http://bugs.python.org/issue22007">sys.stdout.write on OS X is not EINTR safe</a></li> <li><a class="reference external" href="http://bugs.python.org/issue21772">platform.uname() not EINTR safe</a></li> <li><a class="reference external" href="http://bugs.python.org/issue11266">asyncore does not handle EINTR in recv, send, connect, accept,</a></li> <li><a class="reference external" href="http://bugs.python.org/issue20611">socket.create_connection() doesn’t handle EINTR properly</a></li> </ul> <p>Closed issues:</p> <ul class="simple"> <li><a class="reference external" href="http://bugs.python.org/issue9867">Interrupted system calls are not retried</a></li> <li><a class="reference external" href="http://bugs.python.org/issue1049450">Solaris: EINTR exception in select/socket calls in telnetlib</a></li> <li><a class="reference external" href="http://bugs.python.org/issue12493">subprocess: Popen.communicate() doesn’t handle EINTR in some cases</a></li> <li><a class="reference external" href="http://bugs.python.org/issue12338">multiprocessing.util._eintr_retry doesn’t recalculate timeouts</a></li> <li><a class="reference external" href="http://bugs.python.org/issue12268">file readline, readlines & readall methods can lose data on EINTR</a></li> <li><a class="reference external" href="http://bugs.python.org/issue17097">multiprocessing BaseManager serve_client() does not check EINTR on recv</a></li> <li><a class="reference external" href="http://bugs.python.org/issue19849">selectors behaviour on EINTR undocumented</a></li> <li><a class="reference external" href="http://bugs.python.org/issue19850">asyncio: limit EINTR occurrences with SA_RESTART</a></li> <li><a class="reference external" href="http://bugs.python.org/issue21602">smtplib.py socket.create_connection() also doesn’t handle EINTR properly</a></li> <li><a class="reference external" href="http://bugs.python.org/issue11650">Faulty RESTART/EINTR handling in Parser/myreadline.c</a></li> <li><a class="reference external" href="http://bugs.python.org/issue3771">test_httpservers intermittent failure, test_post and EINTR</a></li> <li><a class="reference external" href="http://bugs.python.org/issue686667">os.spawnv(P_WAIT, …) on Linux doesn’t handle EINTR</a></li> <li><a class="reference external" href="http://bugs.python.org/issue517554">asyncore fails when EINTR happens in pol</a></li> <li><a class="reference external" href="http://bugs.python.org/issue10956">file.write and file.read don’t handle EINTR</a></li> <li><a class="reference external" href="http://bugs.python.org/issue1628205">socket.readline() interface doesn’t handle EINTR properly</a></li> <li><a class="reference external" href="http://bugs.python.org/issue1068268">subprocess is not EINTR-safe</a></li> <li><a class="reference external" href="http://bugs.python.org/issue7978">SocketServer doesn’t handle syscall interruption</a></li> <li><a class="reference external" href="http://bugs.python.org/issue17367">subprocess deadlock when read() is interrupted</a></li> <li><a class="reference external" href="http://bugs.python.org/issue12462">time.sleep(1): call PyErr_CheckSignals() if the sleep was interrupted</a></li> <li><a class="reference external" href="http://bugs.python.org/issue8354">siginterrupt with flag=False is reset when signal received</a></li> <li><a class="reference external" href="http://bugs.python.org/issue1089358">need siginterrupt() on Linux - impossible to do timeouts</a></li> <li><a class="reference external" href="http://bugs.python.org/issue581232">[Windows] Can not interrupt time.sleep()</a></li> </ul> </section> <section id="python-issues-related-to-signals"> <h4><a class="toc-backref" href="#python-issues-related-to-signals" role="doc-backlink">Python issues related to signals</a></h4> <p>Open issues:</p> <ul class="simple"> <li><a class="reference external" href="http://bugs.python.org/issue17182">signal.default_int_handler should set signal number on the raised exception</a></li> <li><a class="reference external" href="http://bugs.python.org/issue12304">expose signalfd(2) in the signal module</a></li> <li><a class="reference external" href="http://bugs.python.org/issue14484">missing return in win32_kill?</a></li> <li><a class="reference external" href="http://bugs.python.org/issue3180">Interrupts are lost during readline PyOS_InputHook processing</a></li> <li><a class="reference external" href="http://bugs.python.org/issue1687125">cannot catch KeyboardInterrupt when using curses getkey()</a></li> <li><a class="reference external" href="http://bugs.python.org/issue16151">Deferred KeyboardInterrupt in interactive mode</a></li> </ul> <p>Closed issues:</p> <ul class="simple"> <li><a class="reference external" href="http://bugs.python.org/issue753733">sys.interrupt_main()</a></li> </ul> </section> </section> </section> <section id="implementation"> <h2><a class="toc-backref" href="#implementation" role="doc-backlink">Implementation</a></h2> <p>The implementation is tracked in <a class="reference external" href="http://bugs.python.org/issue23285">issue 23285</a>. It was committed on February 07, 2015.</p> </section> <section id="copyright"> <h2><a class="toc-backref" href="#copyright" role="doc-backlink">Copyright</a></h2> <p>This document has been placed in the public domain.</p> </section> </section> <hr class="docutils" /> <p>Source: <a class="reference external" href="https://github.com/python/peps/blob/main/peps/pep-0475.rst">https://github.com/python/peps/blob/main/peps/pep-0475.rst</a></p> <p>Last modified: <a class="reference external" href="https://github.com/python/peps/commits/main/peps/pep-0475.rst">2025-02-01 08:59:27 GMT</a></p> </article> <nav id="pep-sidebar"> <h2>Contents</h2> <ul> <li><a class="reference internal" href="#abstract">Abstract</a></li> <li><a class="reference internal" href="#rationale">Rationale</a><ul> <li><a class="reference internal" href="#interrupted-system-calls">Interrupted system calls</a></li> <li><a class="reference internal" href="#status-in-python-3-4">Status in Python 3.4</a></li> <li><a class="reference internal" href="#use-case-1-don-t-bother-with-signals">Use Case 1: Don’t Bother With Signals</a></li> <li><a class="reference internal" href="#use-case-2-be-notified-of-signals-as-soon-as-possible">Use Case 2: Be notified of signals as soon as possible</a></li> </ul> </li> <li><a class="reference internal" href="#proposal">Proposal</a><ul> <li><a class="reference internal" href="#modified-functions">Modified functions</a></li> <li><a class="reference internal" href="#interruptederror-handling">InterruptedError handling</a></li> </ul> </li> <li><a class="reference internal" href="#backward-compatibility">Backward compatibility</a></li> <li><a class="reference internal" href="#appendix">Appendix</a><ul> <li><a class="reference internal" href="#wakeup-file-descriptor">Wakeup file descriptor</a></li> <li><a class="reference internal" href="#multithreading">Multithreading</a></li> <li><a class="reference internal" href="#signals-on-windows">Signals on Windows</a><ul> <li><a class="reference internal" href="#control-events">Control events</a></li> <li><a class="reference internal" href="#signals">Signals</a></li> <li><a class="reference internal" href="#sigint">SIGINT</a></li> </ul> </li> <li><a class="reference internal" href="#links">Links</a><ul> <li><a class="reference internal" href="#misc">Misc</a></li> <li><a class="reference internal" href="#python-issues-related-to-eintr">Python issues related to EINTR</a></li> <li><a class="reference internal" href="#python-issues-related-to-signals">Python issues related to signals</a></li> </ul> </li> </ul> </li> <li><a class="reference internal" href="#implementation">Implementation</a></li> <li><a class="reference internal" href="#copyright">Copyright</a></li> </ul> <br> <a id="source" href="https://github.com/python/peps/blob/main/peps/pep-0475.rst">Page Source (GitHub)</a> </nav> </section> <script src="../_static/colour_scheme.js"></script> <script src="../_static/wrap_tables.js"></script> <script src="../_static/sticky_banner.js"></script> </body> </html>