From 491aee20c0282fe7e456796f31328a21b02abba3 Mon Sep 17 00:00:00 2001 From: Guilherme Polo Date: Fri, 6 Feb 2009 23:16:11 +0000 Subject: [PATCH] Merged revisions 69376-69377 via svnmerge from svn+ssh://pythondev/python/trunk ........ r69376 | guilherme.polo | 2009-02-06 20:26:22 -0200 (Fri, 06 Feb 2009) | 3 lines Partial fix to issue #1731706: memory leak in Tkapp_Call when calling from a thread different than the one that created the Tcl interpreter. ........ r69377 | guilherme.polo | 2009-02-06 20:48:07 -0200 (Fri, 06 Feb 2009) | 5 lines Issue #1731706: Call Tcl_ConditionFinalize for Tcl_Conditions that will not be used again (this requires Tcl/Tk 8.3.1), also fix a memory leak in Tkapp_Call when calling from a thread different than the one that created the Tcl interpreter. ........ --- Misc/NEWS | 5 +++++ Modules/_tkinter.c | 46 ++++++++++++++++++++++++++++------------------ 2 files changed, 33 insertions(+), 18 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS index cd60fa39d98..d328c61c2b5 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -155,6 +155,11 @@ Core and Builtins Library ------- +- Issue #1731706: Call Tcl_ConditionFinalize for Tcl_Conditions that will + not be used again (this requires Tcl/Tk 8.3.1), also fix a memory leak in + Tkapp_Call when calling from a thread different than the one that created + the Tcl interpreter. Patch by Robert Hancock. + - Issue #4285: Change sys.version_info to be a named tuple. Patch by Ross Light. diff --git a/Modules/_tkinter.c b/Modules/_tkinter.c index eed7177731e..645f9845fa0 100644 --- a/Modules/_tkinter.c +++ b/Modules/_tkinter.c @@ -9,9 +9,9 @@ Copyright (C) 1994 Steen Lumholt. /* TCL/TK VERSION INFO: - Only Tcl/Tk 8.2 and later are supported. Older versions are not - supported. (Use Python 2.2 if you cannot upgrade your Tcl/Tk - libraries.) + Only Tcl/Tk 8.3.1 and later are supported. Older versions are not + supported. Use Python 2.6 or older if you cannot upgrade your + Tcl/Tk libraries. */ /* XXX Further speed-up ideas, involving Tcl 8.0 features: @@ -1085,7 +1085,7 @@ typedef struct Tkapp_CallEvent { int flags; PyObject **res; PyObject **exc_type, **exc_value, **exc_tb; - Tcl_Condition done; + Tcl_Condition *done; } Tkapp_CallEvent; void @@ -1208,10 +1208,12 @@ Tkapp_CallProc(Tkapp_CallEvent *e, int flags) *(e->res) = Tkapp_CallResult(e->self); } LEAVE_PYTHON - done: + + Tkapp_CallDeallocArgs(objv, objStore, objc); +done: /* Wake up calling thread. */ Tcl_MutexLock(&call_mutex); - Tcl_ConditionNotify(&e->done); + Tcl_ConditionNotify(e->done); Tcl_MutexUnlock(&call_mutex); return 1; } @@ -1249,6 +1251,7 @@ Tkapp_Call(PyObject *selfptr, PyObject *args) /* We cannot call the command directly. Instead, we must marshal the parameters to the interpreter thread. */ Tkapp_CallEvent *ev; + Tcl_Condition cond = NULL; PyObject *exc_type, *exc_value, *exc_tb; if (!WaitForMainloop(self)) return NULL; @@ -1260,9 +1263,9 @@ Tkapp_Call(PyObject *selfptr, PyObject *args) ev->exc_type = &exc_type; ev->exc_value = &exc_value; ev->exc_tb = &exc_tb; - ev->done = (Tcl_Condition)0; + ev->done = &cond; - Tkapp_ThreadSend(self, (Tcl_Event*)ev, &ev->done, &call_mutex); + Tkapp_ThreadSend(self, (Tcl_Event*)ev, &cond, &call_mutex); if (res == NULL) { if (exc_type) @@ -1270,6 +1273,7 @@ Tkapp_Call(PyObject *selfptr, PyObject *args) else PyErr_SetObject(Tkinter_TclError, exc_value); } + Tcl_ConditionFinalize(&cond); } else #endif @@ -1455,7 +1459,7 @@ typedef struct VarEvent { PyObject **res; PyObject **exc_type; PyObject **exc_val; - Tcl_Condition cond; + Tcl_Condition *cond; } VarEvent; static int @@ -1499,7 +1503,7 @@ var_proc(VarEvent* ev, int flags) ENTER_PYTHON var_perform(ev); Tcl_MutexLock(&var_mutex); - Tcl_ConditionNotify(&ev->cond); + Tcl_ConditionNotify(ev->cond); Tcl_MutexUnlock(&var_mutex); LEAVE_PYTHON return 1; @@ -1514,6 +1518,7 @@ var_invoke(EventFunc func, PyObject *selfptr, PyObject *args, int flags) TkappObject *self = (TkappObject*)selfptr; VarEvent *ev; PyObject *res, *exc_type, *exc_val; + Tcl_Condition cond = NULL; /* The current thread is not the interpreter thread. Marshal the call to the interpreter thread, then wait for @@ -1530,9 +1535,10 @@ var_invoke(EventFunc func, PyObject *selfptr, PyObject *args, int flags) ev->res = &res; ev->exc_type = &exc_type; ev->exc_val = &exc_val; - ev->cond = NULL; + ev->cond = &cond; ev->ev.proc = (Tcl_EventProc*)var_proc; - Tkapp_ThreadSend(self, (Tcl_Event*)ev, &ev->cond, &var_mutex); + Tkapp_ThreadSend(self, (Tcl_Event*)ev, &cond, &var_mutex); + Tcl_ConditionFinalize(&cond); if (!res) { PyErr_SetObject(exc_type, exc_val); Py_DECREF(exc_type); @@ -2019,7 +2025,7 @@ typedef struct CommandEvent{ int create; int *status; ClientData *data; - Tcl_Condition done; + Tcl_Condition *done; } CommandEvent; static int @@ -2032,7 +2038,7 @@ Tkapp_CommandProc(CommandEvent *ev, int flags) else *ev->status = Tcl_DeleteCommand(ev->interp, ev->name); Tcl_MutexLock(&command_mutex); - Tcl_ConditionNotify(&ev->done); + Tcl_ConditionNotify(ev->done); Tcl_MutexUnlock(&command_mutex); return 1; } @@ -2068,6 +2074,7 @@ Tkapp_CreateCommand(PyObject *selfptr, PyObject *args) data->func = func; if (self->threaded && self->thread_id != Tcl_GetCurrentThread()) { + Tcl_Condition cond = NULL; CommandEvent *ev = (CommandEvent*)ckalloc(sizeof(CommandEvent)); ev->ev.proc = (Tcl_EventProc*)Tkapp_CommandProc; ev->interp = self->interp; @@ -2075,8 +2082,9 @@ Tkapp_CreateCommand(PyObject *selfptr, PyObject *args) ev->name = cmdName; ev->data = (ClientData)data; ev->status = &err; - ev->done = NULL; - Tkapp_ThreadSend(self, (Tcl_Event*)ev, &ev->done, &command_mutex); + ev->done = &cond; + Tkapp_ThreadSend(self, (Tcl_Event*)ev, &cond, &command_mutex); + Tcl_ConditionFinalize(&cond); } else { ENTER_TCL @@ -2107,6 +2115,7 @@ Tkapp_DeleteCommand(PyObject *selfptr, PyObject *args) if (!PyArg_ParseTuple(args, "s:deletecommand", &cmdName)) return NULL; if (self->threaded && self->thread_id != Tcl_GetCurrentThread()) { + Tcl_Condition cond = NULL; CommandEvent *ev; ev = (CommandEvent*)ckalloc(sizeof(CommandEvent)); ev->ev.proc = (Tcl_EventProc*)Tkapp_CommandProc; @@ -2114,9 +2123,10 @@ Tkapp_DeleteCommand(PyObject *selfptr, PyObject *args) ev->create = 0; ev->name = cmdName; ev->status = &err; - ev->done = NULL; - Tkapp_ThreadSend(self, (Tcl_Event*)ev, &ev->done, + ev->done = &cond; + Tkapp_ThreadSend(self, (Tcl_Event*)ev, &cond, &command_mutex); + Tcl_ConditionFinalize(&cond); } else { ENTER_TCL