449 lines
19 KiB
Plaintext
449 lines
19 KiB
Plaintext
@node Non-Local Exits, Signal Handling, Resource Usage And Limitation, Top
|
|
@c %MENU% Jumping out of nested function calls
|
|
@chapter Non-Local Exits
|
|
@cindex non-local exits
|
|
@cindex long jumps
|
|
|
|
Sometimes when your program detects an unusual situation inside a deeply
|
|
nested set of function calls, you would like to be able to immediately
|
|
return to an outer level of control. This section describes how you can
|
|
do such @dfn{non-local exits} using the @code{setjmp} and @code{longjmp}
|
|
functions.
|
|
|
|
@menu
|
|
* Intro: Non-Local Intro. When and how to use these facilities.
|
|
* Details: Non-Local Details. Functions for non-local exits.
|
|
* Non-Local Exits and Signals:: Portability issues.
|
|
* System V contexts:: Complete context control a la System V.
|
|
@end menu
|
|
|
|
@node Non-Local Intro, Non-Local Details, , Non-Local Exits
|
|
@section Introduction to Non-Local Exits
|
|
|
|
As an example of a situation where a non-local exit can be useful,
|
|
suppose you have an interactive program that has a ``main loop'' that
|
|
prompts for and executes commands. Suppose the ``read'' command reads
|
|
input from a file, doing some lexical analysis and parsing of the input
|
|
while processing it. If a low-level input error is detected, it would
|
|
be useful to be able to return immediately to the ``main loop'' instead
|
|
of having to make each of the lexical analysis, parsing, and processing
|
|
phases all have to explicitly deal with error situations initially
|
|
detected by nested calls.
|
|
|
|
(On the other hand, if each of these phases has to do a substantial
|
|
amount of cleanup when it exits---such as closing files, deallocating
|
|
buffers or other data structures, and the like---then it can be more
|
|
appropriate to do a normal return and have each phase do its own
|
|
cleanup, because a non-local exit would bypass the intervening phases and
|
|
their associated cleanup code entirely. Alternatively, you could use a
|
|
non-local exit but do the cleanup explicitly either before or after
|
|
returning to the ``main loop''.)
|
|
|
|
In some ways, a non-local exit is similar to using the @samp{return}
|
|
statement to return from a function. But while @samp{return} abandons
|
|
only a single function call, transferring control back to the point at
|
|
which it was called, a non-local exit can potentially abandon many
|
|
levels of nested function calls.
|
|
|
|
You identify return points for non-local exits by calling the function
|
|
@code{setjmp}. This function saves information about the execution
|
|
environment in which the call to @code{setjmp} appears in an object of
|
|
type @code{jmp_buf}. Execution of the program continues normally after
|
|
the call to @code{setjmp}, but if an exit is later made to this return
|
|
point by calling @code{longjmp} with the corresponding @w{@code{jmp_buf}}
|
|
object, control is transferred back to the point where @code{setjmp} was
|
|
called. The return value from @code{setjmp} is used to distinguish
|
|
between an ordinary return and a return made by a call to
|
|
@code{longjmp}, so calls to @code{setjmp} usually appear in an @samp{if}
|
|
statement.
|
|
|
|
Here is how the example program described above might be set up:
|
|
|
|
@smallexample
|
|
@include setjmp.c.texi
|
|
@end smallexample
|
|
|
|
The function @code{abort_to_main_loop} causes an immediate transfer of
|
|
control back to the main loop of the program, no matter where it is
|
|
called from.
|
|
|
|
The flow of control inside the @code{main} function may appear a little
|
|
mysterious at first, but it is actually a common idiom with
|
|
@code{setjmp}. A normal call to @code{setjmp} returns zero, so the
|
|
``else'' clause of the conditional is executed. If
|
|
@code{abort_to_main_loop} is called somewhere within the execution of
|
|
@code{do_command}, then it actually appears as if the @emph{same} call
|
|
to @code{setjmp} in @code{main} were returning a second time with a value
|
|
of @code{-1}.
|
|
|
|
@need 250
|
|
So, the general pattern for using @code{setjmp} looks something like:
|
|
|
|
@smallexample
|
|
if (setjmp (@var{buffer}))
|
|
/* @r{Code to clean up after premature return.} */
|
|
@dots{}
|
|
else
|
|
/* @r{Code to be executed normally after setting up the return point.} */
|
|
@dots{}
|
|
@end smallexample
|
|
|
|
@node Non-Local Details, Non-Local Exits and Signals, Non-Local Intro, Non-Local Exits
|
|
@section Details of Non-Local Exits
|
|
|
|
Here are the details on the functions and data structures used for
|
|
performing non-local exits. These facilities are declared in
|
|
@file{setjmp.h}.
|
|
@pindex setjmp.h
|
|
|
|
@comment setjmp.h
|
|
@comment ISO
|
|
@deftp {Data Type} jmp_buf
|
|
Objects of type @code{jmp_buf} hold the state information to
|
|
be restored by a non-local exit. The contents of a @code{jmp_buf}
|
|
identify a specific place to return to.
|
|
@end deftp
|
|
|
|
@comment setjmp.h
|
|
@comment ISO
|
|
@deftypefn Macro int setjmp (jmp_buf @var{state})
|
|
When called normally, @code{setjmp} stores information about the
|
|
execution state of the program in @var{state} and returns zero. If
|
|
@code{longjmp} is later used to perform a non-local exit to this
|
|
@var{state}, @code{setjmp} returns a nonzero value.
|
|
@end deftypefn
|
|
|
|
@comment setjmp.h
|
|
@comment ISO
|
|
@deftypefun void longjmp (jmp_buf @var{state}, int @var{value})
|
|
This function restores current execution to the state saved in
|
|
@var{state}, and continues execution from the call to @code{setjmp} that
|
|
established that return point. Returning from @code{setjmp} by means of
|
|
@code{longjmp} returns the @var{value} argument that was passed to
|
|
@code{longjmp}, rather than @code{0}. (But if @var{value} is given as
|
|
@code{0}, @code{setjmp} returns @code{1}).@refill
|
|
@end deftypefun
|
|
|
|
There are a lot of obscure but important restrictions on the use of
|
|
@code{setjmp} and @code{longjmp}. Most of these restrictions are
|
|
present because non-local exits require a fair amount of magic on the
|
|
part of the C compiler and can interact with other parts of the language
|
|
in strange ways.
|
|
|
|
The @code{setjmp} function is actually a macro without an actual
|
|
function definition, so you shouldn't try to @samp{#undef} it or take
|
|
its address. In addition, calls to @code{setjmp} are safe in only the
|
|
following contexts:
|
|
|
|
@itemize @bullet
|
|
@item
|
|
As the test expression of a selection or iteration
|
|
statement (such as @samp{if}, @samp{switch}, or @samp{while}).
|
|
|
|
@item
|
|
As one operand of a equality or comparison operator that appears as the
|
|
test expression of a selection or iteration statement. The other
|
|
operand must be an integer constant expression.
|
|
|
|
@item
|
|
As the operand of a unary @samp{!} operator, that appears as the
|
|
test expression of a selection or iteration statement.
|
|
|
|
@item
|
|
By itself as an expression statement.
|
|
@end itemize
|
|
|
|
Return points are valid only during the dynamic extent of the function
|
|
that called @code{setjmp} to establish them. If you @code{longjmp} to
|
|
a return point that was established in a function that has already
|
|
returned, unpredictable and disastrous things are likely to happen.
|
|
|
|
You should use a nonzero @var{value} argument to @code{longjmp}. While
|
|
@code{longjmp} refuses to pass back a zero argument as the return value
|
|
from @code{setjmp}, this is intended as a safety net against accidental
|
|
misuse and is not really good programming style.
|
|
|
|
When you perform a non-local exit, accessible objects generally retain
|
|
whatever values they had at the time @code{longjmp} was called. The
|
|
exception is that the values of automatic variables local to the
|
|
function containing the @code{setjmp} call that have been changed since
|
|
the call to @code{setjmp} are indeterminate, unless you have declared
|
|
them @code{volatile}.
|
|
|
|
@node Non-Local Exits and Signals, System V contexts, Non-Local Details, Non-Local Exits
|
|
@section Non-Local Exits and Signals
|
|
|
|
In BSD Unix systems, @code{setjmp} and @code{longjmp} also save and
|
|
restore the set of blocked signals; see @ref{Blocking Signals}. However,
|
|
the POSIX.1 standard requires @code{setjmp} and @code{longjmp} not to
|
|
change the set of blocked signals, and provides an additional pair of
|
|
functions (@code{sigsetjmp} and @code{siglongjmp}) to get the BSD
|
|
behavior.
|
|
|
|
The behavior of @code{setjmp} and @code{longjmp} in the GNU library is
|
|
controlled by feature test macros; see @ref{Feature Test Macros}. The
|
|
default in the GNU system is the POSIX.1 behavior rather than the BSD
|
|
behavior.
|
|
|
|
The facilities in this section are declared in the header file
|
|
@file{setjmp.h}.
|
|
@pindex setjmp.h
|
|
|
|
@comment setjmp.h
|
|
@comment POSIX.1
|
|
@deftp {Data Type} sigjmp_buf
|
|
This is similar to @code{jmp_buf}, except that it can also store state
|
|
information about the set of blocked signals.
|
|
@end deftp
|
|
|
|
@comment setjmp.h
|
|
@comment POSIX.1
|
|
@deftypefun int sigsetjmp (sigjmp_buf @var{state}, int @var{savesigs})
|
|
This is similar to @code{setjmp}. If @var{savesigs} is nonzero, the set
|
|
of blocked signals is saved in @var{state} and will be restored if a
|
|
@code{siglongjmp} is later performed with this @var{state}.
|
|
@end deftypefun
|
|
|
|
@comment setjmp.h
|
|
@comment POSIX.1
|
|
@deftypefun void siglongjmp (sigjmp_buf @var{state}, int @var{value})
|
|
This is similar to @code{longjmp} except for the type of its @var{state}
|
|
argument. If the @code{sigsetjmp} call that set this @var{state} used a
|
|
nonzero @var{savesigs} flag, @code{siglongjmp} also restores the set of
|
|
blocked signals.
|
|
@end deftypefun
|
|
|
|
@node System V contexts,, Non-Local Exits and Signals, Non-Local Exits
|
|
@section Complete Context Control
|
|
|
|
The Unix standard one more set of function to control the execution path
|
|
and these functions are more powerful than those discussed in this
|
|
chapter so far. These function were part of the original @w{System V}
|
|
API and by this route were added to the Unix API. Beside on branded
|
|
Unix implementations these interfaces are not widely available. Not all
|
|
platforms and/or architectures the GNU C Library is available on provide
|
|
this interface. Use @file{configure} to detect the availability.
|
|
|
|
Similar to the @code{jmp_buf} and @code{sigjmp_buf} types used for the
|
|
variables to contain the state of the @code{longjmp} functions the
|
|
interfaces of interest here have an appropriate type as well. Objects
|
|
of this type are normally much larger since more information is
|
|
contained. The type is also used in a few more places as we will see.
|
|
The types and functions described in this section are all defined and
|
|
declared respectively in the @file{ucontext.h} header file.
|
|
|
|
@comment ucontext.h
|
|
@comment SVID
|
|
@deftp {Data Type} ucontext_t
|
|
|
|
The @code{ucontext_t} type is defined as a structure with as least the
|
|
following elements:
|
|
|
|
@table @code
|
|
@item ucontext_t *uc_link
|
|
This is a pointer to the next context structure which is used if the
|
|
context described in the current structure returns.
|
|
|
|
@item sigset_t uc_sigmask
|
|
Set of signals which are blocked when this context is used.
|
|
|
|
@item stack_t uc_stack
|
|
Stack used for this context. The value need not be (and normally is
|
|
not) the stack pointer. @xref{Signal Stack}.
|
|
|
|
@item mcontext_t uc_mcontext
|
|
This element contains the actual state of the process. The
|
|
@code{mcontext_t} type is also defined in this header but the definition
|
|
should be treated as opaque. Any use of knowledge of the type makes
|
|
applications less portable.
|
|
|
|
@end table
|
|
@end deftp
|
|
|
|
Objects of this type have to be created by the user. The initialization
|
|
and modification happens through one of the following functions:
|
|
|
|
@comment ucontext.h
|
|
@comment SVID
|
|
@deftypefun int getcontext (ucontext_t *@var{ucp})
|
|
The @code{getcontext} function initializes the variable pointed to by
|
|
@var{ucp} with the context of the calling thread. The context contains
|
|
the content of the registers, the signal mask, and the current stack.
|
|
Executing the contents would start at the point where the
|
|
@code{getcontext} call just returned.
|
|
|
|
The function returns @code{0} if successful. Otherwise it returns
|
|
@code{-1} and sets @var{errno} accordingly.
|
|
@end deftypefun
|
|
|
|
The @code{getcontext} function is similar to @code{setjmp} but it does
|
|
not provide an indication of whether the function returns for the first
|
|
time or whether the initialized context was used and the execution is
|
|
resumed at just that point. If this is necessary the user has to take
|
|
determine this herself. This must be done carefully since the context
|
|
contains registers which might contain register variables. This is a
|
|
good situation to define variables with @code{volatile}.
|
|
|
|
Once the context variable is initialized it can be used as is or it can
|
|
be modified. The latter is normally done to implement co-routines or
|
|
similar constructs. The @code{makecontext} function is what has to be
|
|
used to do that.
|
|
|
|
@comment ucontext.h
|
|
@comment SVID
|
|
@deftypefun void makecontext (ucontext_t *@var{ucp}, void (*@var{func}) (void), int @var{argc}, @dots{})
|
|
|
|
The @var{ucp} parameter passed to the @code{makecontext} shall be
|
|
initialized by a call to @code{getcontext}. The context will be
|
|
modified to in a way so that if the context is resumed it will start by
|
|
calling the function @code{func} which gets @var{argc} integer arguments
|
|
passed. The integer arguments which are to be passed should follow the
|
|
@var{argc} parameter in the call to @code{makecontext}.
|
|
|
|
Before the call to this function the @code{uc_stack} and @code{uc_link}
|
|
element of the @var{ucp} structure should be initialized. The
|
|
@code{uc_stack} element describes the stack which is used for this
|
|
context. No two contexts which are used at the same time should use the
|
|
same memory region for a stack.
|
|
|
|
The @code{uc_link} element of the object pointed to by @var{ucp} should
|
|
be a pointer to the context to be executed when the function @var{func}
|
|
returns or it should be a null pointer. See @code{setcontext} for more
|
|
information about the exact use.
|
|
@end deftypefun
|
|
|
|
While allocating the memory for the stack one has to be careful. Most
|
|
modern processors keep track of whether a certain memory region is
|
|
allowed to contain code which is executed or not. Data segments and
|
|
heap memory is normally not tagged to allow this. The result is that
|
|
programs would fail. Examples for such code include the calling
|
|
sequences the GNU C compiler generates for calls to nested functions.
|
|
Safe ways to allocate stacks correctly include using memory on the
|
|
original threads stack or explicitly allocate memory tagged for
|
|
execution using (@pxref{Memory-mapped I/O}).
|
|
|
|
@strong{Compatibility note}: The current Unix standard is very imprecise
|
|
about the way the stack is allocated. All implementations seem to agree
|
|
that the @code{uc_stack} element must be used but the values stored in
|
|
the elements of the @code{stack_t} value are unclear. The GNU C library
|
|
and most other Unix implementations require the @code{ss_sp} value of
|
|
the @code{uc_stack} element to point to the base of the memory region
|
|
allocated for the stack and the size of the memory region is stored in
|
|
@code{ss_size}. There are implements out there which require
|
|
@code{ss_sp} to be set to the value the stack pointer will have (which
|
|
can depending on the direction the stack grows be different). This
|
|
difference makes the @code{makecontext} function hard to use and it
|
|
requires detection of the platform at compile time.
|
|
|
|
@comment ucontext.h
|
|
@comment SVID
|
|
@deftypefun int setcontext (const ucontext_t *@var{ucp})
|
|
|
|
The @code{setcontext} function restores the context described by
|
|
@var{ucp}. The context is not modified and can be reused as often as
|
|
wanted.
|
|
|
|
If the context was created by @code{getcontext} execution resumes with
|
|
the registers filled with the same values and the same stack as if the
|
|
@code{getcontext} call just returned.
|
|
|
|
If the context was modified with a call to @code{makecontext} execution
|
|
continues with the function passed to @code{makecontext} which gets the
|
|
specified parameters passed. If this function returns execution is
|
|
resumed in the context which was referenced by the @code{uc_link}
|
|
element of the context structure passed to @code{makecontext} at the
|
|
time of the call. If @code{uc_link} was a null pointer the application
|
|
terminates in this case.
|
|
|
|
Since the context contains information about the stack no two threads
|
|
should use the same context at the same time. The result in most cases
|
|
would be disastrous.
|
|
|
|
The @code{setcontext} function does not return unless an error occurred
|
|
in which case it returns @code{-1}.
|
|
@end deftypefun
|
|
|
|
The @code{setcontext} function simply replaces the current context with
|
|
the one described by the @var{ucp} parameter. This is often useful but
|
|
there are situations where the current context has to be preserved.
|
|
|
|
@comment ucontext.h
|
|
@comment SVID
|
|
@deftypefun int swapcontext (ucontext_t *restrict @var{oucp}, const ucontext_t *restrict @var{ucp})
|
|
|
|
The @code{swapcontext} function is similar to @code{setcontext} but
|
|
instead of just replacing the current context the latter is first saved
|
|
in the object pointed to by @var{oucp} as if this was a call to
|
|
@code{getcontext}. The saved context would resume after the call to
|
|
@code{swapcontext}.
|
|
|
|
Once the current context is saved the context described in @var{ucp} is
|
|
installed and execution continues as described in this context.
|
|
|
|
If @code{swapcontext} succeeds the function does not return unless the
|
|
context @var{oucp} is used without prior modification by
|
|
@code{makecontext}. The return value in this case is @code{0}. If the
|
|
function fails it returns @code{-1} and set @var{errno} accordingly.
|
|
@end deftypefun
|
|
|
|
@heading Example for SVID Context Handling
|
|
|
|
The easiest way to use the context handling functions is as a
|
|
replacement for @code{setjmp} and @code{longjmp}. The context contains
|
|
on most platforms more information which might lead to less surprises
|
|
but this also means using these functions is more expensive (beside
|
|
being less portable).
|
|
|
|
@smallexample
|
|
int
|
|
random_search (int n, int (*fp) (int, ucontext_t *))
|
|
@{
|
|
volatile int cnt = 0;
|
|
ucontext_t uc;
|
|
|
|
/* @r{Safe current context.} */
|
|
if (getcontext (&uc) < 0)
|
|
return -1;
|
|
|
|
/* @r{If we have not tried @var{n} times try again.} */
|
|
if (cnt++ < n)
|
|
/* @r{Call the function with a new random number}
|
|
@r{and the context}. */
|
|
if (fp (rand (), &uc) != 0)
|
|
/* @r{We found what we were looking for.} */
|
|
return 1;
|
|
|
|
/* @r{Not found.} */
|
|
return 0;
|
|
@}
|
|
@end smallexample
|
|
|
|
Using contexts in such a way enables emulating exception handling. The
|
|
search functions passed in the @var{fp} parameter could be very large,
|
|
nested, and complex which would make it complicated (or at least would
|
|
require a lot of code) to leave the function with an error value which
|
|
has to be passed down to the caller. By using the context it is
|
|
possible to leave the search function in one step and allow restarting
|
|
the search which also has the nice side effect that it can be
|
|
significantly faster.
|
|
|
|
Something which is harder to implement with @code{setjmp} and
|
|
@code{longjmp} is to switch temporarily to a different execution path
|
|
and then resume where execution was stopped.
|
|
|
|
@smallexample
|
|
@include swapcontext.c.texi
|
|
@end smallexample
|
|
|
|
This an example how the context functions can be used to implement
|
|
co-routines or cooperative multi-threading. All that has to be done is
|
|
to call every once in a while @code{swapcontext} to continue running a
|
|
different context. It is not allowed to do the context switching from
|
|
the signal handler directly since neither @code{setcontext} nor
|
|
@code{swapcontext} are functions which can be called from a signal
|
|
handler. But setting a variable in the signal handler and checking it
|
|
in the body of the functions which are executed. Since
|
|
@code{swapcontext} is saving the current context it is possible to have
|
|
multiple different scheduling points in the code. Execution will always
|
|
resume where it was left.
|