]> granicus.if.org Git - python/commitdiff
Work around deadlock risk. Will backport.
authorMartin v. Löwis <martin@v.loewis.de>
Mon, 1 May 2006 06:28:01 +0000 (06:28 +0000)
committerMartin v. Löwis <martin@v.loewis.de>
Mon, 1 May 2006 06:28:01 +0000 (06:28 +0000)
Misc/NEWS
Modules/_tkinter.c

index 3bd5a1f506097bbc361ccedf25985390c40c804a..1a180c29e3fc038ed6922449eb49d8b30fd2da58 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -63,6 +63,9 @@ Core and builtins
 Extension Modules
 -----------------
 
+- Calling Tk_Init twice is refused if the first call failed as that
+  may deadlock.
+
 - Patch #1191065: Fix preprocessor problems on systems where recvfrom
   is a macro.
 
index ebaf799b14075d4df52c5adc086459966ecbfd23..bbcbfa16e7616c5871b4d4d610334d81a603270a 100644 (file)
@@ -2619,21 +2619,32 @@ Tkapp_InterpAddr(PyObject *self, PyObject *args)
 static PyObject        *
 Tkapp_TkInit(PyObject *self, PyObject *args)
 {
+       static int has_failed;
        Tcl_Interp *interp = Tkapp_Interp(self);
        Tk_Window main_window;
        const char * _tk_exists = NULL;
-       PyObject *res = NULL;
        int err;
        main_window = Tk_MainWindow(interp);
 
+       /* In all current versions of Tk (including 8.4.13), Tk_Init
+          deadlocks on the second call when the first call failed.
+          To avoid the deadlock, we just refuse the second call through
+          a static variable. */
+       if (has_failed) {
+               PyErr_SetString(Tkinter_TclError, 
+                               "Calling Tk_Init again after a previous call failed might deadlock");
+               return NULL;
+       }
+          
        /* We want to guard against calling Tk_Init() multiple times */
        CHECK_TCL_APPARTMENT;
        ENTER_TCL
        err = Tcl_Eval(Tkapp_Interp(self), "info exists tk_version");
        ENTER_OVERLAP
        if (err == TCL_ERROR) {
-               /* XXX: shouldn't we do something with res? */
-               res = Tkinter_Error(self);
+               /* This sets an exception, but we cannot return right
+                  away because we need to exit the overlap first. */
+               Tkinter_Error(self);
        } else {
                _tk_exists = Tkapp_Result(self);
        }
@@ -2644,6 +2655,7 @@ Tkapp_TkInit(PyObject *self, PyObject *args)
        if (_tk_exists == NULL || strcmp(_tk_exists, "1") != 0) {
                if (Tk_Init(interp)     == TCL_ERROR) {
                        PyErr_SetString(Tkinter_TclError, Tcl_GetStringResult(Tkapp_Interp(self)));
+                       has_failed = 1;
                        return NULL;
                }
        }