@@ -40,9 +40,10 @@ Copyright (C) 1994 Steen Lumholt.
4040#define CHECK_SIZE (size , elemsize ) \
4141 ((size_t)(size) <= Py_MIN((size_t)INT_MAX, UINT_MAX / (size_t)(elemsize)))
4242
43- /* If Tcl is compiled for threads, we must also define TCL_THREAD. We define
44- it always; if Tcl is not threaded, the thread functions in
45- Tcl are empty. */
43+ /* As we require that Tcl is compiled for threads, we must also define
44+ TCL_THREADS. We define it always; if Tcl is not threaded, the thread
45+ functions in Tcl are empty. We check if Tcl is actually compiled for
46+ threads when importing this module. */
4647#define TCL_THREADS
4748
4849#ifdef TK_FRAMEWORK
@@ -179,6 +180,7 @@ _get_tcl_lib_path(void)
179180}
180181#endif /* MS_WINDOWS */
181182
183+ <<<<<<< HEAD
182184#if defined(MS_WINDOWS ) && TK_MAJOR_VERSION >= 9
183185static void
184186mount_tk_dll_zip (void )
@@ -233,13 +235,8 @@ Tkinter_TkInit(Tcl_Interp *interp)
233235/* The threading situation is complicated. Tcl is not thread-safe, except
234236 when configured with --enable-threads.
235237
236- So we need to use a lock around all uses of Tcl. Previously, the
237- Python interpreter lock was used for this. However, this causes
238- problems when other Python threads need to run while Tcl is blocked
239- waiting for events.
240-
241- To solve this problem, a separate lock for Tcl is introduced.
242- Holding it is incompatible with holding Python's interpreter lock.
238+ We introduce a lock specifically for Tcl; holding it is incompatible
239+ with holding Python's interpreter lock.
243240 The following four macros manipulate both locks together.
244241
245242 ENTER_TCL and LEAVE_TCL are brackets, just like
@@ -271,9 +268,8 @@ Tkinter_TkInit(Tcl_Interp *interp)
271268 These locks expand to several statements and brackets; they should
272269 not be used in branches of if statements and the like.
273270
274- If Tcl is threaded, this approach won't work anymore. The Tcl
275- interpreter is only valid in the thread that created it, and all Tk
276- activity must happen in this thread, also. That means that the
271+ The Tcl interpreter is only valid in the thread that created it, and
272+ all Tk activity must happen in this thread, also. That means that the
277273 mainloop must be invoked in the thread that created the
278274 interpreter. Invoking commands from other threads is possible;
279275 _tkinter will queue an event for the interpreter thread, which will
@@ -283,48 +279,51 @@ Tkinter_TkInit(Tcl_Interp *interp)
283279 the command invocation will block.
284280
285281 In addition, for a threaded Tcl, a single global tcl_tstate won't
286- be sufficient anymore, since multiple Tcl interpreters may
287- simultaneously dispatch in different threads. So we use the Tcl TLS
288- API.
282+ be sufficient, since multiple Tcl interpreters may simultaneously
283+ dispatch in different threads. So we use the Tcl TLS API.
289284
290285*/
291286
292- static PyThread_type_lock tcl_lock = 0 ;
287+ static int
288+ _check_tcl_threaded (void )
289+ {
290+ Tcl_Interp * interp ;
291+ Tcl_Obj * threaded ;
292+ interp = Tcl_CreateInterp ();
293+ threaded = Tcl_GetVar2Ex (interp ,
294+ "tcl_platform" ,
295+ "threaded" ,
296+ TCL_GLOBAL_ONLY );
297+ Tcl_DeleteInterp (interp );
298+ if (threaded == NULL ) return 0 ;
299+ else return 1 ;
300+ }
293301
294- #ifdef TCL_THREADS
295302static Tcl_ThreadDataKey state_key ;
296303#define tcl_tstate \
297304 (*(PyThreadState**)Tcl_GetThreadData(&state_key, sizeof(PyThreadState*)))
298- #else
299- static PyThreadState * tcl_tstate = NULL ;
300- #endif
301305
302306#define ENTER_TCL \
303307 { PyThreadState *tstate = PyThreadState_Get(); \
304308 Py_BEGIN_ALLOW_THREADS \
305- if(tcl_lock)PyThread_acquire_lock(tcl_lock, 1); \
306309 tcl_tstate = tstate;
307310
308311#define LEAVE_TCL \
309312 tcl_tstate = NULL; \
310- if(tcl_lock)PyThread_release_lock(tcl_lock); \
311313 Py_END_ALLOW_THREADS}
312314
313315#define ENTER_OVERLAP \
314316 Py_END_ALLOW_THREADS
315317
316318#define LEAVE_OVERLAP_TCL \
317- tcl_tstate = NULL; if(tcl_lock)PyThread_release_lock(tcl_lock); }
319+ tcl_tstate = NULL; }
318320
319321#define ENTER_PYTHON \
320322 { PyThreadState *tstate = tcl_tstate; tcl_tstate = NULL; \
321- if(tcl_lock) \
322- PyThread_release_lock(tcl_lock); \
323323 PyEval_RestoreThread((tstate)); }
324324
325325#define LEAVE_PYTHON \
326326 { PyThreadState *tstate = PyEval_SaveThread(); \
327- if(tcl_lock)PyThread_acquire_lock(tcl_lock, 1); \
328327 tcl_tstate = tstate; }
329328
330329#ifndef FREECAST
@@ -339,7 +338,6 @@ typedef struct {
339338 PyObject_HEAD
340339 Tcl_Interp * interp ;
341340 int wantobjects ;
342- int threaded ; /* True if tcl_platform[threaded] */
343341 Tcl_ThreadId thread_id ;
344342 int dispatching ;
345343 PyObject * trace ;
@@ -373,7 +371,7 @@ typedef struct {
373371static inline int
374372check_tcl_appartment (TkappObject * app )
375373{
376- if (app -> threaded && app -> thread_id != Tcl_GetCurrentThread ()) {
374+ if (app -> thread_id != Tcl_GetCurrentThread ()) {
377375 PyErr_SetString (PyExc_RuntimeError ,
378376 "Calling Tcl from different apartment" );
379377 return -1 ;
@@ -652,20 +650,6 @@ Tkapp_New(const char *screenName, const char *className,
652650 v -> dispatching = 0 ;
653651 v -> trace = NULL ;
654652
655- #ifndef TCL_THREADS
656- if (v -> threaded ) {
657- PyErr_SetString (PyExc_RuntimeError ,
658- "Tcl is threaded but _tkinter is not" );
659- Py_DECREF (v );
660- return 0 ;
661- }
662- #endif
663- if (v -> threaded && tcl_lock ) {
664- /* If Tcl is threaded, we don't need the lock. */
665- PyThread_free_lock (tcl_lock );
666- tcl_lock = NULL ;
667- }
668-
669653 v -> OldBooleanType = Tcl_GetObjType ("boolean" );
670654 {
671655 Tcl_Obj * value ;
@@ -1659,13 +1643,11 @@ Tkapp_CallProc(Tcl_Event *evPtr, int flags)
16591643
16601644
16611645/* This is the main entry point for calling a Tcl command.
1662- It supports three cases, with regard to threading:
1663- 1. Tcl is not threaded: Must have the Tcl lock, then can invoke command in
1664- the context of the calling thread.
1665- 2. Tcl is threaded, caller of the command is in the interpreter thread:
1646+ It supports two cases, with regard to threading:
1647+ 2. Caller of the command is in the interpreter thread:
16661648 Execute the command in the calling thread. Since the Tcl lock will
16671649 not be used, we can merge that with case 1.
1668- 3. Tcl is threaded, caller is in a different thread: Must queue an event to
1650+ 3. Caller is in a different thread: Must queue an event to
16691651 the interpreter thread. Allocation of Tcl objects needs to occur in the
16701652 interpreter thread, so we ship the PyObject* args to the target thread,
16711653 and perform processing there. */
@@ -1686,7 +1668,7 @@ Tkapp_Call(PyObject *selfptr, PyObject *args)
16861668 if (PyTuple_Check (item ))
16871669 args = item ;
16881670 }
1689- if (self -> threaded && self -> thread_id != Tcl_GetCurrentThread ()) {
1671+ if (self -> thread_id != Tcl_GetCurrentThread ()) {
16901672 /* We cannot call the command directly. Instead, we must
16911673 marshal the parameters to the interpreter thread. */
16921674 Tkapp_CallEvent * ev ;
@@ -1963,7 +1945,7 @@ static PyObject*
19631945var_invoke (EventFunc func , PyObject * selfptr , PyObject * args , int flags )
19641946{
19651947 TkappObject * self = TkappObject_CAST (selfptr );
1966- if (self -> threaded && self -> thread_id != Tcl_GetCurrentThread ()) {
1948+ if (self -> thread_id != Tcl_GetCurrentThread ()) {
19671949 VarEvent * ev ;
19681950 // init 'res' and 'exc' to make static analyzers happy
19691951 PyObject * res = NULL , * exc = NULL ;
@@ -1997,7 +1979,7 @@ var_invoke(EventFunc func, PyObject *selfptr, PyObject *args, int flags)
19971979 }
19981980 return res ;
19991981 }
2000- /* Tcl is not threaded, or this is the interpreter thread. */
1982+ /* This is the interpreter thread. */
20011983 return func (self , args , flags );
20021984}
20031985
@@ -2655,7 +2637,7 @@ _tkinter_tkapp_createcommand_impl(TkappObject *self, const char *name,
26552637 return NULL ;
26562638 }
26572639
2658- if (self -> threaded && self -> thread_id != Tcl_GetCurrentThread () &&
2640+ if (self -> thread_id != Tcl_GetCurrentThread () &&
26592641 !WaitForMainloop (self ))
26602642 return NULL ;
26612643
@@ -2669,7 +2651,7 @@ _tkinter_tkapp_createcommand_impl(TkappObject *self, const char *name,
26692651 (gh-80937). The command cannot outlive the interpreter. */
26702652 data -> self = self ;
26712653 data -> func = Py_NewRef (func );
2672- if (self -> threaded && self -> thread_id != Tcl_GetCurrentThread ()) {
2654+ if (self -> thread_id != Tcl_GetCurrentThread ()) {
26732655 err = 0 ; // init to make static analyzers happy
26742656
26752657 Tcl_Condition cond = NULL ;
@@ -2727,7 +2709,7 @@ _tkinter_tkapp_deletecommand_impl(TkappObject *self, const char *name)
27272709
27282710 TRACE (self , ("((sss))" , "rename" , name , "" ));
27292711
2730- if (self -> threaded && self -> thread_id != Tcl_GetCurrentThread ()) {
2712+ if (self -> thread_id != Tcl_GetCurrentThread ()) {
27312713 err = 0 ; // init to make static analyzers happy
27322714
27332715 Tcl_Condition cond = NULL ;
@@ -3082,8 +3064,6 @@ static PyObject *
30823064_tkinter_tkapp_mainloop_impl (TkappObject * self , int threshold )
30833065/*[clinic end generated code: output=0ba8eabbe57841b0 input=036bcdcf03d5eca0]*/
30843066{
3085- PyThreadState * tstate = PyThreadState_Get ();
3086-
30873067 CHECK_TCL_APPARTMENT (self );
30883068 self -> dispatching = 1 ;
30893069
@@ -3094,23 +3074,10 @@ _tkinter_tkapp_mainloop_impl(TkappObject *self, int threshold)
30943074 {
30953075 int result ;
30963076
3097- if (self -> threaded ) {
3098- /* Allow other Python threads to run. */
3099- ENTER_TCL
3100- result = Tcl_DoOneEvent (0 );
3101- LEAVE_TCL
3102- }
3103- else {
3104- Py_BEGIN_ALLOW_THREADS
3105- if (tcl_lock )PyThread_acquire_lock (tcl_lock , 1 );
3106- tcl_tstate = tstate ;
3107- result = Tcl_DoOneEvent (TCL_DONT_WAIT );
3108- tcl_tstate = NULL ;
3109- if (tcl_lock )PyThread_release_lock (tcl_lock );
3110- if (result == 0 )
3111- Sleep (Tkinter_busywaitinterval );
3112- Py_END_ALLOW_THREADS
3113- }
3077+ /* Allow other Python threads to run. */
3078+ ENTER_TCL
3079+ result = Tcl_DoOneEvent (0 );
3080+ LEAVE_TCL
31143081
31153082 if (PyErr_CheckSignals () != 0 ) {
31163083 self -> dispatching = 0 ;
@@ -3686,13 +3653,11 @@ EventHook(void)
36863653 }
36873654#endif
36883655 Py_BEGIN_ALLOW_THREADS
3689- if (tcl_lock )PyThread_acquire_lock (tcl_lock , 1 );
36903656 tcl_tstate = event_tstate ;
36913657
36923658 result = Tcl_DoOneEvent (TCL_DONT_WAIT );
36933659
36943660 tcl_tstate = NULL ;
3695- if (tcl_lock )PyThread_release_lock (tcl_lock );
36963661 if (result == 0 )
36973662 Sleep (Tkinter_busywaitinterval );
36983663 Py_END_ALLOW_THREADS
0 commit comments