The London Perl and Raku Workshop takes place on 26th Oct 2024. If your company depends on Perl, please consider sponsoring and/or attending.

NAME

atexit -- Register a subroutine to be invoked at program-exit time.

rmexit -- Unregister a subroutine that was registered with atexit.

SYNOPSIS

 use AtExit;
 
 sub cleanup {
     my @args = @_;
     print "cleanup() executing: args = @args\n";
 }
 
 $_ = atexit(\&cleanup, "This call was registered first");
 print "first call to atexit() returned $_\n";

 $_ = atexit("cleanup", "This call was registered second");
 print "second call to atexit() returned $_\n";

 $_ = atexit("cleanup", "This call should've been unregistered by rmexit");
 rmexit($_)  ||  warn "couldnt' unregister exit-sub $_!";

 END {
     print "*** Now performing program-exit processing ***\n";
 }

DESCRIPTION

The AtExit module provides ANSI-C style exit processing modeled after the atexit() function in the standard C library (see atexit(3C)). Various exit processing routines may be registered by calling atexit() and passing it the desired subroutine along with any desired arguments. Then, at program-exit time, the subroutines registered with atexit() are invoked with their given arguments in the reverse order of registration (last one registered is invoked first). Registering the same subroutine more than once will cause that subroutine to be invoked once for each registration.

The atexit() function exported by AtExit should be passed a subroutine name or reference, optionally followed by the list of arguments with which to invoke it at program-exit time. Anonymous subroutine references passed to atexit() act as "closures" (which are described in perlref). If a subroutine name is specified (as opposed to a subroutine reference) then, unless the subroutine name has an explicit package prefix, it is assumed to be the name of a subroutine in the caller's current package. A reference to the specified subroutine is obtained, and, if invocation arguments were specified, it is "wrapped up" in a closure which invokes the subroutine with the specified arguments. The resulting subroutine reference is prepended to the front of the @AtExit::EXIT_SUBS list of exit-handling subroutines and the reference is then returned to the caller (just in case you might want to unregister it later using rmexit()). If the given subroutine could not be registered, then the value zero is returned.

The rmexit() function exported by AtExit should be passed one or more subroutine references, each of which was returned by a previous call to atexit(). For each argument given, rmexit() will look for it in the @AtExit::EXIT_SUBS list of exit-handling subroutines and remove the first such match from the list. The value returned will be the number of subroutines that were successfully unregistered.

At program-exit time, the END{} block in the AtExit module iterates over the subroutine references in the @AtExit::EXIT_SUBS array and invokes each one in turn (each subroutine is removed from the front of the queue immediately before it is invoked). Note that the subroutines in this queue are invoked in first-to-last order (the reverse order in which they were registered with atexit()).

Invoking atexit() and rmexit() during program-exit

The variable $AtExit::IGNORE_WHEN_EXITING specifies how calls to atexit() will be handled if they occur during the time that subroutines registered with atexit() are being invoked. By default, this variable is set to a non-zero value, which causes atexit() to ignore any calls made to it during this time (a value of zero will be returned). This behavior is consistent with that of the standard C library function of the same name. If desired however, the user may enable the registration of subroutines by atexit() during this time by setting $AtExit::IGNORE_WHEN_EXITING to zero or to the empty string. Just remember that any subroutines registered with atexit() during program-exit time will be placed at the front of the queue of yet-to-be-invoked exit-processing subroutines.

Regardless of when it is invoked, rmexit() will always attempt to unregister the given subroutines (even when called during program-exit processing). Keep in mind however that if it is invoked during program-exit processing then it will fail to unregister any exit-processing subroutines that have already been invoked by the END{} block in the AtExit module (since those subroutine calls have already been removed from the @AtExit::EXIT_SUBS list).

The variable $AtExit::EXITING may be examined to determine if routines registered using atexit() are currently in the process of being invoked. It will be non-zero if they are and zero otherwise.

NOTES

The usual Perl way of doing exit processing is through the use of END{} blocks (see "Package Constructors and Destructors" in perlmod). The AtExit module implements its exit processing with an END{} block that invokes all the subroutines registered by atexit() in the array @AtExit::EXIT_SUBS. If any other END{} block processing is specified in the user's code or in any other packages it uses, then the order in which the exit processing takes place is subject to Perl's rules for the order in which END{} blocks are processed. This may affect when subroutines registered with atexit() are invoked with respect to other exit processing that is to be performed. In particular, if atexit() is invoked from within an END{} block that executes after the END{} block in the AtExit module, then the corresponding subroutine that was registered will never be invoked by the AtExit module's exit-processing code.

END{} block processing order

END{} blocks, including those in other packages, get called in the reverse order in which they appear in the code. (atexit() subroutines get called in the reverse order in which they are registered.) If a package gets read via "use", it will act as if the END{} block was defined at that particular part of the "main" code. Packages read via "require" will be executed after the code of "main" has been parsed and will be seen last so will execute first (they get executed in the context of the package in which they exist).

It is important to note that END{} blocks only get called on normal termination (which includes calls to die() or Carp::croak()). They do not get called when the program terminates abnormally (due to a signal for example) unless special arrangements have been made by the programmer (e.g. using a signal handler -- see "%SIG{expr}" in perlvar).

SEE ALSO

atexit(3C) describes the atexit() function for the standard C library (the actual Unix manual section in which it appears may differ from platform to platform - try sections 3C, 3, 2C, and 2). Further information on anonymous subroutines ("closures") may be found in perlref. For more information on END{} blocks, see "Package Constructors and Destructors" in perlmod. See "%SIG{expr}" in perlvar for handling abnormal program termination.

AUTHOR

Andrew Langmead <aml@world.std.com> (initial draft).

Brad Appleton <Brad_Appleton-GBDA001@email.mot.com> (final version).