Intercept Nonlocal gotos
Portability: |
SAS/C extension
|
#include <lcjmp.h>
int blkjmp(jmp_buf env);
blkjmp
requests interception of calls to
longjmp
that could terminate the calling function. When you call
blkjmp
, it always returns 0. If a call to
longjmp
is later intercepted, the call to
blkjmp
is resumed and it then returns the integer argument that was
passed to
longjmp
. The
env
variable is modified to indicate the target of the intercepted
longjmp
so that it can be reissued by the intercepting
routine.
After a call to
longjmp
is intercepted,
blkjmp
must be
reissued if continued interception is wanted.
Because
exit
is implemented
as a
longjmp
to the caller of
main
, you can use
blkjmp
to intercept
program exit.
The sigsetjmp
and siglongjmp
functions, introduced in SAS/C Release 6.00, allow
the signal mask to be saved as part of a setjmp
operation, and restored as part of a longjmp
operation. In the 6.00 implementation, siglongjmp
restored the signal mask before searching the stack for blkjmp
callers.
This meant that the old signal mask was restored before
any caller of blkjmp
received control to intercept
the jump. Since in most cases the restored signal mask allows more signals
than the old signal mask, this had the effect of allowing a signal to be discovered
in a blkjmp
cleanup routine, thereby causing
part of the cleanup to be bypassed.
The 6.50 version of the library modifies siglongjmp
so that the signal mask is changed as late as
possible.
If there is no interference from blkjmp
callers,
the signal mask is changed immediately before control is returned to the target sigsetjmp
call.
As with the 6.00 library, if a call to
siglongjmp
is intercepted by blkjmp
,
the signal mask is restored immediately before control is returned to the blkjmp
call.
Additionally, a new function called
sigblkjmp
has been defined. This function is an enhanced version
of blkjmp
, which stores the signal mask data
associated with a siglongjmp
in the buffer
passed to sigblkjmp
as well as the registers
and other environmental information.
This means that the signal mask is not changed when
control is given to a sigblkjmp
cleanup routine.
The mask is only changed when control passes to the original sigsetjmp
call, or to a caller of the old blkjmp
function.
Use of sigblkjmp
rather
than blkjmp
is recommended in any program which
uses sigsetjmp
and siglongjmp
.
Note:
Both blkjmp
and sigblkjmp
are compatible with both the setjmp
and longjmp
functions
as well as with their sig-
versions.
When an application contains functions which execute
in access register (AR) mode, the size of the jmp_buf
used by the setjmp
, longjmp
, and blkjmp
functions increases
due to the need to save the access registers in a call to setjmp
and restore them in a call to longjmp
. If a function is compiled with the
armode
option, when the header file is included, logic within the
header file generates an appropriate definition of the jmp_buf
type.
Some applications may require a mixture of AR-mode and
non-AR-mode functions. These programs require special care to avoid incompatible
definitions. For example, a situation could occur where an external jmp_buf
variable seems to be different sizes in different
compilations. Also, if a function that is not compiled to run in AR mode intercepts
a longjmp
made by a caller in AR mode, the
access register information can be lost or garbled, resulting in errors when
the longjmp
completes.
To prevent problems such as these, functions that use setjmp
,
longjmp
, or blkjmp
, and that may be combined with AR-mode functions, should
include the header file . This header file defines the jmp_buf
type and the longjmp
family
of functions in a way that will behave correctly whether or not the called
function is compiled with AR mode. It can also be included in a program that
does not use AR mode, although extra overhead will be introduced due to the
need to maintain access register information.
Note:
<arjump.h>
should be included only in an SPE application.
blkjmp
normally returns 0; it returns a non-zero value if a call to
longjmp
has been intercepted (in which case,
blkjmp
returns the value of the second argument passed to
longjmp
).
Variables of storage class
auto
and
register
whose values are
changed between the
blkjmp
and
longjmp
calls have indeterminate values on return to
blkjmp
.
This example demonstrates how
blkjmp
can be used to enable a function to release resources, even
if terminated by a call to
longjmp
in a
function it calls:
#include <stdio.h>
#include <lcjmp.h>
#include <stdlib.h>
jmp_buf env;
static void get_resource(void), use_resource(void);
int main()
{
int code;
if (code = setjmp(env)) goto escape;
get_resource();
puts("get_resource returned normally.");
exit(0);
escape:
printf("Executing escape routine for error %d\n", code);
exit(code);
}
static void get_resource(void)
{
int code;
jmp_buf my_env;
/* Allocate resource here. */
if (code = blkjmp(my_env)) goto release;
puts("Resources allocated.");
/* Free resource here. */
use_resource();
puts("use_resource returned normally, "
"get_resource is freeing resources.");
return;
/* Free resource here. */
release:
printf("use_resource indicated error %d\n", code);
puts("Resources now freed, proceeding with longjmp.");
longjmp(my_env, code);
}
static void use_resource(void)
{
puts("Entering use_resource");
/* Attempt to use resource here. */
puts("Error 3 detected, calling longjmp.");
longjmp(env, 3);
puts("This statement will not be executed.");
}
longjmp
,
setjmp
,
siglongjmp
,
sigsetjmp
Copyright © 2001
by SAS Institute Inc., Cary, NC, USA. All rights reserved.