On 08/12/2007, <b class="gmail_sendername">Guido van Rossum</b> <<a href="mailto:guido@python.org">guido@python.org</a>> 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 9:57 AM, Gustavo Carneiro <<a href="mailto:gjcarneiro@gmail.com">gjcarneiro@gmail.com</a>> wrote:<br>> On 08/12/2007, Guido van Rossum <<a href="mailto:guido@python.org">guido@python.org</a>> wrote:
<br>><br>> > On Dec 8, 2007 3:58 AM, Gustavo Carneiro <<a href="mailto:gjcarneiro@gmail.com">gjcarneiro@gmail.com</a>> wrote:<br>> > > Not only that, but pygtk is a generic module;<br>> ><br>
> > What does "generic" mean in this context? Surely not that it applies<br>> > to other libraries than GTK?<br>><br>> Well, actually this is also a PyGObject issue, not only PyGtk. PyGObject<br>
> wraps GLib. GLib was created to serve the needs of Gtk+, but is useful by<br>> itself for writing portable programs. Among other things, GLib offers a<br>> generic "main loop", which programs can use to do generic event-driven
<br>> programming, such as timeouts, polling file descriptors, and doing other<br>> work when the main loop becomes idle.<br>><br>> You could argue that non-gtk programs are rare and we shouldn't worry too
<br>> much about them. Maybe it's true, I don't know.<br>><br>><br>> > > who are we to forbid the usage<br>> > > of signals if python itself allows it? If we were to ignore signals<br>
> then<br>> > > sooner or later someone would come along and shout "hey, signals work<br>> just<br>> > > fine in pure python, so why did pygtk have to break my signals?".<br>> ><br>
> > Um, signals don't "work just fine" in pure Python. And I would argue<br>> > they don't either in C. They are extremely subtle, and most code using<br>> > signals is broken in some way. Just try to read the sigaction() man
<br>> > page and claim you understand it.<br>> ><br>> > Unfortunately, in Unix there are some conditions that can only be<br>> > delivered using signals (e.g. SIGINTR, SIGTERM) and others for which
<br>> > your choices are either polling or signals (SIGCHILD, SIGWINCH).<br>> > Traditionally, solutions based on select() or poll() with a short<br>> > timeout (e.g. 20 or 100 ms) have worked well, as the number of
<br>> > instructions executed each time is really negligeable, and the<br>> > response time is still reasonable on a human time scale. Unfortunately<br>> > it seems recent developments in power management for ultra-low power
<br>> > devices have made this an issue again.<br>> ><br>> > Windows solves this more elegantly by having a unified "wait for<br>> > multiple conditions" system call which can wait on I/O, semaphores,
<br>> > and other events (within the same process or coming from other<br>> > processes). Unfortunately, in Unix, some events don't have a file<br>> > descriptor associated with them, and for those select()/poll() cannot
<br>> > be used.<br>> ><br>> > The best solution I can think of is to add a new API that takes a<br>> > signal and a file descriptor and registers a C-level handler for that<br>> > signal which writes a byte to the file descriptor. You can then create
<br>> > a pipe, connect the signal handler to the write end, and add the read<br>> > end to your list of file descriptors passed to select() or poll(). The<br>> > handler must be written in C in order to avoid the race condition
<br>> > referred to by Glyph (signals arriving after the signal check in the<br>> > VM main loop but before the select()/poll() system call is entered<br>> > will not be noticed until the select()/poll() call completes).
<br>><br>> Funny that everyone mentions this solution, as it is the solution<br>> implemented by my patch :-)<br><br>Mind pointing me to it again? I can't find it in the Python bug tracker.<br><br>> Well, to be fair, it might not be _exactly_ what is implemented by the
<br>> patch. Reading between the lines, I think what you mean is to have python's<br>> C signal handler mostly untouched; it would only write a byte to a pipe _in<br>> addition to_ the normal setting the flag and Py_AddPendingCall.
<br><br>Well, in many cases I see no problems with the current signal handler,<br>and people are used to it, so I'm not sure what is gained by getting<br>rid of it.<br><br>> The patch I submitted, on the other hand, completely removes the vector of
<br>> flags and Py_AddPendingCall, and instead writes the number of the signal<br>> that was raised into the pipe, and reads it back from the pipe in the Python<br>> main loop.<br><br>I believe Py_AddPendingCall was meant to be used by other places
<br>besides the signal handling.</blockquote><div><br>True. The patch does not remove Py_AddPendingCall, only stops using it for signals.<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;">
> Which is the best solution? I think my patch fixes two problems: 1. the<br>> need to have a FD to wake up poll() (t o fix the problem with what we are<br>> discussing in this thread), and 2. make Python's signal handling more
<br>> reliable (not 100% reliable because it doesn't handle longer bursts of<br>> signals than the pipe buffer can take, but at least is race free).<br><br>I think it's okay to drop signals if too many come. The FD should be
<br>put in non-blocking mode so the signal handler won't block forever.<br>Does Unix even promise that a signal gets delivered twice if it gets<br>sent quickly twice in a row?</blockquote><div><br>Good point.<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;">> My solution is being reject because people are afraid to touch the signal<br>> handling code, which has its faults, but well know faults. But if I
<br>> refactor the patch to keep the crappy-but-sort-of-working signal code, and<br>> only enhance it with the pipe, maybe it will more likely get accepted.<br>><br>> Do I understand correctly? :-)<br><br>Not really; I don't recall seeing your patch. And I object to your
<br>subjective description of the existing signal handling; it has served<br>us well enough.</blockquote><div><br>Sorry. I have to say existing code is very bad in order to convince people it is worth changing... :P<br><br>
Anyway, the approach of writing to a pipe and reading it back later appears (to me) simpler to read and understand. That should also count for something, right?<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 have a worry though -- if signal handlers *always* and *only*<br>communicate by writing a byte to a FD, does that mean that the VM main<br>loop will have to attempt to read a byte from a pipe every time it<br>checks for signals? That sounds very expensive for something that's
<br>not needed by the vast majority of Python applications.</blockquote><div><br>Yes, it would be expensive. Instead the patch uses a simple global boolean value, set to true when a signal is received, after writing to the pipe. PyErr_CheckSignals() does not try to read from the pipe unless that value is true.
<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;"> Plus, you will<br>have to expose the FD to the user so that it can be included in
<br>select() and poll() calls.</blockquote><div><br>Correct. <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;">Anyway, let's see the patch first.
</blockquote><div><br><a href="http://bugs.python.org/issue1564547">http://bugs.python.org/issue1564547</a><br></div></div><br>-- <br>Gustavo J. A. M. Carneiro<br>INESC Porto, Telecommunications and Multimedia Unit<br>"The universe is always one step beyond logic." -- Frank Herbert