You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

178 lines
4.2 KiB

/*
* Copyright 2002-2019 Intel Corporation.
*
* This software is provided to you as Sample Source Code as defined in the accompanying
* End User License Agreement for the Intel(R) Software Development Products ("Agreement")
* section 1.L.
*
* This software and the related documents are provided as is, with no express or implied
* warranties, other than those that are expressly stated in the License.
*/
/*
* This test verifies that Pin properly saves and restores the applicaton's
* FP state when emulating a delivered signal. The application's main thread
* simply does some FP calculation in a loop while ALRM signals are handled.
* The signal handler also does some FP computation, which will change the
* FP state. If Pin doesn't properly save/restore the FP state, the handler
* will mess up the main thread's calculations.
*
*********************************************************************************
*
* I have observed that this test occasionally fails on vs-lin64-4 (running SUSE10
* on Intel64). The cause of the problem is probably the same as the bug
* described at the top of "xmmcheck.c".
*/
#include <stdlib.h>
#include <math.h>
#include <stdio.h>
#include <string.h>
#include <signal.h>
#include <sys/time.h>
#define COUNT 100
volatile unsigned SigCount = 0;
static double fpcheck();
static void handle1(int);
static void handle2(int, siginfo_t *, void *);
int main()
{
struct sigaction sigact;
struct itimerval itval;
double fact;
char buf[100];
char *point;
printf("Before sigaction call\n");
sigact.sa_handler = handle1;
sigact.sa_flags = 0;
sigemptyset(&sigact.sa_mask);
if (sigaction(SIGALRM, &sigact, 0) == -1)
{
fprintf(stderr, "Unable to set up handler\n");
return 1;
}
printf("Before setitimer\n");
itval.it_interval.tv_sec = 0;
itval.it_interval.tv_usec = 10000;
itval.it_value.tv_sec = 0;
itval.it_value.tv_usec = 10000;
if (setitimer(ITIMER_REAL, &itval, 0) == -1)
{
fprintf(stderr, "Unable to set up timer\n");
return 1;
}
printf("Before fpcheck\n");
fact = fpcheck();
printf("After fpcheck\n");
itval.it_value.tv_sec = 0;
itval.it_value.tv_usec = 0;
if (setitimer(ITIMER_REAL, &itval, 0) == -1)
{
fprintf(stderr, "Unable to disable timer\n");
return 1;
}
sprintf(buf, "%.0f", fact);
point = strchr(buf, '.');
if (point)
*point = '\0';
if (strcmp(buf, "1307674368000") != 0)
{
fprintf(stderr, "15! should be 1307674368000, but computed as '%s'\n", buf);
return 1;
}
printf("15! = %s\n", buf);
return 0;
}
static double fpcheck()
{
double x[15];
double fact, calc;
unsigned i;
for (i = 1; i <= 15; i++)
x[i-1] = (double)i;
fact = 1.0;
for (i = 0; i < 15; i++)
fact = fact * x[15 - (i+1)];
while (SigCount < COUNT)
{
calc = 1.0;
for (i = 0; i < 15; i++)
calc = calc * x[15 - (i+1)];
if ((calc - fact > 0.5) || (calc - fact < -0.5))
{
fprintf(stderr, "Unexpected FP change (fact=%f, calc=%f)\n", fact, calc);
return 1;
}
}
return fact;
}
static void handle1(int sig)
{
SigCount++;
double x[100];
unsigned i;
fprintf(stderr, "handle1: %d\n", SigCount);
for (i = 0; i < 100; i++)
x[i] = (double)(i+1);
for (i = 2; i < 100; i++)
x[i] = x[i] / x[i-1] * x[i-2] + x[i];
/*
* After a while, switch to using a "siginfo" handler. This exercises different
* signal emulation paths within Pin.
*/
if (SigCount > COUNT/2)
{
struct sigaction sigact;
sigact.sa_sigaction = handle2;
sigact.sa_flags = SA_SIGINFO;
sigemptyset(&sigact.sa_mask);
if (sigaction(SIGALRM, &sigact, 0) == -1)
{
fprintf(stderr, "Unable to reset handler\n");
exit(1);
}
}
}
static void handle2(int sig, siginfo_t *si, void *v)
{
double x[100];
unsigned i;
SigCount++;
fprintf(stderr, "handle1: %d\n", SigCount);
for (i = 0; i < 100; i++)
x[i] = (double)(i+1);
for (i = 2; i < 100; i++)
x[i] = x[i] / x[i-1] * x[i-2] + x[i];
}