after 500The after command can register a Tcl command to occur after a period of time, in milliseconds:
after milliseconds cmd arg arg...The after command behaves like eval; if you give it extra arguments it concatenates them to form a single command. If your argument structure is important, use list to build the command. The following example always works, no matter what the value of myvariable is:
after 500 [list puts $myvariable]The return value of after is an identifier for the registered command. You can cancel this command with the after cancel operation. You specify either the identifier returned from after, or the command string. In the latter case the event that matches the command string exactly is canceled.
Table 14-1 summarizes the after command:
The fileevent Command
The fileevent command registers a procedure that is called when an I/O channel is ready for read or write events. For example, you can open a pipeline or network socket for reading, and then process the data from the pipeline or socket using a command registered with fileevent. Using network sockets is described in Chapter 14. The advantage of this approach is that your application can do other things, like update the user interface, while waiting for data from the pipeline or socket. You can use fileevent on stdin and stdout, too.
The command registered with fileevent uses the regular Tcl commands to read or write data on the I/O channel. For example, if the pipeline generates line-oriented output, you should use gets to read a line of input. If you try and read more data than is available, your application may block waiting for more input. For this reason you should read one line in your fileevent handler, assuming the data is line-oriented. If you know the pipeline will generate data in fixed-sized blocks, then you can use the read command to read one block.
set pipe [open "|some command"]
fileevent $pipe readable [list Reader $pipe]
proc Reader { pipe } {
if [eof $pipe] {
catch {close $pipe}
return
}
gets $pipe line
# Process one line
}Table 14-2 summarizes the fileevent command.
fileevent fileId readable ?command? | Query or register command to be called when fileId is readable. |
fileevent fileId writable ?command? | Query or register command to be called when fileId is writable. |
The vwait Command
The vwait command waits until a variable is modified. For example, you can set variable x at a future time, and then wait for that variable to be set with vwait.
set x 0
after 500 {set x 1}
vwait xWaiting with vwait causes Tcl to enter the event loop. Tcl will process events until the variable x is modified. The vwait command completes when some Tcl code runs in response to an event and modifies the variable. In this case the event is a timer event, and the Tcl code is simply:
set x 1In some cases x is not used at all except to start the event loop. The following example sets up a file event handler for stdin that will read and execute commands. Once this is set up, vwait is used to enter the event loop and process commands until the input channel is closed. The process exits at that point, so the vwait variable forever is not used:
fileevent stdin readable StdinRead
proc StdinRead {} {
global command
if [eof stdin] {
exit
}
append command(line) [gets stdin]
if [info complete $command(line)] {
catch {uplevel #0 $command(line)} result
puts $result
set command(line) {}
}
}
vwait forever
fconfigure stdin-blocking 1 -buffering none -buffersize 4096 -eofchar {} -translation lf
Table 14-3 summarizes the properties controlled by fconfigure. They are discussed in more detail below.
Non-Blocking I/O
By default, I/O channels are blocking. A gets or read will wait until data is available before returning. A puts may also wait if the I/O channel is not ready to accept data. This behavior is OK if you are using disk files, which are essentially always ready. If you use pipelines or network sockets, however, the blocking behavior can hang up your application.
fconfigure fileID -blocking 0It is not strictly necessary to put a channel into non-blocking mode if you use fileevent. However, if the channel is in blocking mode, then it is still possible for the gets or read done by your fileevent procedure to block. For example, an I/O channel might have some data ready, but not a complete line. In this case a gets would block, unless the channel is non-blocking. Perhaps the best motivation for a non-blocking channel is the buffering behavior of a non-blocking puts. You can even close a channel that has buffered data, and Tcl will automatically write out the buffers as the channel becomes ready. For these reasons, it is common to use a non-blocking channel with fileevent. Example 14-3 shows a fileevent handler for a non-blocking channel. As described above, the gets may not find a complete line, in which case it doesn't read anything and returns -1.
set pipe [open "|some command"]
fileevent $pipe readable [list Reader $pipe]
fconfigure $pipe -blocking 0
proc Reader { pipe } {
if [eof $pipe] {
catch {close $pipe}
return
}
if {[gets $pipe line] < 0} {
# We blocked anyway because only part of a line
# was available for input
} else {
# Process one line
}
}
fconfigure fileID -buffering noneFull buffering means that output data is accumulated until a buffer fills, then a write is performed. For reading, Tcl attempts to read a whole buffer each time more data is needed. The read-ahead for buffering will not block. The -buffersize parameter controls the buffer size:
fconfigure fileID -buffering full -buffersize 8192Line buffering is used by default on stdin and stdout. Each newline in an output channel causes an write operation. Read buffering is the same as full buffering. The following command turns on line buffering:
fconfigure fileID -buffering line
The default behavior is almost always what you want, but you can control the translattion with fconfigure. The possible settings for -translation are:
fconfigure fileID -eofchar {}
fconfigure pipe -translation {auto crlf} -buffersize 4096