Ivan Pozdeev <ivan_pozd...@mail.ru> added the comment:

Here are the possible courses of action to fix this.

All require design changes, thus can be shot down on a whim. So I'll ask for 
advice and approval at python-dev first, to be sure that my efforts won't be 

First, some terminology I'll be using:
* A "(Tcl interpreter) call" (in quotes) is a sequence of interdependent calls 
into Tcl that a Tkinter routine makes in the course of its action.
* Outstanding "calls" are those from other threads that have not started yet 
and are currently waiting for the Tcl lock.
* A "downstream" "call" is a call made by a running PythonCmd's Python payload.
* Each call to PythonCmd has a "start" -- before releasing the Tcl lock -- and 
an "end" -- when it reacquires it to Tcl_SetObjResult() and return
* A PythonCmd is "active" when it's before its "start" and "end"

Now, the fix options proper:

* At the "end", rearrange the Tcl interpreter's stack frames so that the 
current PythonCmd's one is on top (effectively, make it look as if independent 
"calls" use independent Tcl stacks. Theoretically possible.)
    * Confirmed this to be impossible with Tcl's public API
* Prohibit other `PythonCmd's while one is already "active", except its 
"downstream" ones. Options:
    * At the "end", the old PythonCmd checks if there are others "calls" on top 
of it (will only happen if such "call" has another "active" PythonCmd on top: 
all other Tkinter routines hold the Tcl lock for their entire duration after 
the 33257 fix), wait if there are.
        * Problematic: this wait algorithm is biased against the old PythonCmd. 
Will lead to a potentially infinite wait if there are many threads making Tcl 
calls that result in PythonCmds.
    * Hold the Tcl lock for the entire duration of a PythonCmd. To allow 
"downstream" calls, make the Tcl lock reentrant.
        * Requires redesign of about two dozen functions in thread_*.c and 
pycond.h: there are only non-reentrant locks currently.
        * Behaviour change: wouldn't allow outstanding "calls" while a 
PythonCmd is "active". This change is transparent to Python code though.
    * Reuse the threaded versions of Tkapp_* routines: bind a nonthreaded 
interpreter to a thread and forward calls to it as events like in the threaded 
        * Problematic: visible behaviour change: `tk.call()`s would now hang 
without a running `mainloop()`. Currently, only event handlers don't fire.

Rejected options:
* The new PythonCmd somehow checks at "start" if another one is "active" and 
waits if it's not a descendant of it.
    * The new PythonCmd's Tcl interpreter frame has already been allocated when 
it gets control, so the old one cannot return before the new one in any case.


Python tracker <rep...@bugs.python.org>
Python-bugs-list mailing list

Reply via email to