Commit 869b2ec9 authored by Martin v. Löwis's avatar Martin v. Löwis

Use object interface for global vars. Fixes #721171.

Also move complete processing of get/set/delvar calls to target thread.
parent 80b46eb6
...@@ -1449,65 +1449,39 @@ Tkapp_AddErrorInfo(PyObject *self, PyObject *args) ...@@ -1449,65 +1449,39 @@ Tkapp_AddErrorInfo(PyObject *self, PyObject *args)
TCL_DECLARE_MUTEX(var_mutex) TCL_DECLARE_MUTEX(var_mutex)
typedef CONST84_RETURN char* (*EventFunc1)(Tcl_Interp*, CONST char*, int); typedef PyObject* (*EventFunc)(PyObject*, PyObject *args, int flags);
typedef CONST84_RETURN char* (*EventFunc2)(Tcl_Interp*, CONST char*, CONST char*, int);
typedef CONST84_RETURN char* (*EventFunc3)(Tcl_Interp*, CONST char*, CONST char*, CONST char*, int);
typedef struct VarEvent { typedef struct VarEvent {
Tcl_Event ev; /* must be first */ Tcl_Event ev; /* must be first */
TkappObject *self; PyObject *self;
char* arg1; PyObject *args;
char* arg2;
char* arg3;
int flags; int flags;
EventFunc1 func1; EventFunc func;
EventFunc2 func2;
EventFunc3 func3;
PyObject **res; PyObject **res;
PyObject **exc; PyObject **exc_type;
PyObject **exc_val;
Tcl_Condition cond; Tcl_Condition cond;
int coderesult;
} VarEvent; } VarEvent;
static const char* void
var_perform(VarEvent *ev) var_perform(VarEvent *ev)
{ {
if (!ev->arg2 && !ev->arg2) *(ev->res) = ev->func(ev->self, ev->args, ev->flags);
return ev->func1(ev->self->interp, ev->arg1, ev->flags); if (!*(ev->res)) {
if (!ev->arg3) PyObject *exc, *val, *tb;
return ev->func2(ev->self->interp, ev->arg1, PyErr_Fetch(&exc, &val, &tb);
ev->arg2, ev->flags); PyErr_NormalizeException(&exc, &val, &tb);
return ev->func3(ev->self->interp, ev->arg1, ev->arg2, *(ev->exc_type) = exc;
ev->arg3, ev->flags); *(ev->exc_val) = val;
} Py_DECREF(tb);
static void
var_fill_result(VarEvent *ev, const char* res)
{
if (ev->coderesult) {
if ((int)res != TCL_ERROR) {
Py_INCREF(Py_None);
*(ev->res) = Py_None;
return;
}
} }
else if (res) {
*(ev->res) = PyString_FromString(res);
return;
}
*(ev->res) = NULL;
*(ev->exc) = PyObject_CallFunction(
Tkinter_TclError, "s",
Tcl_GetStringResult(ev->self->interp));
} }
static int static int
var_proc(VarEvent* ev, int flags) var_proc(VarEvent* ev, int flags)
{ {
const char *result = var_perform(ev);
ENTER_PYTHON ENTER_PYTHON
var_fill_result(ev, result); var_perform(ev);
Tcl_MutexLock(&var_mutex); Tcl_MutexLock(&var_mutex);
Tcl_ConditionNotify(&ev->cond); Tcl_ConditionNotify(&ev->cond);
Tcl_MutexUnlock(&var_mutex); Tcl_MutexUnlock(&var_mutex);
...@@ -1516,125 +1490,105 @@ var_proc(VarEvent* ev, int flags) ...@@ -1516,125 +1490,105 @@ var_proc(VarEvent* ev, int flags)
} }
static PyObject* static PyObject*
var_invoke(PyObject *_self, char* arg1, char* arg2, char* arg3, int flags, var_invoke(EventFunc func, PyObject *_self, PyObject *args, int flags)
EventFunc1 func1, EventFunc2 func2, EventFunc3 func3,
int coderesult)
{ {
VarEvent _ev;
TkappObject *self = (TkappObject*)_self; TkappObject *self = (TkappObject*)_self;
VarEvent *ev = self->threaded ?
(VarEvent*)ckalloc(sizeof(VarEvent)) : &_ev;
PyObject *res, *exc;
ev->self = self;
ev->arg1 = arg1;
ev->arg2 = arg2;
ev->arg3 = arg3;
ev->flags = flags;
ev->func1 = func1;
ev->func2 = func2;
ev->func3 = func3;
ev->coderesult = coderesult;
ev->res = &res;
ev->exc = &exc;
#ifdef WITH_THREAD #ifdef WITH_THREAD
if (self->threaded && self->thread_id != Tcl_GetCurrentThread()) { if (self->threaded && self->thread_id != Tcl_GetCurrentThread()) {
TkappObject *self = (TkappObject*)_self;
VarEvent *ev;
PyObject *res, *exc_type, *exc_val;
/* The current thread is not the interpreter thread. Marshal /* The current thread is not the interpreter thread. Marshal
the call to the interpreter thread, then wait for the call to the interpreter thread, then wait for
completion. */ completion. */
if (!WaitForMainloop(self)) if (!WaitForMainloop(self))
return NULL; return NULL;
ev = (VarEvent*)ckalloc(sizeof(VarEvent));
ev->self = _self;
ev->args = args;
ev->flags = flags;
ev->func = func;
ev->res = &res;
ev->exc_type = &exc_type;
ev->exc_val = &exc_val;
ev->cond = NULL; ev->cond = NULL;
ev->ev.proc = (Tcl_EventProc*)var_proc; ev->ev.proc = (Tcl_EventProc*)var_proc;
Tkapp_ThreadSend(self, (Tcl_Event*)ev, &ev->cond, &var_mutex); Tkapp_ThreadSend(self, (Tcl_Event*)ev, &ev->cond, &var_mutex);
if (!res) {
PyErr_SetObject(exc_type, exc_val);
Py_DECREF(exc_type);
Py_DECREF(exc_val);
return NULL;
}
return res;
} }
else
#endif #endif
{ /* Tcl is not threaded, or this is the interpreter thread. */
/* Tcl is not threaded, or this is the interpreter thread. To return func(_self, args, flags);
perform the call, we must hold the TCL lock. To receive the
results, we must also hold the Python lock. */
const char *result;
ENTER_TCL
result = var_perform(ev);
ENTER_OVERLAP
var_fill_result(ev, result);
LEAVE_OVERLAP_TCL
}
if (!res) {
PyErr_SetObject(Tkinter_TclError, exc);
return NULL;
}
return res;
}
static PyObject*
var_invoke2(PyObject *_self, char* arg1, char* arg2, char* arg3, int flags,
int (*func1)(Tcl_Interp*, CONST char*, int),
int (*func2)(Tcl_Interp*, CONST char*, CONST char*, int),
int (*func3)(Tcl_Interp*, CONST char*, CONST char*, CONST char*, int))
{
return var_invoke(_self, arg1, arg2, arg3, flags,
(EventFunc1)func1, (EventFunc2)func2,
(EventFunc3)func3, 1);
} }
static PyObject * static PyObject *
SetVar(PyObject *self, PyObject *args, int flags) SetVar(PyObject *self, PyObject *args, int flags)
{ {
char *name1, *name2, *s; char *name1, *name2;
PyObject *res;
PyObject *newValue; PyObject *newValue;
PyObject *tmp; PyObject *res = NULL;
Tcl_Obj *newval, *ok;
tmp = PyList_New(0);
if (!tmp)
return NULL;
if (PyArg_ParseTuple(args, "sO:setvar", &name1, &newValue)) { if (PyArg_ParseTuple(args, "sO:setvar", &name1, &newValue)) {
/* XXX Merge? */ /* XXX Acquire tcl lock??? */
s = AsString(newValue, tmp); newval = AsObj(newValue);
if (s == NULL) if (newval == NULL)
return NULL; return NULL;
res = var_invoke(self, name1, s, NULL, flags, ENTER_TCL
NULL, Tcl_SetVar, NULL, 0); ok = Tcl_SetVar2Ex(Tkapp_Interp(self), name1, NULL,
newval, flags);
ENTER_OVERLAP
if (!ok)
Tkinter_Error(self);
else {
res = Py_None;
Py_INCREF(res);
}
LEAVE_OVERLAP_TCL
} }
else { else {
PyErr_Clear(); PyErr_Clear();
if (PyArg_ParseTuple(args, "ssO:setvar", if (PyArg_ParseTuple(args, "ssO:setvar",
&name1, &name2, &newValue)) { &name1, &name2, &newValue)) {
s = AsString(newValue, tmp); /* XXX must hold tcl lock already??? */
if (s == NULL) newval = AsObj(newValue);
return NULL; ENTER_TCL
res = var_invoke(self, name1, name2, s, flags, ok = Tcl_SetVar2Ex(Tkapp_Interp(self), name1, name2, newval, flags);
NULL, NULL, Tcl_SetVar2, 0); ENTER_OVERLAP
if (!ok)
Tkinter_Error(self);
else {
res = Py_None;
Py_INCREF(res);
}
LEAVE_OVERLAP_TCL
} }
else { else {
Py_DECREF(tmp);
return NULL; return NULL;
} }
} }
Py_DECREF(tmp); return res;
if (!res)
return NULL;
Py_DECREF(res);
Py_INCREF(Py_None);
return Py_None;
} }
static PyObject * static PyObject *
Tkapp_SetVar(PyObject *self, PyObject *args) Tkapp_SetVar(PyObject *self, PyObject *args)
{ {
return SetVar(self, args, TCL_LEAVE_ERR_MSG); return var_invoke(SetVar, self, args, TCL_LEAVE_ERR_MSG);
} }
static PyObject * static PyObject *
Tkapp_GlobalSetVar(PyObject *self, PyObject *args) Tkapp_GlobalSetVar(PyObject *self, PyObject *args)
{ {
return SetVar(self, args, TCL_LEAVE_ERR_MSG | TCL_GLOBAL_ONLY); return var_invoke(SetVar, self, args, TCL_LEAVE_ERR_MSG | TCL_GLOBAL_ONLY);
} }
...@@ -1644,25 +1598,29 @@ GetVar(PyObject *self, PyObject *args, int flags) ...@@ -1644,25 +1598,29 @@ GetVar(PyObject *self, PyObject *args, int flags)
{ {
char *name1, *name2=NULL; char *name1, *name2=NULL;
PyObject *res = NULL; PyObject *res = NULL;
Tcl_Obj *tres;
if (!PyArg_ParseTuple(args, "s|s:getvar", &name1, &name2)) if (!PyArg_ParseTuple(args, "s|s:getvar", &name1, &name2))
return NULL; return NULL;
res = var_invoke(self, name1, name2, NULL, flags, ENTER_TCL
Tcl_GetVar, Tcl_GetVar2, NULL, 0); tres = Tcl_GetVar2Ex(Tkapp_Interp(self), name1, name2, flags);
ENTER_OVERLAP
res = FromObj(self, tres);
LEAVE_OVERLAP_TCL
return res; return res;
} }
static PyObject * static PyObject *
Tkapp_GetVar(PyObject *self, PyObject *args) Tkapp_GetVar(PyObject *self, PyObject *args)
{ {
return GetVar(self, args, TCL_LEAVE_ERR_MSG); return var_invoke(GetVar, self, args, TCL_LEAVE_ERR_MSG);
} }
static PyObject * static PyObject *
Tkapp_GlobalGetVar(PyObject *self, PyObject *args) Tkapp_GlobalGetVar(PyObject *self, PyObject *args)
{ {
return GetVar(self, args, TCL_LEAVE_ERR_MSG | TCL_GLOBAL_ONLY); return var_invoke(GetVar, self, args, TCL_LEAVE_ERR_MSG | TCL_GLOBAL_ONLY);
} }
...@@ -1671,26 +1629,35 @@ static PyObject * ...@@ -1671,26 +1629,35 @@ static PyObject *
UnsetVar(PyObject *self, PyObject *args, int flags) UnsetVar(PyObject *self, PyObject *args, int flags)
{ {
char *name1, *name2=NULL; char *name1, *name2=NULL;
int code;
PyObject *res = NULL; PyObject *res = NULL;
if (!PyArg_ParseTuple(args, "s|s:unsetvar", &name1, &name2)) if (!PyArg_ParseTuple(args, "s|s:unsetvar", &name1, &name2))
return NULL; return NULL;
res = var_invoke2(self, name1, name2, NULL, flags, ENTER_TCL
Tcl_UnsetVar, Tcl_UnsetVar2, NULL); code = Tcl_UnsetVar2(Tkapp_Interp(self), name1, name2, flags);
ENTER_OVERLAP
if (code == TCL_ERROR)
res = Tkinter_Error(self);
else {
Py_INCREF(Py_None);
res = Py_None;
}
LEAVE_OVERLAP_TCL
return res; return res;
} }
static PyObject * static PyObject *
Tkapp_UnsetVar(PyObject *self, PyObject *args) Tkapp_UnsetVar(PyObject *self, PyObject *args)
{ {
return UnsetVar(self, args, TCL_LEAVE_ERR_MSG); return var_invoke(UnsetVar, self, args, TCL_LEAVE_ERR_MSG);
} }
static PyObject * static PyObject *
Tkapp_GlobalUnsetVar(PyObject *self, PyObject *args) Tkapp_GlobalUnsetVar(PyObject *self, PyObject *args)
{ {
return UnsetVar(self, args, TCL_LEAVE_ERR_MSG | TCL_GLOBAL_ONLY); return var_invoke(UnsetVar, self, args, TCL_LEAVE_ERR_MSG | TCL_GLOBAL_ONLY);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment