embedded python - cancel "while 1: pass"

Tim Peters tim.one at home.com
Fri Jan 5 13:36:07 EST 2001


[Warren Postma]
> ...
> I have decided to patch Python 1.5.2 to have thread-based
> signals.
>
> I noticed a comment in ceval.c, that said someone else has the
> same thought as me, was it Guido?

The comment is Guido's, but his goal was not the same.

> [Guido's comment, from ceval.c]
> There are two possible race conditions:
>    (1) nested asynchronous registry calls;
>    (2) registry calls made while pending calls are being
>        processed.
>    While (1) is very unlikely, (2) is a real possibility.
>    The current code is safe against (2), but not against (1).
>    The safety against (2) is derived from the fact that only
>    one thread (the main thread) ever takes things out of the queue.
>
> XXX Darn!  With the advent of thread state, we should have an array
>    of pending calls per thread in the thread state!  Later...
>
> -- (end snippet) --
>
> Since Pharlap has no "registry", I don't know what equivalent trouble
> "nested asynchronous registry calls" might get me in on PharLap,

Guido was writing in Dutch there:  his use of "registry" has nothing to do
with Windows.  What he means by "registry call" is "a call to
Py_AddPendingCall", the function which "registers" (in Dutch -- or, for that
matter, also in English <wink>) the callback function to be invoked later.
Note the comment at the start of Py_AddPendingCall:

	/* XXX Begin critical section */
	/* XXX If you want this to be safe against nested
	   XXX asynchronous calls, you'll have to work harder! */

It's getting at the same thing.  Py_AddPendingCall does not have proper
mutual exclusion (the comment *says* "critical section" but the code doesn't
implement one!), and it *is* subject to race condition #1, as explained in
the previous comment.  "Nested" isn't quite the right word, though:  if two
threads each call Py_AddPendingCall close in time, it's possible for both of
them to see busy==0 upon entry to Py_AddPendingCall, and so for both of them
to enter the body simultaneously.  Madness will ensue.  Python itself never
makes calls like that now, but if you're using the mechanism for more, you
may.  *If* it had per-thread queues of pending calls (as suggested in the
first comment), that problem would go away.  As I mentioned in a previous
msg, this (a per-thread queue) would be one of the things easier to
implement if we first had a portable thread-local storage mechanism to build
on.

> but so far, so good. I have removed the checks to see if thread id
> == main_thread.

Then you've also taken away the current code's protection against Guido's
race condition #2.  As you quoted him above:

    The safety against (2) is derived from the fact that only
    one thread (the main thread) ever takes things out of the queue.

It's in the nature of race conditions that they're erratic, so there's no
assurance in "so far, so good".  The comments are telling you what *is*
going to go wrong, sooner or later -- it's just a matter of time (and system
load, and OS scheduling, and phase of the moon, and ...).





More information about the Python-list mailing list