NAME
bgexec - Run programs in the background while handling Tk
events.
SYNOPSIS
bgexec varName ?option value?... program ?arg?...
_________________________________________________________________
DESCRIPTION
The bgexec command executes programs in the background,
allowing Tk to handle events. A global Tcl variable var
Name is set when the program has completed.
INTRODUCTION
Tcl's exec command is very useful for gathering informa
tion 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 nor
mally. 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 for the program is exactly the same as
the previous example, when we used exec.
global myStatus myOutput
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.
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.
set myStatus {}
There are several bgexec options to collect different
types of information.
global myStatus myOutput myErrs
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 -onout
put 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
}
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 { 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
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
global myStatus myOutput
bgexec myStatus -output myOutput du -s $dir &
...
tkwait variable myStatus
SYNTAX
The bgexec command takes the following form:
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 sta
tus 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 sig
nal 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 pro
gram 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 com
pletes.
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:
-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.
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 when
ever 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 when
ever 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.
-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 stan
dard 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 stan
dard output. The data is appended to the command as
an extra argument before it is executed.
-update varName
Deprecated. This option is replaced by -onerror.
-- 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 pro
gram can not finish until the second program has com
pleted.
ing 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 pro
gram 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 tranparently 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 pro
gram, 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.
busy, exec, tkwait
KEYWORDS
exec, background, busy
Man(1) output converted with
man2html