Date: Thu, 6 May 1999 13:36:01 +0300 (IDT) From: Eli Zaretskii X-Sender: eliz AT is To: djgpp-workers AT delorie DOT com Subject: More x87 weirdness Message-ID: MIME-Version: 1.0 Content-Type: TEXT/PLAIN; charset=US-ASCII 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 #include #include #include #include #include #include #include #include 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++; }