@@ -219,6 +219,9 @@ _get_tcl_lib_path()
219219*/
220220
221221static 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
224227static Tcl_ThreadDataKey state_key ;
@@ -229,21 +232,43 @@ typedef PyThreadState *ThreadSpecificData;
229232static 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