Movatterモバイル変換


[0]ホーム

URL:


Jump to content
WikipediaThe Free Encyclopedia
Search

setjmp.h

From Wikipedia, the free encyclopedia
(Redirected fromSetjmp)
Header file for C programs
This articleneeds additional citations forverification. Please helpimprove this article byadding citations to reliable sources. Unsourced material may be challenged and removed.
Find sources: "Setjmp.h" – news ·newspapers ·books ·scholar ·JSTOR
(December 2016) (Learn how and when to remove this message)
C standard library (libc)
General topics
Miscellaneous headers

setjmp.h is aheader defined in theC standard library to provide "non-local jumps":control flow that deviates from the usualsubroutine call and return sequence. The complementary functionssetjmp andlongjmp provide this functionality.

A typical use ofsetjmp/longjmp is implementation of anexception mechanism that exploits the ability oflongjmp to reestablish program or thread state, even across multiple levels of function calls. A less common use ofsetjmp is to create syntax similar tocoroutines.

Member functions

[edit]
intsetjmp(jmp_bufenv)
Sets up the localjmp_buf buffer and initializes it for the jump. This routine[1] saves the program's calling environment in the environment buffer specified by theenv argument for later use bylongjmp. If the return is from a direct invocation,setjmp returns 0. If the return is from a call tolongjmp,setjmp returns a nonzero value.
voidlongjmp(jmp_bufenv,intvalue)
Restores the context of the environment bufferenv that was saved by invocation of thesetjmp routine[1] in the same invocation of the program. Invokinglongjmp from a nested signal handler isundefined. The value specified byvalue is passed fromlongjmp tosetjmp. Afterlongjmp is completed, program execution continues as if the corresponding invocation ofsetjmp had just returned. If thevalue passed tolongjmp is 0,setjmp will behave as if it had returned 1; otherwise, it will behave as if it had returnedvalue.

setjmp saves the current environment (the program state), at some point of program execution, into a platform-specific data structure (jmp_buf) that can be used at some later point of program execution bylongjmp to restore the program state to that saved bysetjmp intojmp_buf. This process can be imagined to be a "jump" back to the point of program execution wheresetjmp saved the environment. The (apparent)return value fromsetjmp indicates whether control reached that point normally (zero) or from a call tolongjmp (nonzero). This leads to a commonidiom:if(setjmp(x)){/* handle longjmp(x) */}.

POSIX.1 does not specify whethersetjmp andlongjmp save and restore the current set of blockedsignals; if a program employs signal handling it should use POSIX'ssigsetjmp/siglongjmp.

Member types

[edit]
jmp_bufAn array type suitable for holding the information needed to restore a calling environment.

The C99 Rationale describesjmp_buf as being an array type forbackward compatibility; existing code refers tojmp_buf storage locations by name (without the& address-of operator), which is only possible for array types.[2] It notes that it can simply be a one-member-long array with its single member being the actual data; indeed, this is the approach employed by theGNU C library, which defines the type asstruct __jmp_buf_tag[1].

Caveats and limitations

[edit]

When a "non-local goto" is executed viasetjmp/longjmp inC++, normal "stack unwinding" does not occur. Therefore, any required cleanup actions will not occur either. This could include closingfile descriptors, flushingbuffers, or freeingheap-allocated memory.

If the function in whichsetjmp was called returns, it is no longer possible to safely uselongjmp with the correspondingjmp_buf object. This is because thestack frame is invalidated when the function returns. Callinglongjmp restores thestack pointer, which—because the function returned—would point to a non-existent and potentially overwritten or corrupted stack frame.[3][4]

Similarly,C99 does not require thatlongjmp preserve the current stack frame. This means that jumping into a function which was exited via a call tolongjmp is undefined.[5]

Example usage

[edit]

Simple example

[edit]

The example below shows the basic idea of setjmp. There,main() callsfirst(), which in turn callssecond(). Then,second() jumps back intomain(), skippingfirst()'s call ofprintf().

#include<stdio.h>#include<setjmp.h>staticjmp_bufbuf;voidsecond(){printf("second\n");// printslongjmp(buf,1);// jumps back to where setjmp was called - making setjmp now return 1}voidfirst(){second();printf("first\n");// does not print}intmain(){if(!setjmp(buf))first();// when executed, setjmp returned 0else// when longjmp jumps back, setjmp returns 1printf("main\n");// printsreturn0;}

When executed, the above program will output:

secondmain

Notice that although thefirst() subroutine gets called, "first" is never printed, assecond() never returns control tofirst(). Instead, "main" is printed when the conditional statementif (!setjmp(buf)) is checked a second time.

Exception handling

[edit]

In this example,setjmp is used to bracket exception handling, liketry in some other languages. The call tolongjmp is analogous to athrow statement, allowing an exception to return an error status directly to thesetjmp. The following code adheres to the1999 ISO C standard andSingle UNIX Specification by invokingsetjmp in a limited range of contexts:[6]

  • As the condition to anif,switch or iteration statement
  • As above in conjunction with a single! or comparison with an integer constant
  • As a statement (with the return value unused)

Following these rules can make it easier for the implementation to create the environment buffer, which can be a sensitive operation.[2] More general use ofsetjmp can cause undefined behaviour, such as corruption of local variables; conforming compilers and environments are not required to protect or even warn against such usage. However, slightly more sophisticated idioms such asswitch ((exception_type = setjmp(env))) { } are common in literature and practice, and remain relatively portable. A simple conforming methodology is presented below, where an additional variable is maintained along with the state buffer. This variable could be elaborated into a structure incorporating the buffer itself.

In a more modern-looking example, the usual "try" block would be implemented as a setjmp (with some preparation code for multilevel jumps, as seen infirst), the "throw" as longjmp with the optional parameter as the exception, and the "catch" as the "else" block under "try".

#include<setjmp.h>#include<stdio.h>#include<stdlib.h>#include<string.h>staticvoidfirst();staticvoidsecond();/* Use a file scoped static variable for the exception stack so we can access * it anywhere within this translation unit. */staticjmp_bufexception_env;staticintexception_type;intmain(void){char*volatilemem_buffer=NULL;if(setjmp(exception_env)){// if we get here there was an exceptionprintf("first failed, exception type: %d\n",exception_type);}else{// Run code that may signal failure via longjmp.puts("calling first");first();mem_buffer=malloc(300);// allocate a resourceprintf("%s\n",strcpy(mem_buffer,"first succeeded"));// not reached}free(mem_buffer);// NULL can be passed to free, no operation is performedreturn0;}staticvoidfirst(){jmp_bufmy_env;puts("entering first");// reachedmemcpy(my_env,exception_env,sizeofmy_env);// store value of exception_env in my_env since exception_env will be reusedswitch(setjmp(exception_env)){case3:// if we get here there was an exception.puts("second failed, exception type: 3; remapping to type 1");exception_type=1;default:// fall throughmemcpy(exception_env,my_env,sizeofexception_env);// restore exception stacklongjmp(exception_env,exception_type);// continue handling the exceptioncase0:// normal, desired operationputs("calling second");// reachedsecond();puts("second succeeded");// not reached}memcpy(exception_env,my_env,sizeofexception_env);// restore exception stackputs("leaving first");// never reached}staticvoidsecond(){puts("entering second");// reachedexception_type=3;longjmp(exception_env,exception_type);// declare that the program has failedputs("leaving second");// not reached}

This program's output is:

calling firstentering firstcalling secondentering secondsecond failed, exception type: 3; remapping to type 1first failed, exception type: 1

Cooperative multitasking

[edit]

C99 provides thatlongjmp is guaranteed to work only when the destination is a calling function, i.e., that the destination scope is guaranteed to be intact. Jumping to a function that has already terminated byreturn orlongjmp is undefined.[5] However, most implementations oflongjmp do not specifically destroy local variables when performing the jump. Since the context survives until its local variables are erased, it could actually be restored bysetjmp. In many environments (such asReally Simple Threads andTinyTimbers), idioms such asif(!setjmp(child_env)) longjmp(caller_env); can allow a called function to effectively pause-and-resume at asetjmp.

This is exploited by thread libraries to providecooperative multitasking facilities without usingsetcontext or otherfiber facilities.

Considering thatsetjmp to a child function will generally work unless sabotaged, andsetcontext, as part of POSIX, is not required to be provided by C implementations, this mechanism may be portable where thesetcontext alternative fails.

Since no exception will be generated upon overflow of one of the multiple stacks in such a mechanism, it is essential to overestimate the space required for each context, including the one containingmain() and including space for any signal handlers that might interrupt regular execution. Exceeding the allocated space will corrupt the other contexts, usually with the outermost functions first. Unfortunately, systems requiring this kind of programming strategy are often also small ones with limited resources.

#include<setjmp.h>#include<stdio.h>jmp_bufmainTask,childTask;voidcall_with_cushion();voidchild();intmain(){if(!setjmp(mainTask)){call_with_cushion();// child never returns, yield}// execution resumes after this "}" after first time that child yieldswhile(1){printf("Parent\n");if(!setjmp(mainTask))longjmp(childTask,1);// yield - note that this is undefined under C99}}voidcall_with_cushion(){charspace[1000];// Reserve enough space for main to runspace[999]=1;// Do not optimize array out of existencechild();}voidchild(){while(1){printf("Child loop begin\n");if(!setjmp(childTask))longjmp(mainTask,1);// yield - invalidates childTask in C99printf("Child loop end\n");if(!setjmp(childTask))longjmp(mainTask,1);// yield - invalidates childTask in C99}/* Don't return. Instead we should set a flag to indicate that main()       should stop yielding to us and then longjmp(mainTask, 1) */}

References

[edit]
  1. ^abISO C states thatsetjmp must be implemented as a macro, but POSIX explicitly states that it is undefined whethersetjmp is a macro or a function.
  2. ^abC99 Rationale, version 5.10, April 2003, section 7.13
  3. ^CS360 Lecture Notes — Setjmp and Longjmp
  4. ^setjmp(3)Archived 2009-07-26 at theWayback Machine
  5. ^abISO/IEC 9899:1999, 2005, 7.13.2.1:2 and footnote 211
  6. ^setjmp: set jump point for a non-local goto – System Interfaces Reference,The Single UNIX Specification, Version 4 fromThe Open Group

Further reading

[edit]

External links

[edit]
Retrieved from "https://en.wikipedia.org/w/index.php?title=Setjmp.h&oldid=1248348304"
Categories:
Hidden categories:

[8]ページ先頭

©2009-2025 Movatter.jp