www.delorie.com/archives/browse.cgi   search  
Mail Archives: djgpp-workers/1999/05/06/06:38:17

Date: Thu, 6 May 1999 13:36:01 +0300 (IDT)
From: Eli Zaretskii <eliz AT is DOT elta DOT co DOT il>
X-Sender: eliz AT is
To: djgpp-workers AT delorie DOT com
Subject: More x87 weirdness
Message-ID: <Pine.SUN.3.91.990506131239.15114C@is>
MIME-Version: 1.0
Reply-To: djgpp-workers AT delorie DOT com

While testing stability of multiple exceptions fired at high rates, I've 
bumped into a strange phenomenon.  Perhaps somebody could help me 
understand what goes on and maybe correct a bug.

It seems that some complex condition causes x87 to stop generating FP
exceptions after some time (during which a lot of exceptions are fired),
even though its control word unmasks them.  Using a test program, I
verified that both the control word and the SIGFPE handler are set
correctly, even after the FP exceptions stop.  Nevertheless, calling e.g. 
"log(-1)" doesn't crash the program, but prints -Inf instead, as if the 
exception were masked.

Is there something else, apart of the control word, that should be set up
to ensure FP exceptions are generated?  I cannot find anything in the
references I have.  (The CPU is a P-166, if that matters.)  Since the 
control word is okay, I don't know what to look for to debug this.

A simple test program is attached below.  It sets things up so that
SIGALRM is raised every 100 msec, and generates FP exceptions at even 
higher rate.  You can also press and hold Ctrl-C or Ctrl-\, to add some 
more signals for a good measure.  In addition, I compile it with -pg, so 
the profiling code also fires exceptions every 55 msec.

Now, for some reason, after the program runs for some time (like several
minutes), it stops reporting SIGFPEs.  If I press the capital `T' (which
calls `_clear87'), SIGFPEs resume again.  The interesting thing is that,
if you press `q' when the SIGFPEs aren't reported, the program reports a
control word that clearly indicates the Divide-by-zero and
Invalid-operation exceptions are unmasked, and yet a log of a negative
number doesn't raise an exception! 

Here's the test program.  Note that if you want to build it with stock 
v2.02, you need a patched itimer.c.  Also, don't press Ctrl-C and Ctrl-\ 
too much, or it will crash (this is fixed by the change in exceptn.S that 
I posted a couple of days ago).  Usually, leaving the program to run for 
several minutes will be enough to get into the state where SIGFPEs stop 
(just go for a coffee or something).

------------------------------------------------------------------------
#include <sys/time.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <setjmp.h>
#include <math.h>
#include <float.h>
#include <pc.h>
#include <dpmi.h>

int tick;
void sig_handler(int);

volatile int result;
void int_handler(int sig)
{
  double urand;

  if (sig != SIGINT)
    abort();
  puts ("\tSIGINT");
  urand = ((double)rand()) / RAND_MAX;
  if (urand > 0.5)
    result = urand / (rand() < 0);
  else
    result = sqrt (-1. / urand);
}

void quit_handler(int sig)
{
  if (sig != SIGQUIT)
    abort();
  puts ("\t\tSIGQUIT");
}

jmp_buf jb;
void fpe_handler(int sig)
{
  _clear87();
  if (sig != SIGFPE)
    abort();
  puts ("\t\t\tSIGFPE");
  longjmp(jb, 1);
}

int main(void)
{
  struct itimerval t;
  int c;

  t.it_interval.tv_sec = 0;
  t.it_interval.tv_usec =100;
  t.it_value.tv_sec = 0;
  t.it_value.tv_usec = 100; 
  signal(SIGALRM, sig_handler);
  setitimer(ITIMER_REAL, &t, NULL);
  signal (SIGINT, int_handler);
  signal (SIGQUIT, quit_handler);
  if (!setjmp(jb))
    signal (SIGFPE, fpe_handler);
  _control87(0x033a, 0xffff);	/* unmask zero-divide and invalid-op */
  c = 0;
  while(!kbhit() || (c = getkey()) != 'q')
    {
      printf("Tick %d\n", tick);
      if (c == 'A')
	{
	  signal (SIGINT, SIG_DFL);
	}
      else if (c == 'T')
	{
	  _clear87();
	}
      else if ((tick % 5) == 0 || (tick % 11) == 0 || (tick % 23) == 0)
	{
	  result = (M_PI + tick) / (tick < 0) + sqrt (M_PI - tick);
	}
      c = 0;
    }
  printf ("x87 CW: 0x%x\n", _control87(0, 0));
  printf ("SIGFPE handler: 0x%p (should be 0x%p)\n",
	  signal(SIGFPE, SIG_DFL), fpe_handler);
  printf ("log of a negative number is %f\n", log(-1.0*tick));
  abort();
  return 0;
}	
void sig_handler(int signum)
{
  tick++;
}

- Raw text -


  webmaster     delorie software   privacy  
  Copyright © 2019   by DJ Delorie     Updated Jul 2019