On 09/12/2007, <b class="gmail_sendername">Guido van Rossum</b> &lt;<a href="mailto:guido@python.org">guido@python.org</a>&gt; wrote:<div><span class="gmail_quote"></span><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">
On Dec 8, 2007 3:57 PM, Adam Olsen &lt;<a href="mailto:rhamph@gmail.com">rhamph@gmail.com</a>&gt; wrote:<br>&gt;<br>&gt; On Dec 8, 2007 4:28 PM, Guido van Rossum &lt;<a href="mailto:guido@python.org">guido@python.org</a>&gt; wrote:
<br>&gt; &gt;<br>&gt; &gt; On Dec 8, 2007 2:36 PM, Adam Olsen &lt;<a href="mailto:rhamph@gmail.com">rhamph@gmail.com</a>&gt; wrote:<br>&gt; &gt; &gt; On Dec 8, 2007 2:56 PM,&nbsp;&nbsp;&lt;<a href="mailto:glyph@divmod.com">glyph@divmod.com
</a>&gt; wrote:<br>&gt; &gt; &gt; &gt; On 05:20 pm, <a href="mailto:guido@python.org">guido@python.org</a> wrote:<br>&gt; &gt; &gt; &gt; &gt;The best solution I can think of is to add a new API that takes a<br>&gt; &gt; &gt; &gt; &gt;signal and a file descriptor and registers a C-level handler for that
<br>&gt; &gt; &gt; &gt; &gt;signal which writes a byte to the file descriptor. You can then create<br>&gt; &gt; &gt; &gt; &gt;a pipe, connect the signal handler to the write end, and add the read<br>&gt; &gt; &gt; &gt; &gt;end to your list of file descriptors passed to select() or poll(). The
<br>&gt; &gt; &gt; &gt; &gt;handler must be written in C in order to avoid the race condition<br>&gt; &gt; &gt; &gt; &gt;referred to by Glyph (signals arriving after the signal check in the<br>&gt; &gt; &gt; &gt; &gt;VM main loop but before the select()/poll() system call is entered
<br>&gt; &gt; &gt; &gt; &gt;will not be noticed until the select()/poll() call completes).<br>&gt; &gt; &gt; &gt;<br>&gt; &gt; &gt; &gt; This paragraph jogged my memory.&nbsp;&nbsp;I remember this exact solution being<br>&gt; &gt; &gt; &gt; discussed now, a year ago when I was last talking about these issues.
<br>&gt; &gt; &gt; &gt;<br>&gt; &gt; &gt; &gt; There&#39;s another benefit to implementing a write-a-byte C signal handler.<br>&gt; &gt; &gt; &gt; Without this feature, it wouldn&#39;t make sense to have passed the<br>&gt; &gt; &gt; &gt; SA_RESTART flag to sigaction, because and GUIs written in Python could
<br>&gt; &gt; &gt; &gt; have spent an indefinite amount of time waiting to deliver their signal<br>&gt; &gt; &gt; &gt; to Python code.&nbsp;&nbsp;So, if you had to handle SIGCHLD in Python, for<br>&gt; &gt; &gt; &gt; example, calls like file().write() would suddenly start raising a new
<br>&gt; &gt; &gt; &gt; exception (EINTR).&nbsp;&nbsp;With it, you could avoid a whole class of subtle<br>&gt; &gt; &gt; &gt; error-handling code in Twisted programs.<br>&gt; &gt; &gt;<br>&gt; &gt; &gt; SA_RESTART still isn&#39;t useful.&nbsp;&nbsp;The low-level poll call (not write!)
<br>&gt; &gt; &gt; must stop and call back into python.&nbsp;&nbsp;If that doesn&#39;t indicate an<br>&gt; &gt; &gt; error you can safely restart your poll call though, and follow it with<br>&gt; &gt; &gt; a (probably non-blocking) write.
<br>&gt; &gt;<br>&gt; &gt; Can&#39;t say I understand all of this, but it does reiterate that there<br>&gt; &gt; are more problems with signals than just the issue that Gustavo is<br>&gt; &gt; trying to squash. The possibility of having *any* I/O interrupted is
<br>&gt; &gt; indeed a big worry. Though perhaps this could be alleviated by rigging<br>&gt; &gt; things so that signals get delivered (at the C level) to the main<br>&gt; &gt; thread and the rest of the code runs in a non-main thread?
<br>&gt;<br>&gt; That&#39;s the approach my threading patch will take, although reversed<br>&gt; (signals are handled by a background thread, leaving the main thread<br>&gt; as the *main* thread.)<br><br>Hm... Does this mean you&#39;re *always* creating an extra thread to handle signals?
<br><br>&gt; I share your concern about interrupting whatever random syscalls (not<br>&gt; even limited to I/O!) that a library happens to use.<br>&gt;<br>&gt;<br>&gt; &gt; &gt; Note that the only reason to use C for a low-level handler here is
<br>&gt; &gt; &gt; give access to sigatomic_t and avoid needing locks.&nbsp;&nbsp;If you ran the<br>&gt; &gt; &gt; signal handler in a background thread (using sigwait to trigger them)<br>&gt; &gt; &gt; you could use a python handler.
<br>&gt; &gt;<br>&gt; &gt; I haven&#39;t seen Gustavo&#39;s patch yet, but *my* reason for using a C<br>&gt; &gt; handler was different -- it was because writing a byte to a pipe in<br>&gt; &gt; Python would do nothing to fix Gustavo&#39;s issue.
<br>&gt; &gt;<br>&gt; &gt; Looking at the man page for sigwait()&nbsp;&nbsp;it could be an alternative<br>&gt; &gt; solution, but I&#39;m not sure how it would actually allow PyGTK to catch<br>&gt; &gt; KeyboardInterrupt.<br>&gt;<br>
&gt; My mail at [1] was referring to this.&nbsp;&nbsp;Option 1 involved writing to a<br>&gt; pipe that gets polled while option 2 requires we generate a new signal<br>&gt; targeting the specific thread we want to interrupt.<br>&gt;
<br>&gt; I&#39;d like to propose an interim solution though: pygtk could install<br>&gt; their own SIGINT handler during the gtk mainloop (or all gtk code?),<br>&gt; have it write to a pipe monitored by gtk, and have gtk raise
<br>&gt; KeyboardInterrupt if it gets used.&nbsp;&nbsp;This won&#39;t allow custom SIGINT<br>&gt; handlers or any other signal handlers to run promptly, but it should<br>&gt; be good enough for OLPC&#39;s use case.<br>&gt;<br>&gt;<br>
&gt; [1] <a href="http://mail.python.org/pipermail/python-dev/2007-December/075607.html">http://mail.python.org/pipermail/python-dev/2007-December/075607.html</a><br><br>Since OLPC has to use 2.5 they don&#39;t really have another choice
<br>besides this or making the timeout (perhaps much) larger -- I&#39;m not<br>going to risk a change as big as anything proposed here for 2.5.2, so<br>nothing will change before 2.6.<br><br>I&#39;ve got to say that all the cross-referencing and asynchronous
<br>discussion here makes it *very* difficult to wrap my head around the<br>various proposals. It also doesn&#39;t help that different participants<br>appear to have different use cases in mind. E.g. do we care about<br>threads started directly from C++ code? (These happen all the time at
<br>Google, but we don&#39;t care much about signals.) And what about<br>restarting system calls (like Glyph brought up)?<br><br>I&#39;ve seen references to bug #1643738 which got a thumbs up from Tim<br>Peters -- Adam, what do you think of that? I know it doesn&#39;t address
<br>Gustavo&#39;s issue but it seems useful in its own right.</blockquote><div><br>That issue seems orthogonal.&nbsp; Just fixes the current async handling code.&nbsp; See how complicated and error prone the current code is?&nbsp; It&#39;s so easy to get race conditions... The pipe solution is much simpler IMHO, less error prone... ;-)
<br><br>But, well, maybe it&#39;s just me that thinks it&#39;s simpler and no one else.&nbsp; That&#39;s life.. :|<br></div><br><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">
Gustavo, at some point you suggested making changes to Python so that<br>all signals are blocked in all threads except for the main thread. I<br>think I&#39;d be more inclined to give that the green light than the patch<br>
using pipes for all signal handling, as long as we can make sure that<br>this blocking of all signals isn&#39;t inherited by fork()&#39;ed children --<br>we had serious problems with that in 2.4 where child processes were
<br>unkillable (except for SIGKILL).</blockquote><div><br>I don&#39;t think that solution works after all.&nbsp; We can only block signals for certain threads inside the threads themselves.&nbsp; But we do not control all threads.&nbsp; Some are created by C libraries, and these threads will not have signals blocked by default, and also there is no &#39;thread creation hook&#39; that we can use.
<br><br>More promising would be pthread_kill solution suggested by loewis.&nbsp; It&#39;s not a bad solution, but&nbsp; it does nothing to improve the possible race conditions in signal handling.&nbsp; Also it is not &quot;theoretically&quot; safe to call in signal handlers, as far as I can tell.&nbsp; At least it&#39;s not on the list of safe functions to call in async handlers: 
<a href="http://www.opengroup.org/onlinepubs/009695399/functions/xsh_chap02_04.html#tag_02_04_03">http://www.opengroup.org/onlinepubs/009695399/functions/xsh_chap02_04.html#tag_02_04_03</a><br></div><br><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">
 I&#39;d also be OK with a patch that<br>leaves the existing signal handling code intact but *adds* a way to<br>have a signal handler written in C that writes one byte to one end of<br>a pipe -- where the pipe is provided by Python code.
</blockquote><div><br>I think this is most balanced approach of all. <br></div><br><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">Does any of this make sense still?
<br><br>Anyway, I would still like to discuss this on #python-dev Monday.<br>Adam, in what time zone are you? (I&#39;m PST.) Who else is interested?</blockquote><div><br>I&#39;ll try to show up if I have time.<br></div></div>
<br>-- <br>Gustavo J. A. M. Carneiro<br>INESC Porto, Telecommunications and Multimedia Unit<br>&quot;The universe is always one step beyond logic.&quot; -- Frank Herbert