]> granicus.if.org Git - python/commitdiff
Merged revisions 69473 via svnmerge from
authorGuilherme Polo <ggpolo@gmail.com>
Mon, 9 Feb 2009 22:33:59 +0000 (22:33 +0000)
committerGuilherme Polo <ggpolo@gmail.com>
Mon, 9 Feb 2009 22:33:59 +0000 (22:33 +0000)
svn+ssh://pythondev/python/trunk

........
  r69473 | guilherme.polo | 2009-02-09 18:50:27 -0200 (Mon, 09 Feb 2009) | 3 lines

  Fixed issue #5122: Synchronize tk load failure check to prevent a
  potential deadlock.
........

Misc/NEWS
Modules/_tkinter.c
Modules/tkappinit.c

index 674ef66891b846204a4e6e50382b35259bd15cae..515785c287e947af68a16f56c878e2cda8d2c4e9 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -163,6 +163,9 @@ Core and Builtins
 Library
 -------
 
+- Issue #5122: Synchronize tk load failure check to prevent a potential
+  deadlock.
+
 - Issue #4890: Handle empty text search pattern in Tkinter.Text.search.
 
 - Issue #4512 (part 2): Promote ``ZipImporter._get_filename()`` to be a
index 645f9845fa0a406f85a6cff0f492dfc3be33988c..1f5a470c9e89e7ab7bfda05352f821be860fcac2 100644 (file)
@@ -33,6 +33,8 @@ Copyright (C) 1994 Steen Lumholt.
 #include <windows.h>
 #endif
 
+#include "tkinter.h"
+
 /* Allow using this code in Python 2.[12] */
 #ifndef PyDoc_STRVAR
 #define PyDoc_STRVAR(name,str) static char name[] = str
@@ -74,9 +76,7 @@ Copyright (C) 1994 Steen Lumholt.
 #define CONST
 #endif
 
-#define TKMAJORMINOR (TK_MAJOR_VERSION*1000 + TK_MINOR_VERSION)
-
-#if TKMAJORMINOR < 8002
+#if TK_VERSION_HEX < 0x08020002
 #error "Tk older than 8.2 not supported"
 #endif
 
@@ -280,6 +280,9 @@ static PyObject *excInCmd;
 static PyObject *valInCmd;
 static PyObject *trbInCmd;
 
+#ifdef TKINTER_PROTECT_LOADTK
+static int tk_load_failed;
+#endif
 
 \f
 static PyObject *
@@ -553,21 +556,35 @@ SplitObj(PyObject *arg)
 int
 Tcl_AppInit(Tcl_Interp *interp)
 {
-       Tk_Window main;
        const char * _tkinter_skip_tk_init;
 
        if (Tcl_Init(interp) == TCL_ERROR) {
                PySys_WriteStderr("Tcl_Init error: %s\n", Tcl_GetStringResult(interp));
                return TCL_ERROR;
        }
-       _tkinter_skip_tk_init = Tcl_GetVar(interp, "_tkinter_skip_tk_init", TCL_GLOBAL_ONLY);
-       if (_tkinter_skip_tk_init == NULL || strcmp(_tkinter_skip_tk_init, "1") != 0) {
-               main = Tk_MainWindow(interp);
-               if (Tk_Init(interp) == TCL_ERROR) {
-                       PySys_WriteStderr("Tk_Init error: %s\n", Tcl_GetStringResult(interp));
-                       return TCL_ERROR;
-               }
+
+       _tkinter_skip_tk_init = Tcl_GetVar(interp,
+                       "_tkinter_skip_tk_init", TCL_GLOBAL_ONLY);
+       if (_tkinter_skip_tk_init != NULL &&
+                       strcmp(_tkinter_skip_tk_init, "1") == 0) {
+               return TCL_OK;
+       }
+
+#ifdef TKINTER_PROTECT_LOADTK
+       if (tk_load_failed) {
+               PySys_WriteStderr("Tk_Init error: %s\n", TKINTER_LOADTK_ERRMSG);
+               return TCL_ERROR;
        }
+#endif
+
+       if (Tk_Init(interp) == TCL_ERROR) {
+#ifdef TKINTER_PROTECT_LOADTK
+               tk_load_failed = 1;
+#endif
+               PySys_WriteStderr("Tk_Init error: %s\n", Tcl_GetStringResult(interp));
+               return TCL_ERROR;
+       }
+
        return TCL_OK;
 }
 #endif /* !WITH_APPINIT */
@@ -650,8 +667,15 @@ Tkapp_New(char *screenName, char *className,
        ckfree(argv0);
 
        if (! wantTk) {
-           Tcl_SetVar(v->interp, "_tkinter_skip_tk_init", "1", TCL_GLOBAL_ONLY);
+               Tcl_SetVar(v->interp,
+                               "_tkinter_skip_tk_init", "1", TCL_GLOBAL_ONLY);
+       }
+#ifdef TKINTER_PROTECT_LOADTK
+       else if (tk_load_failed) {
+               Tcl_SetVar(v->interp,
+                               "_tkinter_tk_failed", "1", TCL_GLOBAL_ONLY);
        }
+#endif
 
        /* some initial arguments need to be in argv */
        if (sync || use) {
@@ -686,6 +710,18 @@ Tkapp_New(char *screenName, char *className,
 
        if (Tcl_AppInit(v->interp) != TCL_OK) {
                PyObject *result = Tkinter_Error((PyObject *)v);
+#ifdef TKINTER_PROTECT_LOADTK
+               if (wantTk) {
+                       const char *_tkinter_tk_failed;
+                       _tkinter_tk_failed = Tcl_GetVar(v->interp,
+                                       "_tkinter_tk_failed", TCL_GLOBAL_ONLY);
+
+                       if ( _tkinter_tk_failed != NULL &&
+                                       strcmp(_tkinter_tk_failed, "1") == 0) {
+                               tk_load_failed = 1;
+                       }
+               }
+#endif
                Py_DECREF((PyObject *)v);
                return (TkappObject *)result;
        }
@@ -2547,22 +2583,21 @@ 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;
        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");
+
+#ifdef TKINTER_PROTECT_LOADTK
+       /* Up to Tk 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 (tk_load_failed) {
+               PyErr_SetString(Tkinter_TclError, TKINTER_LOADTK_ERRMSG);
                return NULL;
        }
+#endif
 
        /* We want to guard against calling Tk_Init() multiple times */
        CHECK_TCL_APPARTMENT;
@@ -2582,8 +2617,10 @@ 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;
+                       PyErr_SetString(Tkinter_TclError, Tcl_GetStringResult(Tkapp_Interp(self)));
+#ifdef TKINTER_PROTECT_LOADTK
+                       tk_load_failed = 1;
+#endif
                        return NULL;
                }
        }
index de04b0dfb6e48df47fcdd0fb91ff282fbc780daa..cfbd20c4f4099ddeaa5c93ec51035d50d91ad536 100644 (file)
 #include <tcl.h>
 #include <tk.h>
 
+#include "tkinter.h"
+
+#ifdef TKINTER_PROTECT_LOADTK
+/* See Tkapp_TkInit in _tkinter.c for the usage of tk_load_faile */
+static int tk_load_failed;
+#endif
+
 int
 Tcl_AppInit(Tcl_Interp *interp)
 {
        Tk_Window main_window;
-       const char * _tkinter_skip_tk_init;
+       const char *_tkinter_skip_tk_init;
+#ifdef TKINTER_PROTECT_LOADTK
+       const char *_tkinter_tk_failed;
+#endif
 
 #ifdef TK_AQUA
 #ifndef MAX_PATH_LEN
@@ -74,12 +84,32 @@ Tcl_AppInit(Tcl_Interp *interp)
                /* Initialize modules that don't require Tk */
 #endif
 
-       _tkinter_skip_tk_init = Tcl_GetVar(interp, "_tkinter_skip_tk_init", TCL_GLOBAL_ONLY);
-       if (_tkinter_skip_tk_init != NULL && strcmp(_tkinter_skip_tk_init, "1") == 0) {
+       _tkinter_skip_tk_init = Tcl_GetVar(interp,
+                       "_tkinter_skip_tk_init", TCL_GLOBAL_ONLY);
+       if (_tkinter_skip_tk_init != NULL &&
+                       strcmp(_tkinter_skip_tk_init, "1") == 0) {
                return TCL_OK;
        }
-       if (Tk_Init(interp) == TCL_ERROR)
+
+#ifdef TKINTER_PROTECT_LOADTK
+       _tkinter_tk_failed = Tcl_GetVar(interp,
+                       "_tkinter_tk_failed", TCL_GLOBAL_ONLY);
+
+       if (tk_load_failed || (
+                               _tkinter_tk_failed != NULL &&
+                               strcmp(_tkinter_tk_failed, "1") == 0)) {
+               Tcl_SetResult(interp, TKINTER_LOADTK_ERRMSG, TCL_STATIC);
+               return TCL_ERROR;
+       }
+#endif
+
+       if (Tk_Init(interp) == TCL_ERROR) {
+#ifdef TKINTER_PROTECT_LOADTK
+               tk_load_failed = 1;
+               Tcl_SetVar(interp, "_tkinter_tk_failed", "1", TCL_GLOBAL_ONLY);
+#endif
                return TCL_ERROR;
+       }
 
        main_window = Tk_MainWindow(interp);