diff options
| -rw-r--r-- | generic/tclIO.c | 82 | ||||
| -rw-r--r-- | generic/tclIORChan.c | 66 | ||||
| -rw-r--r-- | tests/ioCmd.test | 40 |
3 files changed, 25 insertions, 163 deletions
diff --git a/generic/tclIO.c b/generic/tclIO.c index 78cda5c..518adef 100644 --- a/generic/tclIO.c +++ b/generic/tclIO.c @@ -167,7 +167,6 @@ static int CheckForDeadChannel(Tcl_Interp *interp, static void CheckForStdChannelsBeingClosed(Tcl_Channel chan); static void CleanupChannelHandlers(Tcl_Interp *interp, Channel *chanPtr); -static void CleanupTimerHandler(ChannelState *statePtr); static int CloseChannel(Tcl_Interp *interp, Channel *chanPtr, int errorCode); static int CloseChannelPart(Tcl_Interp *interp, Channel *chanPtr, @@ -3504,11 +3503,6 @@ TclClose( Tcl_ClearChannelHandlers(chan); /* - * Cancel any outstanding timer. - */ - DeleteTimerHandler(statePtr); - - /* * Invoke the registered close callbacks and delete their records. */ @@ -8628,7 +8622,6 @@ UpdateInterest( { ChannelState *statePtr = chanPtr->state; /* State info for channel */ - ChannelBuffer *bufPtr = statePtr->outQueueHead; int mask = statePtr->interestMask; if (chanPtr->typePtr == NULL) { @@ -8706,20 +8699,6 @@ UpdateInterest( } } } - - if (!statePtr->timer - && (mask & TCL_WRITABLE) - && GotFlag(statePtr, CHANNEL_NONBLOCKING) - && bufPtr - && !IsBufferEmpty(bufPtr) - && !IsBufferFull(bufPtr) - ) { - TclChannelPreserve((Tcl_Channel)chanPtr); - statePtr->timerChanPtr = chanPtr; - statePtr->timer = Tcl_CreateTimerHandler(SYNTHETIC_EVENT_TIME, - ChannelTimerProc,chanPtr); - } - ChanWatch(chanPtr, mask); } @@ -8748,51 +8727,30 @@ ChannelTimerProc( /* State info for channel */ ChannelState *statePtr = chanPtr->state; - /* TclChannelPreserve() must be called before the current function was - * scheduled, is already in effect. In this function it guards against - * deallocation in Tcl_NotifyChannel and also keps the channel preserved - * until ChannelTimerProc is later called again. - */ - if (chanPtr->typePtr == NULL) { - CleanupTimerHandler(statePtr); - } else { - Tcl_Preserve(statePtr); statePtr->timer = NULL; - if (statePtr->interestMask & TCL_WRITABLE - && GotFlag(statePtr, CHANNEL_NONBLOCKING) - && !GotFlag(statePtr, BG_FLUSH_SCHEDULED)) { + TclChannelRelease((Tcl_Channel)statePtr->timerChanPtr); + statePtr->timerChanPtr = NULL; + } else { + if (!GotFlag(statePtr, CHANNEL_NEED_MORE_DATA) + && (statePtr->interestMask & TCL_READABLE) + && (statePtr->inQueueHead != NULL) + && IsBufferReady(statePtr->inQueueHead)) { /* * Restart the timer in case a channel handler reenters the event loop * before UpdateInterest gets called by Tcl_NotifyChannel. */ statePtr->timer = Tcl_CreateTimerHandler(SYNTHETIC_EVENT_TIME, ChannelTimerProc,chanPtr); - Tcl_NotifyChannel((Tcl_Channel) chanPtr, TCL_WRITABLE); + Tcl_Preserve(statePtr); + Tcl_NotifyChannel((Tcl_Channel) chanPtr, TCL_READABLE); + Tcl_Release(statePtr); } else { - /* The channel may have just been closed from within Tcl_NotifyChannel */ - if (!GotFlag(statePtr, CHANNEL_INCLOSE)) { - if (!GotFlag(statePtr, CHANNEL_NEED_MORE_DATA) - && (statePtr->interestMask & TCL_READABLE) - && (statePtr->inQueueHead != NULL) - && IsBufferReady(statePtr->inQueueHead)) { - /* - * Restart the timer in case a channel handler reenters the event loop - * before UpdateInterest gets called by Tcl_NotifyChannel. - */ - - statePtr->timer = Tcl_CreateTimerHandler(SYNTHETIC_EVENT_TIME, - ChannelTimerProc,chanPtr); - Tcl_NotifyChannel((Tcl_Channel) chanPtr, TCL_READABLE); - } else { - CleanupTimerHandler(statePtr); - UpdateInterest(chanPtr); - } - } else { - CleanupTimerHandler(statePtr); - } + statePtr->timer = NULL; + UpdateInterest(chanPtr); + TclChannelRelease((Tcl_Channel)statePtr->timerChanPtr); + statePtr->timerChanPtr = NULL; } - Tcl_Release(statePtr); } } @@ -8803,17 +8761,11 @@ DeleteTimerHandler( { if (statePtr->timer != NULL) { Tcl_DeleteTimerHandler(statePtr->timer); - CleanupTimerHandler(statePtr); + statePtr->timer = NULL; + TclChannelRelease((Tcl_Channel)statePtr->timerChanPtr); + statePtr->timerChanPtr = NULL; } } -static void -CleanupTimerHandler( - ChannelState *statePtr -){ - TclChannelRelease((Tcl_Channel)statePtr->timerChanPtr); - statePtr->timer = NULL; - statePtr->timerChanPtr = NULL; -} /* *---------------------------------------------------------------------- diff --git a/generic/tclIORChan.c b/generic/tclIORChan.c index fe54f65..5acd950 100644 --- a/generic/tclIORChan.c +++ b/generic/tclIORChan.c @@ -54,8 +54,6 @@ static int ReflectSetOption(void *clientData, const char *newValue); static int ReflectTruncate(void *clientData, long long length); -static void TimerRunRead(void *clientData); -static void TimerRunWrite(void *clientData); /* * The C layer channel type/driver definition used by the reflection. @@ -113,17 +111,6 @@ typedef struct { int dead; /* Boolean signal that some operations * should no longer be attempted. */ - Tcl_TimerToken readTimer; /* - A token for the timer that is scheduled in - order to call Tcl_NotifyChannel when the - channel is readable - */ - Tcl_TimerToken writeTimer; /* - A token for the timer that is scheduled in - order to call Tcl_NotifyChannel when the - channel is writable - */ - /* * Note regarding the usage of timers. * @@ -133,9 +120,11 @@ typedef struct { * * See 'refchan', 'memchan', etc. * - * A timer is used here as well in order to ensure at least on pass through - * the event loop when a channel becomes ready. See issues 67a5eabbd3d1 and - * ef28eb1f1516. + * Here this is _not_ required. Interest in events is posted to the Tcl + * level via 'watch'. And posting of events is possible from the Tcl level + * as well, via 'chan postevent'. This means that the generation of all + * events, fake or not, timer based or not, is completely in the hands of + * the Tcl level. Therefore no timer here. */ } ReflectedChannel; @@ -949,18 +938,7 @@ TclChanPostEventObjCmd( #if TCL_THREADS if (rcPtr->owner == rcPtr->thread) { #endif - if (events & TCL_READABLE) { - if (rcPtr->readTimer == NULL) { - rcPtr->readTimer = Tcl_CreateTimerHandler(SYNTHETIC_EVENT_TIME, - TimerRunRead, rcPtr); - } - } - if (events & TCL_WRITABLE) { - if (rcPtr->writeTimer == NULL) { - rcPtr->writeTimer = Tcl_CreateTimerHandler(SYNTHETIC_EVENT_TIME, - TimerRunWrite, rcPtr); - } - } + Tcl_NotifyChannel(chan, events); #if TCL_THREADS } else { ReflectEvent *ev = (ReflectEvent *)Tcl_Alloc(sizeof(ReflectEvent)); @@ -1008,24 +986,6 @@ TclChanPostEventObjCmd( #undef EVENT } -static void -TimerRunRead( - void *clientData) -{ - ReflectedChannel *rcPtr = (ReflectedChannel *)clientData; - rcPtr->readTimer = NULL; - Tcl_NotifyChannel(rcPtr->chan, TCL_READABLE); -} - -static void -TimerRunWrite( - void *clientData) -{ - ReflectedChannel *rcPtr = (ReflectedChannel *)clientData; - rcPtr->writeTimer = NULL; - Tcl_NotifyChannel(rcPtr->chan, TCL_WRITABLE); -} - /* * Channel error message marshalling utilities. */ @@ -1224,12 +1184,6 @@ ReflectClose( Tcl_Free((void *)tctPtr); ((Channel *)rcPtr->chan)->typePtr = NULL; } - if (rcPtr->readTimer != NULL) { - Tcl_DeleteTimerHandler(rcPtr->readTimer); - } - if (rcPtr->writeTimer != NULL) { - Tcl_DeleteTimerHandler(rcPtr->writeTimer); - } Tcl_EventuallyFree(rcPtr, FreeReflectedChannel); return EOK; } @@ -1299,12 +1253,6 @@ ReflectClose( Tcl_Free((void *)tctPtr); ((Channel *)rcPtr->chan)->typePtr = NULL; } - if (rcPtr->readTimer != NULL) { - Tcl_DeleteTimerHandler(rcPtr->readTimer); - } - if (rcPtr->writeTimer != NULL) { - Tcl_DeleteTimerHandler(rcPtr->writeTimer); - } Tcl_EventuallyFree(rcPtr, FreeReflectedChannel); return (result == TCL_OK) ? EOK : EINVAL; } @@ -2253,8 +2201,6 @@ NewReflectedChannel( rcPtr->chan = NULL; rcPtr->interp = interp; rcPtr->dead = 0; - rcPtr->readTimer = 0; - rcPtr->writeTimer = 0; #if TCL_THREADS rcPtr->thread = Tcl_GetCurrentThread(); #endif diff --git a/tests/ioCmd.test b/tests/ioCmd.test index 7f27266..dfa7d06 100644 --- a/tests/ioCmd.test +++ b/tests/ioCmd.test @@ -971,17 +971,6 @@ proc onfinal {} { if {[lindex $hargs 0] ne "finalize"} {return} return -code return "" } - -proc onwatch {} { - upvar args hargs - lassign $hargs watch chan eventspec - if {$watch ne "watch"} return - foreach spec $eventspec { - chan postevent $chan $spec - } - return -} - } # Set everything up in the main thread. @@ -2063,7 +2052,7 @@ test iocmd-31.6 {chan postevent, posted events do happen} -match glob -body { close $c rename foo {} set res -} -result {{watch rc* read} {} {} TOCK {watch rc* {}}} +} -result {{watch rc* read} {} TOCK {} {watch rc* {}}} test iocmd-31.7 {chan postevent, posted events do happen} -match glob -body { set res {} proc foo {args} {oninit; onfinal; track; return} @@ -2076,7 +2065,7 @@ test iocmd-31.7 {chan postevent, posted events do happen} -match glob -body { close $c rename foo {} set res -} -result {{watch rc* write} {} {} TOCK {watch rc* {}}} +} -result {{watch rc* write} {} TOCK {} {watch rc* {}}} test iocmd-31.8 {chan postevent after close throws error} -match glob -setup { proc foo {args} {oninit; onfinal; track; return} proc dummy args { return } @@ -2089,31 +2078,6 @@ test iocmd-31.8 {chan postevent after close throws error} -match glob -setup { rename foo {} rename dummy {} } -returnCodes error -result {can not find reflected channel named "rc*"} -test iocmd-31.9 { - chan postevent - - call to current coroutine - - see 67a5eabbd3d1 -} -match glob -body { - set res {} - proc foo {args} {oninit; onwatch; onfinal; track; return} - set c [chan create {r w} foo] - after 0 [list ::apply [list c { - coroutine c1 ::apply [list c { - chan event $c readable [list [info coroutine]] - yield - set ::done READING - } [namespace current]] $c - } [namespace current]] $c] - set stop [after 10000 {set done TIMEOUT}] - vwait ::done - catch {after cancel $stop} - lappend res $done - close $c - rename foo {} - set res -} -result {{watch rc* read} READING {watch rc* {}}} # --- === *** ########################### # 'Pull the rug' tests. Create channel in a interpreter A, move to |
