149 lines
5.7 KiB
C
149 lines
5.7 KiB
C
|
/* The <setjmp.h> header relates to the C phenomenon known as setjmp/longjmp.
|
||
|
* It is used to escape out of the current situation into a previous one.
|
||
|
* A typical example is in an editor, where hitting DEL breaks off the current
|
||
|
* command and puts the editor back in the main loop, though care has to be
|
||
|
* taken when the DEL occurs while executing a library function, since
|
||
|
* some of them are not reentrant.
|
||
|
*
|
||
|
* POSIX does not require the process signal mask to be saved and restored
|
||
|
* during setjmp/longjmp. However, the current implementation does this
|
||
|
* in order to agree with OSF/1 and other BSD derived systems.
|
||
|
*
|
||
|
* The pair of functions _setjmp/_longjmp may be used when the signal
|
||
|
* mask is not to be saved/restored. These functions are traditional
|
||
|
* in BSD systems.
|
||
|
*
|
||
|
* There are different ways of implementing setjmp/longjmp. Probably
|
||
|
* the best way is to unify it with signal handling. This is true for the
|
||
|
* following reasons: Both setjmp/longjmp and signal delivery must save
|
||
|
* a context so that it may be restored later. The jmp_buf necessarily
|
||
|
* contains signal information, namely the signal mask to restore. Both
|
||
|
* longjmp and the return of a signal handler must trap to the operating
|
||
|
* system to restore the previous signal mask. Finally, the jmp_buf
|
||
|
* and the sigcontext structure contain the registers to restore.
|
||
|
*
|
||
|
* Some compilers, namely ACK, will not enregister any variables inside a
|
||
|
* function containing a call to setjmp, even if those variables are
|
||
|
* explicitly declared as register variables. Thus for ACK, the
|
||
|
* identification of the jmp_buf with a sigcontext structure would cause
|
||
|
* unnecessary overhead: the jmp_buf has room for all the registers, but
|
||
|
* the only registers that need to be saved are the stack pointer,
|
||
|
* frame pointer, and program counter.
|
||
|
*
|
||
|
* So, for ACK a jmp_buf is much smaller than a sigcontext structure, and
|
||
|
* longjmp does not directly call sigreturn. Instead, longjmp calls a
|
||
|
* front-end function which initializes the appropriate fields of a
|
||
|
* sigcontext structure, marks this structure as containing no valid
|
||
|
* general purpose registers, and then calls sigreturn.
|
||
|
*
|
||
|
* The POSIX sigjmp_buf is identical to the jmp_buf in all cases.
|
||
|
*
|
||
|
* Different compilers have different symbols that they recognize as
|
||
|
* setjmp symbols. ACK recognizes __setjmp, the GNU C compiler
|
||
|
* recognizes setjmp and _setjmp, and BCC recognizes all three.
|
||
|
* When these symbols occur within a function, the compiler may keep
|
||
|
* all local variables on the stack, avoid certain optimizations, or
|
||
|
* pass hidden arguments to the setjmp function.
|
||
|
*
|
||
|
* Thus, setjmp implementations vary in two independent ways which may
|
||
|
* be identified through the following preprocessor tokens:
|
||
|
*
|
||
|
* _SETJMP_SYMBOL -- If 0, this means the compiler treats setjmp and _setjmp
|
||
|
* specially. If 1, this means the compiler treats __setjmp specially.
|
||
|
*
|
||
|
* _SETJMP_SAVES_REGS -- If 1, this means setjmp/longjmp must explicitly
|
||
|
* save and restore all registers. This also implies that a jmp_buf is
|
||
|
* different than a sigcontext structure. If 0, this means that the compiler
|
||
|
* will not use register variables within a function that calls one of
|
||
|
* its SETJMP_SYMBOLs.
|
||
|
*
|
||
|
* When _SETJMP_SYMBOL = 1, the implementation has a few dozen bytes of
|
||
|
* unnecessary overhead. This happens in the following manner: a program uses
|
||
|
* _setjmp/_longjmp because it is not interested in saving and restoring the
|
||
|
* signal mask. Nevertheless, because _setjmp expands to the general purpose
|
||
|
* function __setjmp, code for sigprocmask(2) is linked into the program.
|
||
|
*/
|
||
|
|
||
|
#ifndef _SETJMP_H
|
||
|
#define _SETJMP_H
|
||
|
|
||
|
#ifndef _ANSI_H
|
||
|
#include <ansi.h>
|
||
|
#endif
|
||
|
|
||
|
#if !defined(__ACK__) && !defined(__BCC__) && !defined(__GNUC__)
|
||
|
#define __ACK__
|
||
|
#endif
|
||
|
|
||
|
#ifdef __ACK__
|
||
|
#define _SETJMP_SYMBOL 1
|
||
|
#define _SETJMP_SAVES_REGS 0
|
||
|
#endif
|
||
|
#ifdef __BCC__
|
||
|
#define _SETJMP_SYMBOL 0
|
||
|
#define _SETJMP_SAVES_REGS 1
|
||
|
#endif
|
||
|
#ifdef __GNUC__
|
||
|
#define _SETJMP_SYMBOL 0
|
||
|
#define _SETJMP_SAVES_REGS 1
|
||
|
#endif
|
||
|
|
||
|
/* The jmp_buf data type. Do not change the order of these fields -- some
|
||
|
* C library code refers to these fields by name. When _SETJMP_SAVES_REGS
|
||
|
* is 1, the file <sys/jmp_buf.h> gives the usage of the sixteen registers.
|
||
|
*/
|
||
|
typedef struct {
|
||
|
int __flags; /* XXX - long might give better alignment */
|
||
|
long __mask; /* must have size >= sizeof(sigset_t) */
|
||
|
#if (_SETJMP_SAVES_REGS == 0)
|
||
|
_PROTOTYPE(void (*__pc),(void)); /* program counter */
|
||
|
void *__sp; /* stack pointer */
|
||
|
void *__lb; /* local base (ACKspeak for frame pointer) */
|
||
|
#else
|
||
|
void *__regs[16]; /* size is machine dependent */
|
||
|
#endif
|
||
|
} jmp_buf[1];
|
||
|
|
||
|
#if (_SETJMP_SYMBOL == 1)
|
||
|
|
||
|
_PROTOTYPE( int __setjmp, (jmp_buf _env, int _savemask) );
|
||
|
_PROTOTYPE( void longjmp, (jmp_buf _env, int _val) );
|
||
|
_PROTOTYPE(int sigjmp, (jmp_buf _jb, int _retval) );
|
||
|
|
||
|
#define setjmp(env) __setjmp((env), 1)
|
||
|
|
||
|
#ifdef _MINIX
|
||
|
#define _setjmp(env) __setjmp((env), 0)
|
||
|
_PROTOTYPE(void _longjmp, (jmp_buf _env, int _val) );
|
||
|
#endif
|
||
|
|
||
|
#ifdef _POSIX_SOURCE
|
||
|
typedef jmp_buf sigjmp_buf;
|
||
|
_PROTOTYPE( void siglongjmp, (sigjmp_buf _env, int _val) );
|
||
|
|
||
|
#define sigsetjmp(env, savemask) __setjmp((env), (savemask))
|
||
|
#endif /* _POSIX_SOURCE */
|
||
|
|
||
|
#endif /* _SETJMP_SYMBOL == 1 */
|
||
|
|
||
|
#if (_SETJMP_SYMBOL == 0)
|
||
|
|
||
|
_PROTOTYPE( int setjmp, (jmp_buf _env) );
|
||
|
_PROTOTYPE( void longjmp, (jmp_buf _env, int _val) );
|
||
|
|
||
|
#ifdef _MINIX
|
||
|
_PROTOTYPE( int _setjmp, (jmp_buf _env) );
|
||
|
_PROTOTYPE( void _longjmp, (jmp_buf _env, int _val) );
|
||
|
#endif
|
||
|
|
||
|
#ifdef _POSIX_SOURCE
|
||
|
#define sigjmp_buf jmp_buf
|
||
|
_PROTOTYPE( void siglongjmp, (sigjmp_buf _env, int _val) );
|
||
|
/* XXX - the name _setjmp is no good - that's why ACK used __setjmp. */
|
||
|
#define sigsetjmp(env, savemask) ((savemask) ? setjmp(env) : _setjmp(env))
|
||
|
#endif /* _POSIX_SOURCE */
|
||
|
|
||
|
#endif /* _SETJMP_SYMBOL == 0 */
|
||
|
|
||
|
#endif /* _SETJMP_H */
|