NAME¶
bgexec - Run programs in the background while handling Tk events.
SYNOPSIS¶
blt::bgexec varName ?
option value?...
program
?
arg?...
DESCRIPTION¶
The
bgexec command executes programs in the background, allowing Tk to
handle events. A global Tcl variable
varName is set when the program
has completed.
INTRODUCTION¶
Tcl's
exec command is very useful for gathering information from the
operating system. It runs a program and returns the output as its result. This
works well for Tcl-only applications. But for Tk applications, a problem
occurs when the program takes time to process. Let's say we want the get the
disk usage of a directory. We'll use the Unix program du to get the summary.
set out [exec du -s $dir]
puts "Disk usage for $dir is $out"
While du is running, scrollbars won't respond. None of the Tk widgets will be
redrawn properly. The
send command won't work. And the worst part is
that the application appears hung up or dead. The problem is that while
exec is waiting for
du to finish, Tk is not able to handle X
events.
The
bgexec command performs the same functions as
exec, but also
allows Tk to handle events. You can execute a long-running program and the Tk
widgets will behave normally. When the program finishes, its output and the
exit status are written to Tcl variables. This makes it easy to monitor and
save the output of a program.
EXAMPLE¶
Here is the disk usage example again, this time using
bgexec. The syntax
to invoke "du" is exactly the same as the previous example, when we
used
exec.
global myStatus myOutput
blt::bgexec myStatus -output myOutput du -s $dir
puts "Disk usage for $dir is $myOutput"
Two global variables, myStatus and myOutput, will be set by
bgexec when
du has completed. MyStatus will contain the program's exit status. MyOutput,
specified by the
-output option, will store the output of the program.
You can also terminate the program by setting the variable myStatus. If myStatus
is set before du has completed, the process is killed. Under Unix, this is
done sending by a configurable signal (by default it's SIGKILL). Under Win32,
this is done by calling
TerminateProcess. It makes no difference what
myStatus is set to.
There are several
bgexec options to collect different types of
information.
global myStatus myOutput myErrs
blt::bgexec myStatus -output myOutput -error myErrs du -s $dir
The
-error option is similar to
-output. It sets a global variable
when the program completes. The variable will contain any data written to
stderr by the program.
The
-output and
-error variables are set only after the program
completes. But if the program takes a long time, to run you may want to
receive its partial output. You can gather data as it becomes available using
the
-onoutput option. It specifies a Tcl command prefix. Whenever new
data is available, this command is executed, with the data appended as an
argument to the command.
proc GetInfo { data } {
puts $data
}
blt::bgexec myStatus -onoutput GetInfo du -s $dir
When output is available, the procedure GetInfo is called. The
-onerror
option performs a similar function for the stderr data stream.
Like
exec,
bgexec returns an error if the exit code of the program
is not zero. If you think you may get a non-zero exit code, you might want to
invoke
bgexec from within a
catch.
catch { blt::bgexec myStatus -output myOutput du -s $dir }
By default,
bgexec will wait for the program to finish. But you can
detach the program making ampersand (&) the last argument on the command
line.
global myStatus myOutput
blt::bgexec myStatus -output myOutput du -s $dir &
Bgexec will return immediately and its result will be a list of the
spawned process ids. If at some point you need to wait for the program to
finish up, you can use
tkwait. When the program finishes, the variable
myStatus will be written to, breaking out the
tkwait command.
global myStatus myOutput
blt::bgexec myStatus -output myOutput du -s $dir &
...
tkwait variable myStatus
SYNTAX¶
The
bgexec command takes the following form:
blt::bgexec varName ?
option value?...
program
?
arg?...
VarName is the name of a global variable which is set when
program
has finished executing. The exit status of will be stored in
varName.
The exit status is a list of a status token, the process-id of the program,
the exit code, and a status message. You can also prematurely terminate the
program by setting
varName. Under Unix, the program will be sent a
signal to terminate it (by default the signal is a SIGKILL; see the
-killsignal option).
Program is the name of the program to be executed and
args are any
extra arguments for
program. The syntax of
program and
args is the same as the
exec command. So you can redirect I/O,
execute pipelines, etc. (see the
exec manual for further information)
just like
exec. If the last argument is an ampersand (&), the
program will be run detached, and
bgexec will return immediately.
VarName will still be set with the return status when
program
completes.
OPTIONS¶
Option refers to the switch name always beginning with a dash (-).
Value is the value of the option. Option-value pairs are terminated
either by the program name, or double dashes (--). The following options are
available for
bgexec:
- -decodeerror encodingName
-
Specifies the encoding of the stderr channel. This affects only data
returned to the Tcl interpreter. No translation is done on file
redirection.
For example if data is to be converted from Unicode for use in Tcl, you
would use the "unicode" encoding. The default is that no
translation is performed.
- -decodeoutput encodingName
-
Specifies the encoding of the stdout channels. This affects only data
returned to the Tcl interpreter. No translation is done on file
redirection.
For example if data is to be converted from Unicode for use in Tcl, you
would use the "unicode" encoding. The default is that no
translation is performed.
- -error varName
-
Specifies that a global variable varName is to be set with the
contents of stderr after the program has completed.
- -keepnewline boolean
- Specifies that a trailing newline should be retained in the
output. If boolean is true, the trailing newline is truncated from
the output of the -onoutput and -output variables. The
default value is true.
- -killsignal signal
- Specifies the signal to be sent to the program when
terminating. This is available only under Unix. Signal can either
be a number (typically 1-32) or a mnemonic (such as SIGINT). If
signal is the empty string, then no signal is sent. The default
signal is 9 (SIGKILL).
- -lasterror varName
- Specifies a variable varName that is updated
whenever data becomes available from standard error of the program.
VarName is a global variable. Unlike the -error option, data
is available as soon as it arrives.
- -lastoutput varName
- Specifies a variable varName that is updated
whenever data becomes available from standard output of the program.
VarName is a global variable. Unlike the -output option,
data is available as soon as it arrives.
- -linebuffered boolean
- Specifies that updates should be made on a line-by-line
basis. Normally when new data is available bgexec will set the
variable ( -lastoutput and -lasterror options) or invoke the
command ( -onoutput and -onerror options) delivering all the
new data currently available. If boolean is true, only one line at
a time will be delivered. This can be useful when you want to process the
output on a line-by-line basis. The default value is false.
- -output varName
-
Specifies that a global variable varName is to be set with the output
of the program, once it has completed. If this option is not set, no
output will be accumulated.
- -onerror command
- Specifies the start of a Tcl command that will be executed
whenever new data is available from standard error. The data is appended
to the command as an extra argument before it is executed.
- -onoutput command
- Specifies the start of a Tcl command that will be executed
whenever new data is available from standard output. The data is appended
to the command as an extra argument before it is executed.
- -update varName
- Deprecated. This option is replaced by
-lasterror.
- --
- This marks the end of the options. The following argument
will be considered the name of a program even if it starts with a dash (
-).
PREEMPTION¶
Because
bgexec allows Tk to handle events while a program is running,
it's possible for an application to preempt itself with further
user-interactions. Let's say your application has a button that runs the disk
usage example. And while the du program is running, the user accidently
presses the button again. A second
bgexec program will preempt the
first. What this means is that the first program can not finish until the
second program has completed.
Care must be taken to prevent an application from preempting itself by blocking
further user-interactions (such as button clicks). The BLT
busy command
is very useful for just these situations. See the
busy manual for
details.
DIFFERENCES WITH FILEEVENT¶
Since Tk 4.0, a subset of
bgexec can be also achieved using the
fileevent command. The steps for running a program in the background
are:
Execute the program with the
open command (using the "|"
syntax) and save the file handle.
global fileId
set fileId [open "|du -s $dir" r]
Next register a Tcl code snippet with
fileevent to be run whenever output
is available on the file handle. The code snippet will read from the file
handle and save the output in a variable.
fileevent fileId readable {
if { [gets $fileId line] < 0 } {
close $fileId
set output $temp
unset fileId temp
} else {
append temp $line
}
}
The biggest advantage of
bgexec is that, unlike
fileevent, it
requires no additional Tcl code to run a program. It's simpler and less error
prone. You don't have to worry about non-blocking I/O. It's handled
transparently for you.
Bgexec runs programs that
fileevent can not.
Fileevent
assumes that the when stdout is closed the program has completed. But some
programs, like the Unix compress program, reopen stdout, fooling
fileevent into thinking the program has terminated. In the example
above, we assume that the program will write and flush its output
line-by-line. However running another program, your application may block in
the
gets command reading a partial line.
Bgexec lets you get back the exit status of the program. It also allows
you to collect data from both stdout and stderr simultaneously. Finally, since
data collection is handled in C code,
bgexec is faster. You get back to
the Tk event loop more quickly, making your application seem more responsive.
SEE ALSO¶
busy, exec, tkwait
KEYWORDS¶
exec, background, busy