diff options
Diffstat (limited to 'libc/manual/setjmp.texi')
-rw-r--r-- | libc/manual/setjmp.texi | 448 |
1 files changed, 448 insertions, 0 deletions
diff --git a/libc/manual/setjmp.texi b/libc/manual/setjmp.texi new file mode 100644 index 000000000..0cf8b8490 --- /dev/null +++ b/libc/manual/setjmp.texi @@ -0,0 +1,448 @@ +@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. |