Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Fix for [ac7592e73c10d04b], Idle events are never processed when a "writable" handler on a nonblocking channel dominates the event queue. |
---|---|
Downloads: | Tarball | ZIP archive | SQL archive |
Timelines: | family | ancestors | descendants | both | bug-ac7592e73c10d04b |
Files: | files | file ages | folders |
SHA3-256: |
b2d083e9e04e492d8a96054b4698a900 |
User & Date: | pooryorick 2024-04-01 00:23:06 |
References
2024-04-01
| ||
00:26 | • Ticket [ac7592e73c] idle events are never processed when a "writable" handler on a nonblocking channel dominates the event queue status still Open with 3 other changes artifact: e18b556924 user: pooryorick | |
Context
2024-04-01
| ||
00:48 | In io.test/io-44.7, use a unique namespace for the refchan implementation. check-in: 7fa4203380 user: pooryorick tags: bug-ac7592e73c10d04b | |
00:23 | Fix for [ac7592e73c10d04b], Idle events are never processed when a "writable" handler on a nonblocki... check-in: b2d083e9e0 user: pooryorick tags: bug-ac7592e73c10d04b | |
2024-03-29
| ||
15:43 | 4 more files, which should have been removed as part of the libtommath 1.2 -> 1.3 upgrade check-in: 8a8722e215 user: jan.nijtmans tags: trunk, main | |
Changes
Changes to generic/tclIO.c.
︙ | ︙ | |||
1703 1704 1705 1706 1707 1708 1709 | statePtr->saveInBufPtr = NULL; statePtr->inQueueHead = NULL; statePtr->inQueueTail = NULL; statePtr->chPtr = NULL; statePtr->interestMask = 0; statePtr->scriptRecordPtr = NULL; statePtr->bufSize = CHANNELBUFFER_DEFAULT_SIZE; | < | 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 | statePtr->saveInBufPtr = NULL; statePtr->inQueueHead = NULL; statePtr->inQueueTail = NULL; statePtr->chPtr = NULL; statePtr->interestMask = 0; statePtr->scriptRecordPtr = NULL; statePtr->bufSize = CHANNELBUFFER_DEFAULT_SIZE; statePtr->timerChanPtr = NULL; statePtr->csPtrR = NULL; statePtr->csPtrW = NULL; statePtr->outputStage = NULL; /* * As we are creating the channel, it is obviously the top for now. |
︙ | ︙ | |||
8696 8697 8698 8699 8700 8701 8702 | * Our solution here is to drop the interest in the EXCEPTION * events too. This compiles on all platforms, and also passes the * testsuite on all of them. */ mask &= ~TCL_EXCEPTION; | | < | | < | < | 8695 8696 8697 8698 8699 8700 8701 8702 8703 8704 8705 8706 8707 8708 8709 8710 8711 8712 8713 8714 8715 8716 8717 8718 8719 8720 8721 8722 8723 | * Our solution here is to drop the interest in the EXCEPTION * events too. This compiles on all platforms, and also passes the * testsuite on all of them. */ mask &= ~TCL_EXCEPTION; if (!statePtr->timerChanPtr) { TclChannelPreserve((Tcl_Channel)chanPtr); statePtr->timerChanPtr = chanPtr; Tcl_DoWhenIdle(ChannelTimerProc, chanPtr); } } } if (!statePtr->timerChanPtr && mask & TCL_WRITABLE && GotFlag(statePtr, CHANNEL_NONBLOCKING)) { TclChannelPreserve((Tcl_Channel)chanPtr); statePtr->timerChanPtr = chanPtr; Tcl_DoWhenIdle(ChannelTimerProc,chanPtr); } ChanWatch(chanPtr, mask); } /* *---------------------------------------------------------------------- * |
︙ | ︙ | |||
8753 8754 8755 8756 8757 8758 8759 | * until ChannelTimerProc is later called again. */ if (chanPtr->typePtr == NULL) { CleanupTimerHandler(statePtr); } else { Tcl_Preserve(statePtr); | < < | < | | | < | 8749 8750 8751 8752 8753 8754 8755 8756 8757 8758 8759 8760 8761 8762 8763 8764 8765 8766 8767 8768 8769 8770 8771 8772 8773 8774 8775 8776 8777 8778 8779 8780 8781 8782 8783 8784 8785 8786 8787 8788 8789 8790 8791 8792 8793 8794 8795 8796 8797 8798 8799 8800 8801 8802 8803 8804 8805 8806 8807 8808 8809 8810 8811 8812 | * until ChannelTimerProc is later called again. */ if (chanPtr->typePtr == NULL) { CleanupTimerHandler(statePtr); } else { Tcl_Preserve(statePtr); if (statePtr->interestMask & TCL_WRITABLE && GotFlag(statePtr, CHANNEL_NONBLOCKING) && !GotFlag(statePtr, BG_FLUSH_SCHEDULED)) { /* * Restart the timer in case a channel handler reenters the event loop * before UpdateInterest gets called by Tcl_NotifyChannel. */ Tcl_DoWhenIdle(ChannelTimerProc,chanPtr); Tcl_NotifyChannel((Tcl_Channel) chanPtr, TCL_WRITABLE); } 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. */ Tcl_DoWhenIdle(ChannelTimerProc,chanPtr); Tcl_NotifyChannel((Tcl_Channel) chanPtr, TCL_READABLE); } else { CleanupTimerHandler(statePtr); UpdateInterest(chanPtr); } } else { CleanupTimerHandler(statePtr); } } Tcl_Release(statePtr); } } static void DeleteTimerHandler( ChannelState *statePtr ) { if (statePtr->timerChanPtr != NULL) { Tcl_CancelIdleCall(ChannelTimerProc,statePtr->timerChanPtr); CleanupTimerHandler(statePtr); } } static void CleanupTimerHandler( ChannelState *statePtr ){ TclChannelRelease((Tcl_Channel)statePtr->timerChanPtr); statePtr->timerChanPtr = NULL; } /* *---------------------------------------------------------------------- * * Tcl_CreateChannelHandler -- |
︙ | ︙ |
Changes to generic/tclIO.h.
︙ | ︙ | |||
185 186 187 188 189 190 191 | * this channel. */ int interestMask; /* Mask of all events this channel has * handlers for. */ EventScriptRecord *scriptRecordPtr; /* Chain of all scripts registered for event * handlers ("fileevent") on this channel. */ Tcl_Size bufSize; /* What size buffers to allocate? */ | < | 185 186 187 188 189 190 191 192 193 194 195 196 197 198 | * this channel. */ int interestMask; /* Mask of all events this channel has * handlers for. */ EventScriptRecord *scriptRecordPtr; /* Chain of all scripts registered for event * handlers ("fileevent") on this channel. */ Tcl_Size bufSize; /* What size buffers to allocate? */ Channel *timerChanPtr; /* Needed in order to decrement the refCount of the right channel when the timer is deleted. */ struct CopyState *csPtrR; /* State of background copy for which channel * is input, or NULL. */ struct CopyState *csPtrW; /* State of background copy for which channel * is output, or NULL. */ |
︙ | ︙ |
Changes to tests/io.test.
︙ | ︙ | |||
6233 6234 6235 6236 6237 6238 6239 | } -cleanup { close $f4 } -result {initial foo eof} close $f test io-44.6 {FileEventProc procedure: write-only non-blocking channel} -setup { | | | 6233 6234 6235 6236 6237 6238 6239 6240 6241 6242 6243 6244 6245 6246 6247 | } -cleanup { close $f4 } -result {initial foo eof} close $f test io-44.6 {FileEventProc procedure: write-only non-blocking channel} -setup { } -constraints {stdio fileevent} -body { namespace eval refchan { namespace ensemble create namespace export * proc finalize {chan args} { |
︙ | ︙ | |||
6284 6285 6286 6287 6288 6289 6290 6291 6292 6293 6294 6295 6296 6297 | puts $f $data incr count [string length $data] if {$count > 262144} { chan event $f writable {} set x done } }] set token [after 10000 [namespace code { set x timeout }]] vwait [namespace which -variable x] return $x } -cleanup { after cancel $token | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 6284 6285 6286 6287 6288 6289 6290 6291 6292 6293 6294 6295 6296 6297 6298 6299 6300 6301 6302 6303 6304 6305 6306 6307 6308 6309 6310 6311 6312 6313 6314 6315 6316 6317 6318 6319 6320 6321 6322 6323 6324 6325 6326 6327 6328 6329 6330 6331 6332 6333 6334 6335 6336 6337 6338 6339 6340 6341 6342 6343 6344 6345 6346 6347 6348 6349 6350 6351 6352 6353 6354 6355 6356 6357 6358 6359 6360 6361 6362 6363 6364 6365 6366 6367 6368 6369 6370 6371 6372 6373 6374 | puts $f $data incr count [string length $data] if {$count > 262144} { chan event $f writable {} set x done } }] set token [after 10000 [namespace code { set x timeout }]] vwait [namespace which -variable x] return $x } -cleanup { after cancel $token catch {chan close $f} } -result done test io-44.7 { FileEventProc procedure: write-only non-blocking channel postevent idle } -setup { } -constraints {stdio fileevent} -body { namespace eval refchan { namespace ensemble create namespace export * proc finalize {chan args} { namespace delete c_$chan } proc initialize {chan args} { namespace eval c_$chan {} namespace upvar c_$chan watching watching set watching {} list finalize initialize seek watch write } proc watch {chan args} { namespace upvar c_$chan watching watching foreach arg $args { switch $arg { write { if {$arg ni $watching} { lappend watching $arg } after idle after 0 chan postevent $chan $arg } } } } proc write {chan args} { incr ::counter after idle after 0 chan postevent $chan write return 1 } } set f [chan create w [namespace which refchan]] chan configure $f -blocking 0 chan event $f writable [namespace code { puts $f X }] variable x {} apply [list {} { set script { set lambda [list ::apply [list script { variable count variable x if {[incr count] < 1000} { try $script } else { set x done } } [namespace current]] $script] after idle [list after 0 $lambda] } try $script } [namespace current]] set token [after 10000 [namespace code { set x timeout }]] vwait [namespace which -variable x] return $x } -cleanup { after cancel $token |
︙ | ︙ |