#939 socket fileevents don't queue fairly

final: 8.1.1
closed-fixed
nobody
2
2001-04-22
2000-10-26
Anonymous
No

OriginalBugID: 2355 Bug
Version: 8.1.1
SubmitDate: '1999-07-16'
LastModified: '1999-07-21'
Severity: SER
Status: Released
Submitter: techsupp
ChangedBy: redman
OS: Windows 95
Machine: X86
FixedDate: '1999-07-21'
FixedInVersion: 1.3
ClosedDate: '2000-10-25'

Name:
Don Porter

Comments:
This bug is visible on both Windows 95 and Windows 98, but not on
Windows NT.

ReproducibleScript:
Three script files follow, server.tcl, data.tcl, ctrl.tcl:

# FILE: server.tcl
# Computation engine/server program
########################################################################
# Utility proc for reading from non-blocking socket
proc Receive {datahdlr closehdlr s} {
if {[catch {gets $s line} readCount]} {
# socket error
$closehdlr $s
close $s
return
}
if {$readCount < 0} {
if {[fblocked $s]} {
return
}
if {[eof $s]} {
$closehdlr $s
close $s
return
}
}
$datahdlr $s $line
}

########################################################################
# Server for Data clients. Send out iteration counts to them.
# Display their replies in Tk labels.

set datasockets {}

proc DataHdlr {s line} {
set ::msg($s) $line
}

proc DataCloseHdlr {s} {
set idx [lsearch -exact $::datasockets $s]
set ::datasockets [lreplace $::datasockets $idx $idx]
destroy .l$s
unset ::msg($s)
}

proc DataChannel {s h p} {
fconfigure $s -blocking 0 -buffering line -translation {auto crlf}
puts $s "Connected to Data"
lappend ::datasockets $s
pack [label .l$s -textvariable msg($s)]
fileevent $s readable [list Receive DataHdlr DataCloseHdlr $s]
}

socket -server DataChannel 7000

proc StepReport {ct} {
foreach s $::datasockets {
puts $s $ct
}
}

########################################################################
# Iterative computation engine. [Step] is one iteration.
# [ChangeState] starts and stops the computation.

set afterId {}
set state 0

proc ChangeState {f} {
if {$::state == $f} {
return
}
after cancel $::afterId
if {$f} {
set ::afterId [after idle Step]
} else {
set ::afterId {}
}
set ::state $f
}

set count 0

proc Step {} {
after 1000; # Simulate computation
StepReport [incr ::count]
set ::afterId [after 1 {set ::afterId [after idle Step]}]
}

########################################################################
# Server for Control clients. Recieve "start" and "stop" commands from
# them to start and stop the computation engine.

proc CtrlHdlr {s line} {
switch -exact $line {
start {ChangeState 1}
stop {ChangeState 0}
default {}
}
}

proc CtrlCloseHdlr {s} {}

proc CtrlChannel {s h p} {
fconfigure $s -blocking 0 -buffering line -translation {auto crlf}
puts $s "Connected to Control"
fileevent $s readable [list Receive CtrlHdlr CtrlCloseHdlr $s]
}

socket -server CtrlChannel 5000

pack [button .quit -text Quit -command exit]
# END FILE: server.tcl

# FILE: data.tcl
# Data client program
set s [socket localhost 7000]
fconfigure $s -blocking 0 -buffering line -translation {auto crlf}
fileevent $s readable [list Read $s]
proc Read {s} {
set ::value [gets $s]
if {![eof $s]} {
puts $s "Got: $::value"
}
}
label .l -textvariable value
button .quit -text Quit -command exit
pack .l .quit
# END FILE: data.tcl

# FILE: ctrl.tcl
# Control client program
set s [socket localhost 5000]
fconfigure $s -blocking 0 -buffering line -translation {auto crlf}
button .start -text Start -command {puts $s start}
button .stop -text Stop -command {puts $s stop}
button .quit -text Quit -command exit
pack .start .stop .quit
# END FILE: ctrl.tcl

ObservedBehavior:
Using wish, start one copy each of server.tcl, ctrl.tcl, and data.tcl,
in that order. Click "Start" and "Stop" in the ctrl window to see how
the control client starts and stops the computation in the server. The
iteration count displayed in the data client will start and stop on
command.
Whatever iteration count is displayed when the "Stop" button is clicked,
one more iteration will display, then the server's computation will
stop,
and the iteration display will stop changing.

Next, start more data clients. After only a few (I see the problem
reliably
with 4 data clients), the server will no longer respond immediately to a
"Stop" command from the control client. The iteration display will
keeping
ticking merrily along for many iterations before the "Stop" command is
finally acknowledged, and the computation and iteration display stop.

The socket message with the "Stop" command from the control client is
crowded
out by the sea of reply messages "Got: $i" from the data clients. The
socket readable fileevent code in Tcl is not queueing the readable
fileevents fairly. The fileevent carrying the "Stop" command can be
delayed indefinitely while
more recently arrived socket data is read from the data clients.

DesiredBehavior:
When multiple sockets have readable fileevent handlers, traffic on one
socket should not be starved of handling while more recent traffic on
other sockets is handled.

Run the same test scripts using wish8.0p2. Everything works as expected
with that version of Tcl/Tk on Windows 95. The changes made to
tclWinSock.c
in the Tcl 8.0.3 release apparently introduced this bug. The bug
persists
in all subsequent Tcl/Tk releases up through 8.1.1.

Reproduced with 8.1.1, but now works fine with 8.2b2 code.

-- 07/21/1999 redman

Discussion

  • Brent B. Welch

    Brent B. Welch - 2000-10-26
    • priority: 5 --> 2
    • status: open --> closed-fixed
     
  • Don Porter

    Don Porter - 2001-04-22
    • labels: 104246 --> 27. Channel Types