Skip to content

Commit 028b32a

Browse files
committed
Make Tcl lock reentrant
1 parent 0caf355 commit 028b32a

File tree

1 file changed

+32
-7
lines changed

1 file changed

+32
-7
lines changed

Modules/_tkinter.c

Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,9 @@ _get_tcl_lib_path()
219219
*/
220220

221221
static PyThread_type_lock tcl_lock = 0;
222+
/* Only the thread holding the lock can modify these */
223+
static unsigned long tcl_lock_thread_ident = 0;
224+
static unsigned int tcl_lock_reentry_count = 0;
222225

223226
#ifdef TCL_THREADS
224227
static Tcl_ThreadDataKey state_key;
@@ -229,21 +232,43 @@ typedef PyThreadState *ThreadSpecificData;
229232
static PyThreadState *tcl_tstate = NULL;
230233
#endif
231234

235+
#define ACQUIRE_TCL_LOCK \
236+
if (tcl_lock) {\
237+
if (tcl_lock_thread_ident == PyThread_get_thread_ident()) {\
238+
tcl_lock_reentry_count++; \
239+
if(!tcl_lock_reentry_count) \
240+
Py_FatalError("Tcl lock reentry count overflow"); \
241+
} else { \
242+
PyThread_acquire_lock(tcl_lock, 1); \
243+
tcl_lock_thread_ident = PyThread_get_thread_ident(); \
244+
}\
245+
}
246+
247+
#define RELEASE_TCL_LOCK \
248+
if (tcl_lock){\
249+
if (tcl_lock_reentry_count) { \
250+
tcl_lock_reentry_count--; \
251+
} else { \
252+
tcl_lock_thread_ident = 0; \
253+
PyThread_release_lock(tcl_lock); \
254+
}\
255+
}
256+
232257
#define ENTER_TCL \
233258
{ PyThreadState *tstate = PyThreadState_Get();\
234259
ENTER_TCL_CUSTOM_TSTATE(tstate)
235260

236261
#define ENTER_TCL_CUSTOM_TSTATE(tstate) \
237262
Py_BEGIN_ALLOW_THREADS\
238-
if (tcl_lock)PyThread_acquire_lock(tcl_lock, 1); tcl_tstate = tstate;
263+
ACQUIRE_TCL_LOCK; tcl_tstate = tstate;
239264

240265
#define LEAVE_TCL \
241266
tcl_tstate = NULL; \
242-
if(tcl_lock)PyThread_release_lock(tcl_lock); Py_END_ALLOW_THREADS}
267+
RELEASE_TCL_LOCK; Py_END_ALLOW_THREADS}
243268

244269
#define LEAVE_TCL_WITH_BUSYWAIT(result) \
245270
tcl_tstate = NULL; \
246-
if (tcl_lock)PyThread_release_lock(tcl_lock);\
271+
RELEASE_TCL_LOCK;\
247272
if (result == 0)\
248273
Sleep(Tkinter_busywaitinterval);\
249274
Py_END_ALLOW_THREADS
@@ -256,16 +281,16 @@ static PyThreadState *tcl_tstate = NULL;
256281
Py_BEGIN_ALLOW_THREADS
257282

258283
#define LEAVE_OVERLAP_TCL \
259-
tcl_tstate = NULL; if(tcl_lock)PyThread_release_lock(tcl_lock); }
284+
tcl_tstate = NULL; RELEASE_TCL_LOCK; }
260285

261286
#define ENTER_PYTHON \
262287
{ PyThreadState *tstate = tcl_tstate; tcl_tstate = NULL; \
263-
if(tcl_lock) \
264-
PyThread_release_lock(tcl_lock); PyEval_RestoreThread((tstate)); }
288+
RELEASE_TCL_LOCK; PyEval_RestoreThread((tstate)); }
265289

266290
#define LEAVE_PYTHON \
267291
{ PyThreadState *tstate = PyEval_SaveThread(); \
268-
if(tcl_lock)PyThread_acquire_lock(tcl_lock, 1); tcl_tstate = tstate; }
292+
ACQUIRE_TCL_LOCK;\
293+
tcl_tstate = tstate; }
269294

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

0 commit comments

Comments
 (0)