idle BUG - hung Python processes

Mike Clarkson support at internetdiscovery.com
Sat Jun 23 01:56:32 EDT 2001


On Wed, 20 Jun 2001 08:50:00 GMT, Mark Hammond <MarkH at ActiveState.com>
wrote:
>Mike Clarkson wrote:
>
>> I know you're not-a-gui-guy, but can you help with python.exe compile
>> and link flags? Has anyone build Tkinter with Cygwin, and if so, does
>> the same problem show up there?
>
>
>What help specifically?
>
>python.c is compiled with:
>
>/nologo /MD /W3 /GX /Zi /O2 /I "..\Include" /I "..\PC" /D "WIN32" /D 
>"NDEBUG" /D "_CONSOLE" /D "_MBCS" 
>/Fp"x86-temp-release\python/python.pch" /YX 
>/Fo"x86-temp-release\python/" /Fd"x86-temp-release\python/" /FD /c
>
>python.exe is linked with:
>
>odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib 
>comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib 
>/nologo /subsystem:console /incremental:no /pdb:"./python.pdb" /debug 
>/machine:I386 /out:"./python.exe"

Thanks for the reply Mark. I'll build a clean Tcl 8.4 from scratch and
post the flags  it uses. I was just wondering if there was any
possible subtlety on the /D_CONSOLE or /subsystem flags.  I know
compiler and linker flags are a long shot, but Python is the only
program I've seen that generates unkillable processes under Win98, and
it looks like it happens to frozenTkinter apps as well (see PS below).


Here's a minimum Python program that illustrates the problem:

import Tkinter
from Tkconstants import *

root = Tkinter.Tk()
root.wm_protocol('WM_DELETE_WINDOW', root.tk.quit)
root.mainloop()

Call this hang.py and run it in a DOS window under Win98:
	python hang.py

Click on the X in the corner of the Tk window. You generate an
unkillable hung Python that inhibits Windows shutdown. So the first,
and most important question is how can Python ever be unkillable.
The only place to look I could think of was the compile/link flags.
Maybe another might be how sys.exit treats the Tcl thread in Python.

Now if you change the WM_DELETE_WINDOW to use the patched
Tkinter root.quit that I suggested to Robin,

root.wm_protocol('WM_DELETE_WINDOW', root.quit)

then my patch to Tkinter solves the problem for me under Win98. (Robin
said it didn't for him under Win95, but I couldn't get him to check
that he was using the patched call in all places i.e. wm_protocol.) 

self.tk.quit() is the _tkinter quit, which just says bail out of the
self.tk.mainloop(). It doesn't destroy any windows, delete any Tk
intepreter or even delete any of the tcl commands declared in Python
as callbacks. In Tkinter.py, I patched quit() to: (you may have to fix
the tk.eval lines back up to be all one line). 

    def quit(self):
        """Quit the Tcl interpreter. All widgets will be destroyed."""
        # Use raw Tcl to ensure the foreach is atomic
        self.tk.eval('''foreach w [winfo child .] {
	wm protocol $w WM_DELETE_WINDOW {};
	catch {destroy $w}
        }''')
        self.tk.eval('''catch {wm protocol . WM_DELETE_WINDOW {};
destroy .}''')
        self.tk.quit()

My patched root.quit() makes sure all windows all destroyed.
My theory is that the undestroyed windows might be
stopping Python from unloading the Tk and exiting cleanly.

Probably my quit(self) method could also have added at the end
       self.destroy()
which is an internal Tkinter function that deletes the Python callback
functions. It should probably be renamed to _deletetclcallbacks.

The self.destroy() in Idle.PyShell at the end of main() after the
root.mainloop() should then probably be then changed to:
	root.quit()
which I think should solve Robin's original problem (I don't have a
Win95 box here to test it on.)

I'll submit the patch for Tkinter anyway, because I think it's
correct, even if it doesn't explain why Python can be unkillable.
I think it's *very* important that Python never be unkillable.

On a related but different problem, Tk's event loop does not respond
to  WM_QUERYENDSESSION or WM_ENDSESSION events, so there 
is no way to gracefully shut down a Tkinter application when the user
initiates a shutdown.  The Tk event loop can be patched to do this,
but I was wondering if there was any graceful way of doing this in
Python? Would it have to be in a seperate thread?

Many thanks,

Mike.

PS: freeze.py with -s windows links with this:

        link -out:ifindpy.exe *.obj  "shell32.lib" "comdlg32.lib"
"wsock32.lib" "user32.lib" "oleaut32.lib"    "j:\ActivePython-2.1.
0-210/pcbuild/python21.lib"

Note no /subsystem.




More information about the Python-list mailing list