Setjmp/longjmp updates and cleanup.

This commit is contained in:
David van Moolenbroek 2006-12-08 16:23:18 +00:00
parent 170a72fd61
commit d4e6fe3546
16 changed files with 232 additions and 345 deletions

View file

@ -1,87 +0,0 @@
/* This file is intended for use by assembly language programs that
* need to manipulate a jmp_buf. It may only be used by those systems
* for which a jmp_buf is identical to a struct sigcontext.
*/
#ifndef _JMP_BUF_H
#define _JMP_BUF_H
#if !defined(CHIP)
#include "error, configuration is not known"
#endif
#if (CHIP == INTEL)
#if _WORD_SIZE == 4
#define JB_FLAGS 0
#define JB_MASK 4
#define JB_GS 8
#define JB_FS 10
#define JB_ES 12
#define JB_DS 14
#define JB_DI 16
#define JB_SI 20
#define JB_BP 24
#define JB_ST 28
#define JB_BX 32
#define JB_DX 36
#define JB_CX 40
#define JB_AX 44
#define JB_RETADR 48
#define JB_IP 52
#define JB_CS 56
#define JB_PSW 60
#define JB_SP 64
#define JB_SS 68
#else /* _WORD_SIZE == 2 */
#define JB_FLAGS 0
#define JB_MASK 2
#define JB_ES 6
#define JB_DS 8
#define JB_DI 10
#define JB_SI 12
#define JB_BP 14
#define JB_ST 16
#define JB_BX 18
#define JB_DX 20
#define JB_CX 22
#define JB_AX 24
#define JB_RETADR 26
#define JB_IP 28
#define JB_CS 30
#define JB_PSW 32
#define JB_SP 34
#define JB_SS 36
#endif /* _WORD_SIZE == 2 */
#else /* !(CHIP == INTEL) */
#if (CHIP == M68000)
#define JB_FLAGS 0
#define JB_MASK 2
#define JB_RETREG 6
#define JB_D1 10
#define JB_D2 14
#define JB_D3 18
#define JB_D4 22
#define JB_D5 26
#define JB_D6 20
#define JB_D7 34
#define JB_A0 38
#define JB_A1 42
#define JB_A2 46
#define JB_A3 50
#define JB_A4 54
#define JB_A5 58
#define JB_A6 62
#define JB_SP 66
#define JB_PC 70
#define JB_PSW 74
#else /* !(CHIP == INTEL) && !(CHIP == M68000) */
#include "error, CHIP is not supported"
#endif /* (CHIP == INTEL) */
/* Defines from C headers needed in assembly code. The headers have too
* much C stuff to used directly.
*/
#define SIG_BLOCK 0 /* must agree with <signal.h> */
#define SC_SIGCONTEXT 2 /* must agree with <sys/sigcontext.h> */
#define SC_NOREGLOCALS 4 /* must agree with <sys/sigcontext.h> */
#endif /* _JMP_BUF_H */

View file

@ -1,67 +1,51 @@
/* 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 actual implementations of all these functions and, by extension, parts
* of this header, are both compiler- and architecture-dependent. Currently
* two compilers are supported: ACK and GCC. Each of these has their own
* implementation of the functions in their runtime system library code.
* As it is impossible to predict the requirements for any other compilers,
* this header may not be compatible with such other compilers either.
*
* 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.
* The ACK compiler will not enregister any variables inside a function
* containing a setjmp call, even if those variables are explicitly declared
* as register variables. Thus for ACK, of all the registers, only the
* program counter, stack pointer and frame pointer have to be saved into the
* jmp_buf structure. This makes the jmp_buf structure very small, and
* moreover, the implementation of the setjmp/longjmp calls (written in EM)
* architecture-independent and thus very portable. The ACK compiler
* recognizes only the symbol __setjmp as being such a setjmp call.
*
* 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.
* The GCC compiler recognizes all of the setjmp/_setjmp/__setjmp name
* variants as calls to setjmp functions, and treats them as special
* accordingly, but does require that the setjmp implementation save and
* restore most of the registers. It has no portable setjmp and longjmp
* functions like ACK, and therefore has to have enough space in the jmp_buf
* structure to store the registers on any architecture it's ported to.
*
* 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.
* Taking the common denominator of both compilers, the function definitions
* in this header rely on the presence of merely two functions: __setjmp and
* longjmp. On the other hand, the size of jmp_buf depends on the compiler
* used: for ACK, jmp_buf is exactly big enough to store the three mentioned
* registers; for GCC and any other compiler, the size is chosen in such a
* way that it's likely to offer enough room to store registers for any
* architecture. The POSIX sigjmp_buf is identical to jmp_buf in all cases.
*
* 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.
* As far as porting is concerned --
*
* The POSIX sigjmp_buf is identical to the jmp_buf in all cases.
* All code writers/porters that have to deal with the actual contents of the
* jmp_buf structure in one way or another, should look at <sys/jmp_buf.h>.
*
* 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:
* Porters of a new compiler to Minix have to make sure the compiler
* recognizes at least __setjmp as a setjmp call (if applicable) and provide
* library implementations of __setjmp and longjmp conforming to their
* declarations below; if this is not possible, compiler-specific code will
* have to be added to this header.
*
* _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.
* Porters of Minix+GCC to other architectures have to make sure that the
* __regs array of the jmp_buf structure is large enough to hold all the
* registers the __setjmp implementation for that architecture has to save.
*/
#ifndef _SETJMP_H
@ -71,82 +55,34 @@
#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 1
#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)
#if defined(__ACK__)
_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 */
long __mask; /* must have size >= sizeof(sigset_t) */
int __flags;
#else /* GCC */
int __flags; /* XXX - long might give better alignment */
long __mask; /* must have size >= sizeof(sigset_t) */
void *__regs[16]; /* actual use is architecture 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) );
#define _longjmp(env, val) longjmp((env), (val))
#endif
#ifdef _POSIX_SOURCE
typedef jmp_buf sigjmp_buf;
#ifdef __GNUC__
#define siglongjmp longjmp
#else
_PROTOTYPE( void siglongjmp, (sigjmp_buf _env, int _val) );
#endif
#define sigsetjmp(env, savemask) __setjmp((env), (savemask))
#define siglongjmp(env, val) longjmp((env), (val))
#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 */

45
include/sys/jmp_buf.h Normal file
View file

@ -0,0 +1,45 @@
/* This file is intended for use by program code (possibly written in
* assembly) that needs to manipulate a jmp_buf or sigjmp_buf. The JB_*
* values are byte offsets into the jmp_buf and sigjmp_buf structures.
*/
#ifndef _JMP_BUF_H
#define _JMP_BUF_H
#include <minix/config.h>
#if defined(__ACK__)
/* as per lib/ack/rts/setjmp.e */
/* note the lack of parentheses, which would confuse 'as' */
#define JB_PC 0
#define JB_SP JB_PC + _EM_PSIZE
#define JB_LB JB_SP + _EM_PSIZE
#define JB_MASK JB_LB + _EM_PSIZE
#define JB_FLAGS JB_MASK + _EM_LSIZE
#if (CHIP == INTEL)
#define JB_BP JB_LB
#endif
#elif defined(__GNUC__)
#if (CHIP == INTEL) && (_WORD_SIZE == 4)
/* as per lib/gnu/rts/__setjmp.gs */
#define JB_FLAGS 0
#define JB_MASK 4
#define JB_PC 8
#define JB_SP 12
#define JB_BP 16
#define JB_BX 20
#define JB_CX 24
#define JB_DX 28
#define JB_SI 32
#define JB_DI 36
#endif /* (CHIP == INTEL) && (_WORD_SIZE == 4) */
#endif /* __GNU__ */
#endif /* _JMP_BUF_H */

View file

@ -136,11 +136,6 @@ struct sigcontext {
#define sc_psw sc_regs.sr_psw
#endif /* _MINIX_CHIP == M68000 */
/* Values for sc_flags. Must agree with <minix/jmp_buf.h>. */
#define SC_SIGCONTEXT 2 /* nonzero when signal context is included */
#define SC_NOREGLOCALS 4 /* nonzero when registers are not to be
saved and restored */
_PROTOTYPE( int sigreturn, (struct sigcontext *_scp) );
#endif /* _SIGCONTEXT_H */

View file

@ -38,19 +38,6 @@ message *m_ptr; /* pointer to request message */
if (src_phys == 0) return(EFAULT);
phys_copy(src_phys, vir2phys(&sc), (phys_bytes) sizeof(struct sigcontext));
/* Make sure that this is not just a jump buffer. */
if ((sc.sc_flags & SC_SIGCONTEXT) == 0) return(EINVAL);
/* Fix up only certain key registers if the compiler doesn't use
* register variables within functions containing setjmp.
*/
if (sc.sc_flags & SC_NOREGLOCALS) {
rp->p_reg.retreg = sc.sc_retreg;
rp->p_reg.fp = sc.sc_fp;
rp->p_reg.pc = sc.sc_pc;
rp->p_reg.sp = sc.sc_sp;
return(OK);
}
sc.sc_psw = rp->p_reg.psw;
#if (CHIP == INTEL)

View file

@ -47,7 +47,7 @@ message *m_ptr; /* pointer to request message */
memcpy(&sc.sc_regs, (char *) &rp->p_reg, sizeof(struct sigregs));
/* Finish the sigcontext initialization. */
sc.sc_flags = SC_SIGCONTEXT;
sc.sc_flags = 0; /* unused at this time */
sc.sc_mask = smsg.sm_mask;
/* Copy the sigcontext structure to the user's stack. */

View file

@ -2,9 +2,7 @@
LIBRARIES=libc
libc_FILES=" \
_longjmp.gs \
_setjmp.gs \
longjmp.gs \
setjmp.gs"
__setjmp.gs \
longjmp.gs"
TYPE=gnu

31
lib/gnu/rts/__setjmp.gs Normal file
View file

@ -0,0 +1,31 @@
/ __setjmp.gnu.s
/
/ Created: Oct 14, 1993 by Philip Homburg <philip@cs.vu.nl>
.text
.globl ___setjmp
___setjmp:
movl 4(%esp), %eax # jmp_buf
movl %edx, 28(%eax) # save edx
movl 0(%esp), %edx
movl %edx, 8(%eax) # save program counter
movl %esp, 12(%eax) # save stack pointer
movl %ebp, 16(%eax) # save frame pointer
movl %ebx, 20(%eax)
movl %ecx, 24(%eax)
movl %esi, 32(%eax)
movl %edi, 36(%eax)
movl 8(%esp), %edx # save mask?
movl %edx, 0(%eax) # save whether to restore mask
testl %edx, %edx
jz 1f
leal 4(%eax), %edx # pointer to sigset_t
pushl %edx
call ___newsigset # save mask
addl $4, %esp
1:
movl $0, %eax
ret
/ $PchId: __setjmp.gnu.s,v 1.4 1996/03/12 19:30:54 philip Exp $

View file

@ -1,38 +0,0 @@
/ _longjmp.gnu.s
/
/ Created: Oct 15, 1993 by Philip Homburg <philip@cs.vu.nl>
.text
.globl __longjmp
__longjmp:
movl 4(%esp), %eax # jmp_buf
cmpl $0, 0(%eax) # save mask?
je 1f
leal 4(%eax), %ebx # pointer to sigset_t
pushl %ebx
call ___oldsigset # restore mask
addl $4, %esp
movl 4(%esp), %eax # jmp_buf
1:
movl 8(%esp), %ecx # result value
movl 12(%eax), %esp # restore stack pointer
movl 8(%eax), %ebx # restore program counter
movl %ebx, 0(%esp)
pushl %ecx # save result code
movl 16(%eax), %ebp # restore frame pointer
movl 20(%eax), %ebx
movl 24(%eax), %ecx
movl 28(%eax), %edx
movl 32(%eax), %esi
movl 36(%eax), %edi
pop %eax
testl %eax, %eax
jz 1f
ret
1: movl $1, %eax
ret
/ $PchId: _longjmp.gnu.s,v 1.4 1996/03/12 19:30:02 philip Exp $

View file

@ -1,35 +0,0 @@
/ _setjmp.gnu.s
/
/ Created: Oct 14, 1993 by Philip Homburg <philip@cs.vu.nl>
.text
.globl ___setjmp
___setjmp:
movl 4(%esp), %eax # jmp_buf
movl %ebx, 20(%eax) # save ebx
movl 0(%esp), %ebx
movl %ebx, 8(%eax) # save program counter
movl %esp, 12(%eax) # save stack pointer
movl %ebp, 16(%eax) # save frame pointer
movl %ecx, 24(%eax)
movl %edx, 28(%eax)
movl %esi, 32(%eax)
movl %edi, 36(%eax)
movl 8(%esp), %ebx # save mask?
movl %ebx, 0(%eax) # save whether to restore mask
pushl 20(%eax) # save ebx
testl %ebx, %ebx
jz 1f
leal 4(%eax), %ebx # pointer to sigset_t
pushl %ebx
call ___newsigset # save mask
addl $4, %esp
1:
popl %ebx
movl $0, %eax
ret
/ $PchId: _setjmp.gnu.s,v 1.4 1996/03/12 19:30:54 philip Exp $

View file

@ -1,6 +1,38 @@
.text
.globl _longjmp
_longjmp:
jmp __longjmp
/ longjmp.gnu.s
/
/ Created: Oct 15, 1993 by Philip Homburg <philip@cs.vu.nl>
/ $PchId: longjmp.gnu.s,v 1.4 1996/03/12 19:31:18 philip Exp $
.text
.globl _longjmp
_longjmp:
movl 4(%esp), %eax # jmp_buf
cmpl $0, 0(%eax) # save mask?
je 1f
leal 4(%eax), %edx # pointer to sigset_t
pushl %edx
call ___oldsigset # restore mask
addl $4, %esp
movl 4(%esp), %eax # jmp_buf
1:
movl 8(%esp), %ecx # result value
movl 12(%eax), %esp # restore stack pointer
movl 8(%eax), %edx # restore program counter
movl %edx, 0(%esp)
pushl %ecx # save result code
movl 16(%eax), %ebp # restore frame pointer
movl 20(%eax), %ebx
movl 24(%eax), %ecx
movl 28(%eax), %edx
movl 32(%eax), %esi
movl 36(%eax), %edi
pop %eax
testl %eax, %eax
jz 1f
ret
1: movl $1, %eax
ret
/ $PchId: longjmp.gnu.s,v 1.4 1996/03/12 19:30:02 philip Exp $

View file

@ -1,6 +0,0 @@
.text
.globl _setjmp
_setjmp:
jmp ___setjmp
/ $PchId: setjmp.gnu.s,v 1.4 1996/03/12 19:31:18 philip Exp $

View file

@ -1,42 +1,10 @@
#include <lib.h>
#define sigfillset _sigfillset
#define sigjmp _sigjmp
#define sigprocmask _sigprocmask
#define sigreturn _sigreturn
#include <sys/sigcontext.h>
#include <setjmp.h>
#include <signal.h>
_PROTOTYPE( int sigjmp, (jmp_buf jb, int retval));
#if (_SETJMP_SAVES_REGS == 0)
/* 'sigreturn' using a short format jmp_buf (no registers saved). */
PUBLIC int sigjmp(jb, retval)
jmp_buf jb;
int retval;
{
struct sigcontext sc;
sc.sc_flags = jb[0].__flags;
sc.sc_mask = jb[0].__mask;
#if (CHIP == INTEL)
sc.sc_pc = (int) jb[0].__pc;
sc.sc_sp = (int) jb[0].__sp;
sc.sc_fp = (int) jb[0].__lb;
#endif
#if (CHIP == M68000)
sc.sc_pc = (long) jb[0].__pc;
sc.sc_sp = (long) jb[0].__sp;
sc.sc_fp = (long) jb[0].__lb;
#endif
sc.sc_retreg = retval;
return sigreturn(&sc);
}
#endif
PUBLIC int sigreturn(scp)
register struct sigcontext *scp;
{

View file

@ -89,7 +89,6 @@ libc_FILES=" \
sigemptyset.s \
sigfillset.s \
sigismember.s \
siglongjmp.s \
sigpending.s \
sigprocmask.s \
sigreturn.s \

View file

@ -1,7 +0,0 @@
.sect .text
.extern _longjmp
.define _siglongjmp
.align 2
_siglongjmp:
jmp _longjmp

69
man/man3/setjmp.3 Normal file
View file

@ -0,0 +1,69 @@
.TH SETJMP 3 "June 22, 2006"
.UC 4
.SH NAME
setjmp, longjmp, _setjmp, _longjmp, sigsetjmp, siglongjmp \- save and restore execution contexts
.SH SYNOPSIS
.nf
.ft B
#include <setjmp.h>
int setjmp(jmp_buf env);
void longjmp(jmp_buf env, int val);
int _setjmp(jmp_buf env);
void _longjmp(jmp_buf env, int val);
#define _POSIX_SOURCE
int sigsetjmp(sigjmp_buf env, int savemask);
void siglongjmp(sigjmp_buf env, int val);
.SH DESCRIPTION
These calls provide a way for a process to save an execution context into a
buffer, and later resume execution from that context, effectively performing
a non-local jump. The
.B setjmp
family of functions store the context into the \fIenv\fP data structure,
and return the value 0. The
.B longjmp
family of functions jump to the context saved in the given \fIenv\fP data
structure, causing the process to continue as if it returned from the
corresponding
.B setjmp
call again, but this time with the non-zero return value in \fIval\fP.
.PP
The difference between the three pairs of setjmp/longjmp functions lies in the
behaviour with respect to saving/restoring the process signal mask. POSIX does
not require the process signal mask to be saved and restored during
.B setjmp
/
.B longjmp
\. However, the current implementation does this in order to agree with OSF/1
and other BSD derived systems.
.PP
The pair of functions
.B _setjmp
/
.B _longjmp
, traditional in BSD systems, may be used when the signal mask is not to be
saved/restored.
.PP
Finally, the POSIX
.B sigsetjmp
/
.B siglongjmp
functions allow the programmer to specify explicitly whether the signal mask
is to be saved/restored, by means of the \fIsavemask\fP parameter. If this
parameter is zero, the signal mask will not be saved/restored, otherwise it
will.
.SH NOTES
After the function calling
.B setjmp
has returned, the saved context may not be used in a call to
.B longjmp
anymore, since the relevant portion of the stack may already have been wiped
out at that point.
.PP
Using these functions to return to a previous state from a signal handler
is possible but should be done with extreme care, as some interrupted library
routines may not be reentrant and/or temporarily allocate resources.
.PP
See the setjmp.h header file for more implementation details specific to Minix.