Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 30 Aug 1998 17:51:49 +0200
From:      Martin Cracauer <cracauer@cons.org>
To:        Bruce Evans <bde@zeta.org.au>, cracauer@cons.org, current@FreeBSD.ORG, luoqi@watermarkgroup.com, shocking@prth.pgs.com
Subject:   Re: Floating Point Exceptions, signal handlers & subsequent ops
Message-ID:  <19980830175149.A22835@cons.org>
In-Reply-To: <199808270253.MAA15661@godzilla.zeta.org.au>; from Bruce Evans on Thu, Aug 27, 1998 at 12:53:36PM %2B1000
References:  <199808270253.MAA15661@godzilla.zeta.org.au>

next in thread | previous in thread | raw e-mail | index | archive | help

--envbJBWh7q8WU6mo
Content-Type: text/plain; charset=us-ascii

In <199808270253.MAA15661@godzilla.zeta.org.au>, Bruce Evans wrote: 
> >Ah, now I got it.
> >
> >If sig == SIGFPE, then expect the trap code to be one of FPE_*_TRAP
> >values from machine/trap.h, *not* one of the T_* values.
> 
> Except this is not implemented.

Does the appended diff count as an implementation? Test program
included. 

I'm sure I violate more kernel code rules that DBL_MAX can express :-)
 
> >Why is this, why two classes of trap codes?
> 
> T_* is for the kernel and is unportable.  FPE_* is for the user SIGFPE
> handler and is not so unportable in theory.

I found that the FP_X_ macros are in wide enough use to be valuable
for portable code. I changed the values of the non-FPU SIGFPE macros
on x86 so that they are in the same value domain as the FP_X_
macros. Thus, in a SIGFPE handler you'll find one of the FP_X_ or
FPE_......_TRAP macros as the second argument to the handler.

IMHO the fact that the argument can be from one of two completely
different macros sets models the fact that you'll get non-FPU
exceptions to your FPE handler on a x86 machine quite well.

Martin
-- 
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Martin Cracauer <cracauer@cons.org> http://www.cons.org/cracauer
BSD User Group Hamburg, Germany     http://www.bsdhh.org/

--envbJBWh7q8WU6mo
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="diff.float"

? compile/WINGS
? i386/conf/WINGS
? i386/conf/WINGS.from-SMP-GENERIC
Index: i386/i386/machdep.c
===================================================================
RCS file: /home/CVS-FreeBSD/src/sys/i386/i386/machdep.c,v
retrieving revision 1.304
diff -c -r1.304 machdep.c
*** machdep.c	1998/08/18 07:46:58	1.304
--- machdep.c	1998/08/30 00:22:59
***************
*** 136,141 ****
--- 136,143 ----
  #include <machine/random.h>
  #include <sys/ptrace.h>
  
+ #include <machine/floatingpoint.h>
+ 
  extern void init386 __P((int first));
  extern void dblfault_handler __P((void));
  
***************
*** 502,508 ****
--- 504,515 ----
  	struct sigframe sf;
  	struct sigacts *psp = p->p_sigacts;
  	int oonstack;
+ 	u_long fpuctrl;
  
+ 	if (sig == SIGFPE && code == 0) {
+ 		__fnstcw(&fpuctrl);
+ 		code = 0x3F & ~fpuctrl & curpcb->pcb_savefpu.sv_ex_sw;
+ 	}
  	regs = p->p_md.md_regs;
          oonstack = psp->ps_sigstk.ss_flags & SS_ONSTACK;
  	/*
Index: i386/include/trap.h
===================================================================
RCS file: /home/CVS-FreeBSD/src/sys/i386/include/trap.h,v
retrieving revision 1.7
diff -c -r1.7 trap.h
*** trap.h	1997/02/22 09:35:19	1.7
--- trap.h	1998/08/30 00:23:00
***************
*** 76,89 ****
  #define	    ILL_ALIGN_FAULT	T_ALIGNFLT
  #define	    ILL_FPOP_FAULT	T_FPOPFLT	/* coprocessor operand fault */
  
! /* codes for SIGFPE/ARITHTRAP */
! #define	    FPE_INTOVF_TRAP	0x1	/* integer overflow */
! #define	    FPE_INTDIV_TRAP	0x2	/* integer divide by zero */
! #define	    FPE_FLTDIV_TRAP	0x3	/* floating/decimal divide by zero */
! #define	    FPE_FLTOVF_TRAP	0x4	/* floating overflow */
! #define	    FPE_FLTUND_TRAP	0x5	/* floating underflow */
! #define	    FPE_FPU_NP_TRAP	0x6	/* floating point unit not present */
! #define	    FPE_SUBRNG_TRAP	0x7	/* subrange out of bounds */
  
  /* codes for SIGBUS */
  #define	    BUS_PAGE_FAULT	T_PAGEFLT	/* page fault protection base */
--- 76,92 ----
  #define	    ILL_ALIGN_FAULT	T_ALIGNFLT
  #define	    ILL_FPOP_FAULT	T_FPOPFLT	/* coprocessor operand fault */
  
! /* 
!  * codes for SIGFPE/ARITHTRAP 
!  * avoid values used for FPU exceptions (FP_X_...)
!  */
! #define	    FPE_INTOVF_TRAP	0xFF01	/* integer overflow */
! #define	    FPE_INTDIV_TRAP	0xFF02	/* integer divide by zero */
! #define	    FPE_FLTDIV_TRAP	0xFF03	/* floating/decimal divide by zero */
! #define	    FPE_FLTOVF_TRAP	0xFF04	/* floating overflow */
! #define	    FPE_FLTUND_TRAP	0xFF05	/* floating underflow */
! #define	    FPE_FPU_NP_TRAP	0xFF06	/* floating point unit not present */
! #define	    FPE_SUBRNG_TRAP	0xFF07	/* subrange out of bounds */
  
  /* codes for SIGBUS */
  #define	    BUS_PAGE_FAULT	T_PAGEFLT	/* page fault protection base */

--envbJBWh7q8WU6mo
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="freebsd-signal.c"

#include <stdio.h>
#include <signal.h>
#include <setjmp.h>
#include <sys/types.h>
#include <unistd.h>

#include <math.h>

#include <float.h>
#include <floatingpoint.h>

volatile static sig_atomic_t sig_fpe_was_here = 0;
volatile static int sig_sig;
volatile static int sig_code;
static struct sigcontext sig_context;
static jmp_buf jmpbuf;

static int 
handler(int sig, int code, struct sigcontext *scp)
{
#if 0
#define TMP "FPE handler\n"
  write(2,TMP,sizeof(TMP)-1);
#undef TMP
#endif
  sig_fpe_was_here++;
  sig_sig = sig;
  sig_code = code;
  memcpy(&sig_context, scp, sizeof(*scp));
  longjmp(jmpbuf,1);

  return sig;
}

static const char *
codestring(int code)
{
  switch (code) {

  case FPE_INTOVF_TRAP: return "FPE_INTOVF_TRAP";
  case FPE_INTDIV_TRAP: return "FPE_INTDIV_TRAP";
  case FPE_FPU_NP_TRAP: return "FPE_FPU_NP_TRAP";
  case FPE_SUBRNG_TRAP: return "FPE_SUBRNG_TRAP";

  case FP_X_INV : return "FP_X_INV";
  case FP_X_DNML: return "FP_X_DNML";
  case FP_X_DZ  : return "FP_X_DZ  ";
  case FP_X_OFL : return "FP_X_OFL";
  case FP_X_UFL : return "FP_X_UFL";
  case FP_X_IMP : return "FP_X_IMP";
  default: return "Unknwon code";
  }
}

#if 0
static double 
deopt(double d)
{
  return d;
}
#endif

static double
l_idiv(double p1, double p2)
{
  return (double)((int)p1 / (int)p2);
}

static double
l_fadd(double p1, double p2)
{
  return p1 + p2;
}

static double
l_fmul(double p1, double p2)
{
  return p1 * p2;
}

static double
l_fdiv(double p1, double p2)
{
  return p1 / p2;
}

static double
l_fsub(double p1, double p2)
{
  return p1 - p2;
}

static double
l_sin(double p1, double p2)
{
  return sin(p1);
}

static double
l_sqrt(double p1, double p2)
{
  return sqrt(p1);
}

typedef double (test_f_t)(double, double);

struct funcpair {
  test_f_t *func;
  const double p1;
  const double p2;
  const char *const descr;
} const funcs[] = {
  {l_idiv,   0.0,     0.0,     "int 0/0      "},
  {l_idiv,   1.0,     0.0,     "int 1/0      "},
  {l_fdiv,   0.0,     0.0,     "dbl 0/0      "},
  {l_fdiv,   1.0,     0.0,     "dbl 1/0      "},
  {l_fdiv,   DBL_MIN, DBL_MIN, "dbl MIN/MIN  "},
  {l_fdiv,   DBL_MIN, 2.0,     "dbl MIN/2    "},
  {l_fsub,   DBL_MIN, DBL_MIN, "dbl MIN-MIN  "},
  {l_fmul,   DBL_MAX, 2.0,     "dbl 2*MAX    "},
  {l_fmul,   DBL_MAX, DBL_MAX, "dbl MAX*MAX  "},
  {l_fadd,   DBL_MAX, DBL_MAX, "dbl MAX+MAX  "},
  {l_sin,    10.0,    0.0,     "dbl sin(10.0)"},
  {l_sqrt,   -1.0,    0.0,     "dbl sqrt(-1) "},
  {NULL, NULL}
};

#define forcefpe() asm("wait")

static void 
dotests(void)
{
  const struct funcpair *volatile it;
  double res;

  it = funcs;
  while (it->func) {
    fprintf(stderr, "Function '%s'", it->descr);
    if (setjmp(jmpbuf) == 0) {
      res = it->func(it->p1, it->p2);
      forcefpe();
      fprintf(stderr, " survived, res: %g", res);
    }
    else {
      if (sig_fpe_was_here != 1) {
	fprintf(stderr,"Strange, %d exception after jongjmp\n"
		, sig_fpe_was_here);
	exit(2);
      }
      sig_fpe_was_here = 0;
      fprintf(stderr, " signal %d, code %-20s (%2d)"
	      , sig_sig
	      , codestring(sig_code)
	      , sig_code
	      );
    }
    fputc('\n', stderr);
    it++;
  }
}

int 
main(int argc, char *argv[])
{
  int oldmask;
  
  fprintf(stderr,"Round: %x, Precision: %x\n", fpgetround(), fpgetprec());

  oldmask = fpgetmask();
  signal(SIGFPE,(__sighandler_t *)handler);

  fprintf(stderr,"Testing with all exceptions enabled\n");
  fpsetmask(FP_X_INV|FP_X_DNML|FP_X_DZ|FP_X_OFL|FP_X_UFL|FP_X_IMP);
  dotests();

  fprintf(stderr,"Testing with all exceptions except precision loss\n");
  fpsetmask(FP_X_INV|FP_X_DNML|FP_X_DZ|FP_X_OFL|FP_X_UFL);
  dotests();

  fprintf(stderr,"Testing with exceptions disabled\n");
  fpsetmask(0L);
  dotests();

  fprintf(stderr,"Round: %x, Precision: %x\n", fpgetround(), fpgetprec());

  return 0;
}

--envbJBWh7q8WU6mo--

To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-current" in the body of the message



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?19980830175149.A22835>