If there is pending BG output for a non-blocking channel
then Tcl_DriverCloseProc() is not called when the 'close'
command is invoked.
That can be seen from generic/tclIO.c :
Tcl_Unregister_Channel():
if (!(statePtr->flags & BG_FLUSH_SCHEDULED)) {
...
This can be very bad if channel's output is stalled, e.g. a
serial port blocked by handshake:
% puts "Tcl $tcl_patchLevel"
Tcl 8.4b1
% set chan [open com1: r+]
fileaaf550
% fconfigure $chan -buffering none -blocking 0
% fconfigure $chan -mode 1200,n,8,1 -handshake rtscts
% ### 2 outputs: "hello world" \x0D\x0A, BG_FLUSH
% puts $chan "hello world"
% puts "Queue: [fconfigure $chan -queue]"
Queue: 0 13
% after 1000
% puts "Queue: [fconfigure $chan -queue]"
Queue: 0 13
% close $chan
% set chan [open com1: r+]
couldn't open "com1:": permission denied
%
This problem occurs also for slow output without
handshake:
% puts "Tcl $tcl_patchLevel"
Tcl 8.4b1
% set chan [open com1: r+]
fileaaf768
% fconfigure $chan -buffering none -blocking 0
% # Explicitely reset handshake=none
% fconfigure $chan -mode 1200,n,8,1 -handshake none
% puts $chan "hello world"
% puts $chan "hello world"
% close $chan
% set chan [open com1: r+]
couldn't open "com1:": permission denied
For Tcl < 8.4. this has never been observed for serial
ports, because serial output has already been blocking.
Logged In: YES
user_id=99573
This bahaviour may be interpretet not as a bug,
but as a feature of the channel system.
But then we need an additional option
[fconfigure $chan -flushonclose 0]
(default=1) for channels like serial ports.
Logged In: YES
user_id=79902
When I have time (maybe, just maybe, over Xmas) I'll be
advancing a TIP on behaviour-on-close of serial channels.
Logged In: YES
user_id=80530
Is this related to FR 525783 ?
Logged In: YES
user_id=99573
IMO not. [ 526163 ] tty not reset on exit
is related to the (requested) change made by TIP#35, not to
restore the original TTY settings on close, so that tcl can
be used as a simple
'stty' substitute.
This stuff is not yet finally removed - see the comment in
tclUnixChan.c, ttyCloseProc().
Logged In: YES
user_id=75003
Note: If BG_FLUSH_SCHEDULED is set the channel cannot
be closed completely. There is a BackGround-FLUSH of data
active. The channel won't be visible at the script level
anymore, but the data structures remain until the flush is
completed. After that happend the close proc is called and
the structures are cleaned up completely. This is only for a
non-blocking channel.
To get 'flushonclose' behaviour just set the channel to -
blocking 1. Of course, this may stall the [close] at the tcl
level if the serial port itself is stalled.
Logged In: YES
user_id=99573
Yes, what you say emphasizes that Tcl needs a mechanism
to close a stalled serial channel by discarding all currently
pending output.
Logged In: YES
user_id=79902
There are several possible desired behaviours for what
should happen on closing of a serial channel, but I think
these are the interesting cases:
wait until all OS buffers are empty and reset to initial
state
discard all pending output (including OS level) and reset
to init.
leave channel in *current* state
(I'll not specify what happens to the OS buffers in that
last case as I believe that typically in that case, there
won't be much data in the buffers anyway!)
IIRC, right now we just support the first of those, and we
know that selection of the right behaviour can't be done
automatically (we don't want to discard debug info!) so that
calls for a suitable [fconfigure] option. Which means a TIP.
Which I've not had time to write. (And I'm not certain how
-blocking interacts with this; the buffers in question are
in the OS, not Tcl.)
Logged In: YES
user_id=99573
For blocking channels no changes are necessary.
For non-blocking channels the current behaviour is to put the
channel to *blocking* mode, wait until all Tcl output buffers
are done and only then call Tcl_DriverCloseProc().
If there would be a non-default [fconfigure -discardonclose 1]
option the channel system should
1. *Not* make the channel blocking.
2. Discard all pending output in Tcl buffers.
3. Immediately call Tcl_DriverCloseProc().
The serial SerialCloseProc() is responsive for the OS-level
output. So SerialCloseProc() should also check for the
[fconfigure -discardonclose 1] flag and discard OS-level output.
I could write the TIP and implement the the changes in the
serial drivers SerialCloseProc() for Windows & Posix. But I do
not feel skilled for the changes in the general channel system.