Skip to content

Commit b642cac

Browse files
committed
Make Tcl lock reentrant
1 parent 77daecc commit b642cac

File tree

1 file changed

+33
-6
lines changed

1 file changed

+33
-6
lines changed

Modules/_tkinter.c

Lines changed: 33 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,9 @@ Copyright (C) 1994 Steen Lumholt.
200200
*/
201201

202202
static PyThread_type_lock tcl_lock = 0;
203+
/* Only the thread holding the lock can modify these */
204+
static unsigned long tcl_lock_thread_ident = 0;
205+
static unsigned int tcl_lock_reentry_count = 0;
203206

204207
#ifdef TCL_THREADS
205208
static Tcl_ThreadDataKey state_key;
@@ -209,20 +212,43 @@ typedef PyThreadState *ThreadSpecificData;
209212
static PyThreadState *tcl_tstate = NULL;
210213
#endif
211214

215+
#define ACQUIRE_TCL_LOCK \
216+
if (tcl_lock) {\
217+
if (tcl_lock_thread_ident == PyThread_get_thread_ident()) {\
218+
tcl_lock_reentry_count++; \
219+
if(!tcl_lock_reentry_count) \
220+
Py_FatalError("Tcl lock reentry count overflow"); \
221+
} else { \
222+
PyThread_acquire_lock(tcl_lock, 1); \
223+
tcl_lock_thread_ident = PyThread_get_thread_ident(); \
224+
}\
225+
}
226+
227+
#define RELEASE_TCL_LOCK \
228+
if (tcl_lock){\
229+
if (tcl_lock_reentry_count) { \
230+
tcl_lock_reentry_count--; \
231+
} else { \
232+
tcl_lock_thread_ident = 0; \
233+
PyThread_release_lock(tcl_lock); \
234+
}\
235+
}
236+
212237
#define ENTER_TCL \
213238
{ PyThreadState *tstate = PyThreadState_Get();\
214239
ENTER_TCL_CUSTOM_TSTATE(tstate)
215240

216241
#define ENTER_TCL_CUSTOM_TSTATE(tstate) \
217242
Py_BEGIN_ALLOW_THREADS\
218-
if (tcl_lock)PyThread_acquire_lock(tcl_lock, 1); tcl_tstate = tstate;
243+
ACQUIRE_TCL_LOCK; tcl_tstate = tstate;
219244

220245
#define LEAVE_TCL \
221-
tcl_tstate = NULL; if(tcl_lock)PyThread_release_lock(tcl_lock); Py_END_ALLOW_THREADS}
246+
tcl_tstate = NULL; \
247+
RELEASE_TCL_LOCK; Py_END_ALLOW_THREADS}
222248

223249
#define LEAVE_TCL_WITH_BUSYWAIT(result) \
224250
tcl_tstate = NULL; \
225-
if (tcl_lock)PyThread_release_lock(tcl_lock);\
251+
RELEASE_TCL_LOCK;\
226252
if (result == 0)\
227253
Sleep(Tkinter_busywaitinterval);\
228254
Py_END_ALLOW_THREADS
@@ -235,15 +261,16 @@ static PyThreadState *tcl_tstate = NULL;
235261
Py_BEGIN_ALLOW_THREADS
236262

237263
#define LEAVE_OVERLAP_TCL \
238-
tcl_tstate = NULL; if(tcl_lock)PyThread_release_lock(tcl_lock); }
264+
tcl_tstate = NULL; RELEASE_TCL_LOCK; }
239265

240266
#define ENTER_PYTHON \
241267
{ PyThreadState *tstate = tcl_tstate; tcl_tstate = NULL; \
242-
if(tcl_lock)PyThread_release_lock(tcl_lock); PyEval_RestoreThread((tstate)); }
268+
RELEASE_TCL_LOCK; PyEval_RestoreThread((tstate)); }
243269

244270
#define LEAVE_PYTHON \
245271
{ PyThreadState *tstate = PyEval_SaveThread(); \
246-
if(tcl_lock)PyThread_acquire_lock(tcl_lock, 1); tcl_tstate = tstate; }
272+
ACQUIRE_TCL_LOCK;\
273+
tcl_tstate = tstate; }
247274

248275
#define ENTER_PYTHON_OVERLAP \
249276
{ PyThreadState *tstate = tcl_tstate; tcl_tstate = NULL; PyEval_RestoreThread((tstate)); }

0 commit comments

Comments
 (0)