nazgul@apollo.uucp (Kee Hinckley) (09/28/84)
<-> Setjump stores the current state of the stack and any relevant registers and hands them back to the program to hang onto. At some later date the program can then call longjmp and everything will return to the state of the machine at the time of the setjump. Essentially it is just a way of implementing a non-local goto. For example: char[8] buf; /* Also sometimes known as type: jmp_buf */ foo() { /* * Save state (when we return it will be as * though we had just returned from the setjmp * function. */ setjmp(buf); bar(); ... } bar() { ... longjmp(buf); /* Jump back into foo */ /* Nothing after this get's executed */ } Note that the size of the buffer is going to be implementation dependent (since different compilers are going to require different amounts of state information) but generally it is on the order of a few bytes. Since (at least on the Apple in Aztec C) all you have to store are the stack pointers, the return vector, and a few other pieces of state. When you restore all of these the rest of the stack gets thrown away and you're right back where you started from. One other thing, you can do a longjmp BACK to a setjmp, but doing one forward probably won't work (eg. if you returned from "foo" in the above example, and THEN tried to do a longjmp you would have to be very lucky to have it work. Actually, this is probably all a horrible explanation, does someone at Brown have a graphical demo using Pecan or one of their other trees? -kee
moss@BRL-VLD.ARPA (10/01/84)
From: "Gary S. Moss (AMXBR-VLD-V)" <moss@BRL-VLD.ARPA> Do not use char buf[8] as the storage area for setjmp(). The portable way is to use the typedef jmp_buf from <setjmp.h>. This is defined in Doug Gwyn's System V emulation as follows; /* @(#)setjmp.h 1.3 */ #ifndef _JBLEN #if vax || u3b5 #define _JBLEN 10 #endif #if pdp11 #define _JBLEN 4 /* DAG -- one larger for overlays */ #endif #if u370 #define _JBLEN 4 #endif #if u3b #define _JBLEN 11 #endif typedef int jmp_buf[_JBLEN]; extern int setjmp(); extern void longjmp(); #endif The size of the buffer differs with machine and version of UNIX and the whim of whoever modifies the compiler, so USE THE TYPEDEF BY INCLUDING SETJMP.H!!! I got bit by this one because I defined it as int buf[3] rather than including <setjmp.h>. Since my buffer was one integer short, I stomped on an integer variable when I called setjmp(), and Boy was that a tough bug to track down. -- Moss. PS, I know this was not your question.
bwf@ihldt.UUCP (Bill Fecht) (10/01/84)
Careful, the setjmp() call saves only a few registers and stack pointers, it does not save the stack. Not understanding this could cause two problems: 1) thinking that a longjmp() will restore automatic variables, i.e. #include <setjmp.h> jmp_buf jb; main() { int x; x = 1; setjmp(jb); if (x == 2) { printf("bailout\n"); exit(); } x = 2; longjmp(jb); } 2) thinking that a longjmp() will restore calling sequence, i.e. jmp_buf jb; foo1() { foo2(); bar(); } foo2() { foo3(); } foo3() { setjmp(jb); } bar() { longjmp(jb); } Also, you should use 'jmp_buf jb', NOT 'char[8] jb' (:-)), 'jmp_buf' will reserve all you need to do the setjmp()/longjmp(). I think setjmp() and longjmp() were included in Unix to recover from convoluted nesting in the event of errors, then were included in C for the user, I think. I know uucp uses the mechanism for this a lot. bill (ihack!bwf) fecht
thomson@uthub.UUCP (Brian Thomson) (10/01/84)
Kee Hinckley almost gets it right: > Setjump stores the current state of the stack and any relevant > registers and hands them back to the program to hang onto. At some > later date the program can then call longjmp and everything will > return to the state of the machine at the time of the setjump. In fact, a correct setjmp/longjmp implementation doesn't just store and restore register contents. Rather, longjmp() should do a 'deep return', restoring registers only if they have been salted away as part of normal program execution. In particular, the program jmp_buf env; main() { register int i; i = 0; if(setjmp(&env)) { printf("%d\n", i); exit(0); } i = 1; longjmp(&env, 1); } should print 1, not 0. Check the manual page -- ours (4.2) says "All accessible data have values as of the time longjmp was called." Note that, with this definition, the behaviour of a variable is independent of whether it was declared "register". -- Brian Thomson, CSRI Univ. of Toronto {linus,ihnp4,uw-beaver,floyd,utzoo}!utcsrgv!uthub!thomson
guy@rlgvax.UUCP (Guy Harris) (10/06/84)
> longjmp(jb); . . . > bar() { longjmp(jb); } While we're on the subject of proper use of "longjmp", please note that "longjmp" takes two arguments, not 1. The second argument is the "return value" that the "longjmp"ed-to "setjmp" should "return" when it's "longjmp"ed to; if control is coming out of the "setjmp" from a regular call, it returns 0. The "libPW" library on System V Release 2 (and, presumably, all earlier versions) calls "longjmp" with only one argument; this works (I presume) on System V on the VAX-11 by sheer accident, as there must have been a non-zero value on the stack at the point where "longjmp" expected its argument. It does *not* work on 4.2BSD, as there can happen to be a zero value on the stack at that point. Furthermore, there is no guarantee that it will work on any other implementation of UNIX, or any non-UNIX C implementation. Moral: run your code through "lint" whenever you can. It will yell and scream if you call a routine with the wrong number of arguments (unless you say the routine can optionally take more than a given number, in which case it will check only the required arguments.) It looks like the S5R2 "lint" will even check calls to "printf"! (There's a new "lint" declaration "PRINTFLIKE" which can be used for any routine that takes a "printf" string as an formatting string and has a "printf"-like calling sequence.) Guy Harris {seismo,ihnp4,allegra}!rlgvax!guy
jim@ism780b.UUCP (10/10/84)
#R:apollo:-22099700:ism780b:25500028:000:815 ism780b!jim Oct 7 16:58:00 1984 #include <setjmp.h> jmp_buf jmpbuf; main() { /* register */ int i; i = 0; setjmp(jmpbuf); for( ;; i++ ) foo(i); printf("%d\n", i); } foo(i) { if( i == 5 ) longjmp(jmpbuf, 1); } If you get 5 from the above, but 0 if you remove the /* */, your setjmp/longjmp is BROKEN!! It should always give 5. Note that the manual says that all data have values as of the time *longjmp* was called, not as of the time the setjmp was called (which is unimplementable; why do you get 5 instead of 0 in the above?). To do this, longjmp must unwind the stack, restoring registers as it goes. Note that this only requires jmp_buf to have 3 words, instead of the brain-damaged 10 in the 4.1 implementation, where the registers are saved at setjmp time, which is all wrong. -- Jim Balter, INTERACTIVE Systems (ima!jim)
jim@ism780b.UUCP (10/10/84)
#R:apollo:-22099700:ism780b:25500029:000:142 ism780b!jim Oct 8 01:46:00 1984 Whoops! That should have been if( setjmp(jmpbuf) == 0 ) for( ;; i++ ) foo(i); Sorry. -- Jim Balter, INTERACTIVE Systems (ima!jim)
ka@hou3c.UUCP (Kenneth Almquist) (10/14/84)
> The "libPW" library on System V Release 2 (and, presumably, all earlier > versions) calls "longjmp" with only one argument; this works (I presume) > on System V on the VAX-11 by sheer accident, as there must have been a > non-zero value on the stack at the point where "longjmp" expected its > argument. Actually, the fact that longjmp works with one argument is not an accident. The SVR2 manual page for setjmp states, "If longjmp is invoked with a second argument of 0, setjmp will return 1." This was done to make the two argument version of setjmp backward com- patable with the one argument version. The BSD version of setjmp does not do this, so you have to convert all longjmp calls to use two arguments when porting code to Berkely UN*X. Kenneth Almquist
henry@utzoo.UUCP (Henry Spencer) (10/15/84)
> Actually, the fact that longjmp works with one argument is not an > accident. The SVR2 manual page for setjmp states, "If longjmp is > invoked with a second argument of 0, setjmp will return 1." This > was done to make the two argument version of setjmp backward com- > patable with the one argument version. It's still an accident. Calling a function (e.g. longjmp) with fewer parameters than expected is **NOT** guaranteed to make the missing parameters look like zeros. This may work on some machines, but it is not portable. -- Henry Spencer @ U of Toronto Zoology {allegra,ihnp4,linus,decvax}!utzoo!henry
guy@rlgvax.UUCP (Guy Harris) (10/19/84)
> > Actually, the fact that longjmp works with one argument is not an > > accident. The SVR2 manual page for setjmp states, "If longjmp is > > invoked with a second argument of 0, setjmp will return 1." This > > was done to make the two argument version of setjmp backward com- > > patable with the one argument version. > > It's still an accident. Calling a function (e.g. longjmp) with fewer > parameters than expected is **NOT** guaranteed to make the missing > parameters look like zeros. This may work on some machines, but it > is not portable. Well, one could argue that if all one cares about is whether "setjmp" returns a 0 (normal return) or non-zero (nonlocal goto) value, then calling "longjmp" with only one argument will work under all circumstances (either the non-existent argument gets a zero value by accident, in which case it gets mapped into 1, or it gets a non-zero value by accident, in which case it is non-zero). However, it's still not guaranteed to work everywhere. (Admittedly, there are a few functions in the C library that take a variable number of arguments, like "printf" and the "open" system call in USDL UNIX and in 4.2BSD; however, whether the extra arguments are present or not can be intuited from the values of the required arguments, and the code can avoid touching the extra arguments if they are missing. This is emphatically not the case for "longjmp". There may be implementations of C in which not touching the missing arguments may not be enough; these implementations may special-case "printf", but not "setjmp" or "longjmp" - or "open", for that matter.) Guy Harris {seismo,ihnp4,allegra}!rlgvax!guy