Recipe 12.7 Automating Module Cleanup
12.7.1 Problem
You
need to create module setup code and cleanup code that gets called
automatically, without user intervention.
12.7.2 Solution
For setup code, put executable statements outside subroutine
definitions in the module file. For cleanup code, use an END
subroutine in that module.
12.7.3 Discussion
In some languages, the programmer must remember to call module
initialization code before accessing any of that module's regular
functions. Similarly, when the program is done, the programmer may
have to call module-specific finalization code.
Not so in Perl. For per-module initialization code, executable
statements outside of any subroutines in your module suffice. When
the module is loaded in, that code runs right then and there. The
user never has to remember to do this, because it's done
automatically.
Now, why would you want automatic cleanup code? It depends on the
module. You might want to write a shutdown message to a logfile, tell
a database server to commit any pending state, refresh a screen, or
return the tty to its original state.
Suppose you want a module to log quietly whenever a program using it
starts up or finishes. Add code in an END subroutine to run after
your program finishes:
$Logfile = "/tmp/mylog" unless defined $Logfile;
open(LF, ">>", $Logfile)
or die "can't append to $Logfile: $!";
select(((select(LF), $|=1))[0]); # unbuffer LF
logmsg("startup");
sub logmsg {
my $now = scalar gmtime;
print LF "$0 $$ $now: @_\n"
or die "write to $Logfile failed: $!";
}
END {
logmsg("shutdown");
close(LF)
or die "close $Logfile failed: $!";
}
The first part of code, outside any subroutine declaration, is
executed at module load time. The module user doesn't have to do
anything special to make this happen. Someone might be unpleasantly
surprised, however, if the file couldn't be accessed, since the
die would make the use or
require fail.
END routines work like exit handlers, such as trap
0 in the shell, atexit in C
programming, or global destructors or finalizers in object-oriented
languages. All of the ENDs in a program are run in the opposite order
that they were loaded; that is, last seen, first run. These get
called whether the program finishes through normal process
termination by implicitly reaching the end of your main program,
through an explicit call to the exit function, or
via an uncaught exception such as die or a mistake
involving division by zero.
Uncaught signals are a different matter, however. Death by signal
does not run your exit handlers. The following pragma takes care of
them:
use sigtrap qw(die normal-signals error-signals);
That causes all normal signals and error signals to make your program
expire via the die mechanism, effectively
converting a signal into an exception and thus permitting your END
handlers to run.
You can get fancier, too:
use sigtrap qw(
die untrapped normal-signals
stack-trace any error-signals
);
That says to die only on an untrapped normal
signal, but for error signals, to produce a stack trace before
dying—like the confess function from the
Carp module.
END also isn't called when a process polymorphs itself via the
exec function because you are still in the same
process, just a different program. All normal process attributes
remain, like process ID and parent PID, user and group IDs, umask,
current directory, environment variables, resource limits and
accumulated statistics, and open file descriptors (however, see the
$^F variable in perlvar(1) or
Programming Perl). If it didn't work this way,
exit handlers would execute redundantly in programs manually managing
their fork and exec calls. This
would not be good.
12.7.4 See Also
The standard use sigtrap
pragma, also in Chapter 31 of Programming Perl;
Chapter 18 of Programming Perl and the section
on "Package Constructors and Destructors" in
perlmod(1); the $^F
($SYSTEM_FD_MAX) variable in Chapter 28 of
Programming Perl and in
perldata(1); the fork and
exec functions in Chapter 29 of
Programming Perl and in
perlmod(1)
|