Google
 

Trailing-Edge - PDP-10 Archives - SRI_NIC_PERM_FS_1_19910112 - c/lib/gen/setjmp.c
There are 8 other files named setjmp.c in the archive. Click here to see a list.
/*
**	SETJMP	- setjmp() and longjmp().
**
**	(c) Copyright Ken Harrenstien, SRI International 1987
**
** Must be closely coordinated with signal code as we must be able
** to longjmp() out of a signal handler!
*/

#include <c-env.h>
#if SYS_T20+SYS_10X+SYS_T10+SYS_CSI+SYS_WTS+SYS_ITS	/* Systems supported for */

#include <stddef.h>		/* for NULL */
#include <stdlib.h>		/* abort */
#include <sys/usysig.h>
#include <setjmp.h>

static void `ljmpe`(), _ljmp();	/* Internal routines.  ljmpe() quoted
				** so that ASM code can refer to it by name.
				*/
int
_setjmp(env)
jmp_buf env;
{
	asm("	jrst setjmp\n");
}

int
setjmp(env)
jmp_buf env;
{
	asm(SIGCONTEXT_ASM);	/* Define asm offsets into sigcontext struct */
#asm
#if SYS_T20+SYS_10X
	search monsym		/* for debrk% */
	extern .intlev, .intpca
#endif
	extern .sigstk, .sigblockmask

	skipn 16,-1(17)		/* Get address of sigcontext struct */
	 pushj 17,ljmpe
	move 2,17		/* Get copy of stack ptr */
	pop 2,sc.pc(16)		/* Save return PC, and get bumped ptr */
	movem 2,sc.acs+17(16)	/* Save stack ptr */
	move 3,.sigstk+1
	movem 3,sc.stkflg(16)	/* Save flag saying if this is signal stack */
	move 4,.sigblockmask
	movem 4,sc.mask(16)	/* Save current signal block mask */
#if SYS_T20+SYS_10X
	hrlz 5,.intlev		/* Save interrupt level indicator */
	movem 5,sc.osinf(16)
#else
	setzb 5,sc.osinf(16)
#endif
	add 2,sc.pc(16)	/* AC2 already has stack ptr, add return addr */
	add 2,3		/* Add flag */
	add 2,4		/* Add mask */
	add 2,5		/* Add intlev */
	movem 2,sc.acs+2(16)	/* Store checksum! */
	setz 1,		/* Return zero */
#endasm
}
/* Local flags for _ljmp() use. */
#define LJ_SBMASK 01	/* Restore old signal block mask */
#define LJ_DEINT 02	/* Leave interrupt level */


void
_longjmp(env, val)
jmp_buf env;
int val;
{
    _ljmp(&env[0], val, 0);
}

void
longjmp(env, val)
jmp_buf env;
int val;
{
    int flag = LJ_SBMASK;	/* longjmp always restores block mask */
    register struct sigcontext *scp = &env[0];

    /* Check the jmp_buf environment carefully... */
    if (scp == NULL)		/* First check for valid pointer */
	`ljmpe`();

    /* Ensure saved PC not zero, and Check the checksum */
    if (scp->sc_pc == 0
      || ((scp->sc_pc + scp->sc_acs[017]
	  + scp->sc_stkflg + scp->sc_mask + scp->sc_osinf)
	!= scp->sc_acs[2]))
	`ljmpe`();

    /* Compare stack pointers if possible */
    if ((scp->sc_stkflg != 0) == (_sigstk.ss_onstack != 0)) {
	/* If saved stack state is same as current stack state */
	if (scp->sc_acs[017] >= *(int *)017)	/* Compare stack ptrs! */
	    `ljmpe`();			/* Prev must be less than current! */
    } else if (scp->sc_stkflg)	/* States are different... */
	`ljmpe`();			/* error if prev was on sig stack! */

#if SYS_T20+SYS_10X
    if ((unsigned)scp->sc_osinf >> 18) {
	if (((unsigned)scp->sc_osinf >> 18) != _intlev)
	    `ljmpe`();		/* Cannot change to non-zero intlev */
    } else if (_intlev)
	flag |= LJ_DEINT;	/* Must get out of interrupt level */
#endif
    _ljmp(&env[0], val, flag);
}
/* Aux rtn so longjmp asm code can call symbol which is actually macro. */

static void
`ljmpe`()
{
    longjmperror();
    abort();
}

static void
_ljmp(scp, val, flag)
struct sigcontext *scp;
int val, flag;
{
#asm
	extern .sigtrigpend
	extern .sigusys, .sigpendmask

	skipn 16,-1(17)	/* Get sigcontext pointer */
	 pushj 17,ljmpe	/* If null pointer, go barf! */
	skipn 1,-2(17)	/* Get return value */
	 movei 1,1	/* If zero, substitute 1 */
	skipe 2,-3(17)	/* Get flags */
	 jrst ljmp2	/* Something set, do fancy stuff */

	/* No fancy stuff */
	skipe 15,sc.pc(16)	/* Get return address */
	 skipn 2,sc.acs+17(16)	/* Get new stack ptr */
	  pushj 17,ljmpe	/* If either is zero, go barf. */
	move 17,2
	jrst (15)		/* Return! */

	/* Fancy stuff, sigh.  Get everything we need into ACs. */
ljmp2:	move 3,sc.stkflg(16)	/* Get sigstk and mask */
	move 4,sc.mask(16)
	aos .sigusys		/* Ignore interrupts for a bit */
	skipe 15,sc.pc(16)	/* Get return addr */
	 skipn 7,sc.acs+17(16)	/* Get stack ptr */
	  pushj 17,ljmpe	/* If either is zero, go barf! */
	move 17,7		/* Restore stack ptr! */
	movem 3,.sigstk+1	/* Restore signal stack flag */
	push 17,15		/* Save return addr on new stack */
	trne 2,<LJ_SBMASK>	/* And if flag requests it, */
	 movem 4,.sigblockmask	/* restore signal block mask. */

#if SYS_T20+SYS_10X
	trnn 2,<LJ_DEINT>	/* Need to leave int level? */
	 jrst ljmp99		/* No, skip hairy stuff */

	/* Must leave int level with DEBRK% */
	skipn 7,.intpca		/* Get address of interrupt PC */
	 pushj 17,ljmpe		/* Barf if not set */
	xmovei 6,ljmp98
	movem 6,(7)		/* Store new PC (just below!) */
	debrk%			/* Now get out of int level! */
ljmp98:	setzm .intlev		/* Control "drops thru" to here... */
				/* Restore software idea of int level state */
ljmp99:
#endif
	push 17,1		/* Save return value */
#endasm
	asm(USYS_END_ASM);	/* Permit interrupts, take any pending ones */
	asm("	pop 17,1\n");	/* Restore return value, */
}				/* and return! (Retaddr was pushed on stack) */

#endif /* T20+10X+T10+CSI+WAITS+ITS */