diff options
Diffstat (limited to 'generic/tclIO.c')
-rw-r--r-- | generic/tclIO.c | 26 |
1 files changed, 26 insertions, 0 deletions
diff --git a/generic/tclIO.c b/generic/tclIO.c index 67264a0..ab8d8ac 100644 --- a/generic/tclIO.c +++ b/generic/tclIO.c @@ -3189,6 +3189,9 @@ CutChannel( */ ChanThreadAction((Channel *) chan, TCL_CHANNEL_THREAD_REMOVE); + + /* Channel is not managed by any thread */ + statePtr->managingThread = NULL; } void @@ -3233,6 +3236,9 @@ Tcl_CutChannel( for (; chanPtr != NULL ; chanPtr = chanPtr->upChanPtr) { ChanThreadAction(chanPtr, TCL_CHANNEL_THREAD_REMOVE); } + + /* Channel is not managed by any thread */ + statePtr->managingThread = NULL; } /* @@ -8382,6 +8388,13 @@ Tcl_NotifyChannel( Tcl_Preserve(statePtr); /* + * Avoid processing if the channel owner has been changed. + */ + if (statePtr->managingThread != Tcl_GetCurrentThread()) { + goto done; + } + + /* * If we are flushing in the background, be sure to call FlushChannel for * writable events. Note that we have to discard the writable event so we * don't call any write handlers before the flush is complete. @@ -8415,6 +8428,13 @@ Tcl_NotifyChannel( } else { chPtr = chPtr->nextPtr; } + + /* + * Stop if the channel owner has been changed in-between. + */ + if (chanPtr->state->managingThread != Tcl_GetCurrentThread()) { + goto done; + } } /* @@ -8432,6 +8452,7 @@ Tcl_NotifyChannel( UpdateInterest(chanPtr); } +done: Tcl_Release(statePtr); TclChannelRelease(channel); @@ -8909,6 +8930,11 @@ TclChannelEventScriptInvoker( interp = esPtr->interp; /* + * Be sure event executed in managed channel (covering bugs similar [f583715154]). + */ + assert(chanPtr->state->managingThread == Tcl_GetCurrentThread()); + + /* * We must preserve the interpreter so we can report errors on it later. * Note that we do not need to preserve the channel because that is done * by Tcl_NotifyChannel before calling channel handlers. |