Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Fix for [39680865953cce4f], Basic nonblocking write-only refchan hangs. |
---|---|
Downloads: | Tarball | ZIP archive | SQL archive |
Timelines: | family | ancestors | bug-3968086595 |
Files: | files | file ages | folders |
SHA3-256: |
ab87ef464e12c190fc7a28672aa45d68 |
User & Date: | pooryorick 2024-08-13 13:45:38.623 |
References
2024-08-13
| ||
13:47 | • Pending ticket [3968086595]: Basic nonblocking write-only refchan hangs plus 4 other changes artifact: 08f15f7f32 user: pooryorick | |
Context
2024-08-13
| ||
13:45 | Fix for [39680865953cce4f], Basic nonblocking write-only refchan hangs. Closed-Leaf check-in: ab87ef464e user: pooryorick tags: bug-3968086595 | |
13:32 | Fix [2f22a7364d]: cesu-8 encoding gives same result for different strings check-in: da1af6e174 user: jan.nijtmans tags: trunk, main | |
Changes
Changes to generic/tclIO.c.
︙ | ︙ | |||
8756 8757 8758 8759 8760 8761 8762 8763 8764 8765 8766 8767 8768 8769 | TclChannelPreserve((Tcl_Channel)chanPtr); statePtr->timerChanPtr = chanPtr; statePtr->timer = Tcl_CreateTimerHandler(SYNTHETIC_EVENT_TIME, ChannelTimerProc, chanPtr); } } } ChanWatch(chanPtr, mask); } /* *---------------------------------------------------------------------- * * ChannelTimerProc -- | > > > > > > > > > > > > > > > > > > > | 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 | TclChannelPreserve((Tcl_Channel)chanPtr); statePtr->timerChanPtr = chanPtr; statePtr->timer = Tcl_CreateTimerHandler(SYNTHETIC_EVENT_TIME, ChannelTimerProc, chanPtr); } } } if (!statePtr->timer && mask & TCL_WRITABLE && GotFlag(statePtr, CHANNEL_NONBLOCKING) && ( statePtr->curOutPtr && !IsBufferEmpty(statePtr->curOutPtr) && !IsBufferFull(statePtr->curOutPtr) ) ) { TclChannelPreserve((Tcl_Channel)chanPtr); statePtr->timerChanPtr = chanPtr; statePtr->timer = Tcl_CreateTimerHandler(SYNTHETIC_EVENT_TIME, ChannelTimerProc,chanPtr); } ChanWatch(chanPtr, mask); } /* *---------------------------------------------------------------------- * * ChannelTimerProc -- |
︙ | ︙ | |||
8783 8784 8785 8786 8787 8788 8789 8790 8791 8792 8793 8794 8795 8796 8797 8798 8799 8800 8801 8802 8803 8804 8805 | static void ChannelTimerProc( void *clientData) { Channel *chanPtr = (Channel *)clientData; /* State info for channel */ ChannelState *statePtr = chanPtr->state; if (chanPtr->typePtr == NULL) { statePtr->timer = NULL; 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); | > < > > | > > > > > > > > > > > > > | > > | 8802 8803 8804 8805 8806 8807 8808 8809 8810 8811 8812 8813 8814 8815 8816 8817 8818 8819 8820 8821 8822 8823 8824 8825 8826 8827 8828 8829 8830 8831 8832 8833 8834 8835 8836 8837 8838 8839 8840 8841 8842 8843 8844 8845 8846 8847 8848 8849 8850 8851 8852 8853 8854 | static void ChannelTimerProc( void *clientData) { Channel *chanPtr = (Channel *)clientData; /* State info for channel */ ChannelState *statePtr = chanPtr->state; int notified = 0; if (chanPtr->typePtr == NULL) { statePtr->timer = NULL; 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_READABLE); notified = 1; } if (chanPtr->typePtr != NULL && 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. */ statePtr->timer = Tcl_CreateTimerHandler(SYNTHETIC_EVENT_TIME, ChannelTimerProc,chanPtr); Tcl_NotifyChannel((Tcl_Channel) chanPtr, TCL_WRITABLE); notified = 1; } if (!notified) { statePtr->timer = NULL; UpdateInterest(chanPtr); /* Was set in UpdateInterest. */ TclChannelRelease((Tcl_Channel)statePtr->timerChanPtr); statePtr->timerChanPtr = NULL; } } } static void |
︙ | ︙ |
Changes to tests/io.test.
︙ | ︙ | |||
6364 6365 6366 6367 6368 6369 6370 6371 6372 6373 6374 6375 6376 6377 | close $chan set ::io-44.7-result success } [namespace current]] vwait ::io-44.7-result set ::io-44.7-result } -result success makeFile "foo bar" foo test io-45.1 {DeleteFileEvent, cleanup on close} {fileevent} { set f [open $path(foo) r] fileevent $f readable [namespace code { lappend x "binding triggered: \"[gets $f]\"" fileevent $f readable {} | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 6364 6365 6366 6367 6368 6369 6370 6371 6372 6373 6374 6375 6376 6377 6378 6379 6380 6381 6382 6383 6384 6385 6386 6387 6388 6389 6390 6391 6392 6393 6394 6395 6396 6397 6398 6399 6400 6401 6402 6403 6404 6405 6406 6407 6408 6409 6410 6411 6412 6413 6414 6415 6416 6417 6418 6419 6420 6421 6422 6423 6424 6425 6426 6427 6428 6429 6430 6431 6432 6433 6434 6435 6436 6437 6438 6439 6440 6441 6442 6443 6444 6445 6446 6447 6448 6449 6450 6451 6452 6453 6454 6455 6456 6457 6458 6459 6460 6461 6462 6463 6464 6465 6466 6467 6468 6469 6470 6471 6472 6473 6474 6475 6476 6477 6478 6479 6480 6481 6482 6483 6484 6485 | close $chan set ::io-44.7-result success } [namespace current]] vwait ::io-44.7-result set ::io-44.7-result } -result success test io-44.8 {write-only refchan should not hang} -setup { catch {namespace delete rc} namespace eval rc { namespace export * namespace ensemble create proc buffer chan { namespace upvar chan_$chan buffer buffer return $buffer } proc initialize {chan mode} { namespace eval chan_$chan { variable buffer {} variable watch {} variable writetask {} } return {initialize finalize watch write} } proc finalize chan { namespace upvar chan_$chan writetask writetask after cancel $writetask set writetask {} namespace delete chan_$chan } proc watch {chan spec} { set channs [namespace current]::chan_$chan namespace upvar $channs watch watch writetask writetask set watch $spec after cancel $writetask if {{write} in $spec} { set writetask [after 0 [list after idle [ list ::apply {{channs chan} { if {[namespace exists $channs]} { chan postevent $chan write } }} $channs $chan]]] } else { set writetask {} } return } proc write {chan data} { set channs [namespace current]::chan_$chan namespace upvar $channs buffer buffer watch watch \ writetask writetask append buffer $data after cancel writetask if {{write} in $watch} { set writetask [after 0 [list after idle [ list ::apply {{channs chan} { if {[namespace exists $channs]} { chan postevent $chan write } }} $channs $chan]]] } else { set writetask {} } return [string length $data] } proc post {chan side} { set ns chan_$chan if [namespace exists $ns] { chan postevent $chan $side } return } } } -cleanup { namespace delete rc } -body { variable done set chan [chan create write [namespace which rc]] try { chan configure $chan -blocking 0 coroutine c1 apply [list chan { variable done after 0 [list [info coroutine]] set written 0 yield chan event $chan writable [list [info coroutine]] # Perform enough to exercise more than one buffer. while {[incr i] < 500000} { yield puts $chan $i set written [expr {$written + [string length $i] + 1}] } chan configure $chan -blocking 1 flush $chan set buffersize [string length [rc buffer $chan]] set done [list $written $buffersize] } [namespace current]] $chan vwait [namespace current]::done } finally { close $chan } return $done } -result {3388888 3388888} makeFile "foo bar" foo test io-45.1 {DeleteFileEvent, cleanup on close} {fileevent} { set f [open $path(foo) r] fileevent $f readable [namespace code { lappend x "binding triggered: \"[gets $f]\"" fileevent $f readable {} |
︙ | ︙ |