/* * stress_sigfpe * stress by generating floating point errors */ int stress_sigfpe( uint64_t *const counter, const uint32_t instance, const uint64_t max_ops, const char *name) { (void)instance; for (;;) { struct sigaction new_action; int ret; memset(&new_action, 0, sizeof new_action); new_action.sa_handler = stress_fpehandler; sigemptyset(&new_action.sa_mask); new_action.sa_flags = 0; if (sigaction(SIGFPE, &new_action, NULL) < 0) { pr_failed_err(name, "sigfpe"); return EXIT_FAILURE; } ret = sigsetjmp(jmp_env, 1); /* * We return here if we get SIGFPE, so * first check if we need to terminate */ if (!opt_do_run || (max_ops && *counter >= max_ops)) break; if (ret) (*counter)++; /* SIGFPE occurred */ else uint64_put(1 / uint64_zero()); /* force division by zero */ } return EXIT_SUCCESS; }
/* * stress_sigfpe * stress by generating floating point errors */ static int stress_sigfpe(const args_t *args) { struct sigaction action; static int i = 0; int ret; const uint64_t zero = stress_uint64_zero(); typedef struct { int exception; int err_code; } fpe_err_t; /* * FPE errors to raise */ static const fpe_err_t fpe_errs[] = { #if defined(FPE_INTDIV) { SNG_INTDIV, FPE_INTDIV }, #endif #if defined(FPE_FLTDIV) { SNG_FLTDIV, FPE_FLTDIV }, #endif #if defined(FE_DIVBYZERO) && defined(FPE_FLTDIV) { FE_DIVBYZERO, FPE_FLTDIV }, #endif #if defined(FE_INEXACT) && defined(FPE_FLTRES) { FE_INEXACT, FPE_FLTRES }, #endif #if defined(FE_INVALID) && defined(FPE_FLTINV) { FE_INVALID, FPE_FLTINV }, #endif #if defined(FE_OVERFLOW) && defined(FPE_FLTOVF) { FE_OVERFLOW, FPE_FLTOVF }, #endif #if defined(FE_UNDERFLOW) && defined(FPE_FLTUND) { FE_UNDERFLOW, FPE_FLTUND }, #endif }; (void)memset(&action, 0, sizeof action); #if defined(SA_SIGINFO) action.sa_sigaction = stress_fpehandler; #else action.sa_handler = stress_fpehandler; #endif (void)sigemptyset(&action.sa_mask); #if defined(SA_SIGINFO) action.sa_flags = SA_SIGINFO; #endif ret = sigaction(SIGFPE, &action, NULL); if (ret < 0) { pr_fail("%s: sigaction SIGFPE: errno=%d (%s)\n", args->name, errno, strerror(errno)); return EXIT_FAILURE; } for (;;) { #if defined(SA_SIGINFO) static int expected_err_code; int code; #endif int exception; #if defined(SA_SIGINFO) code = fpe_errs[i].err_code; expected_err_code = code; #endif exception = fpe_errs[i].exception; ret = sigsetjmp(jmp_env, 1); /* * We return here if we get SIGFPE, so * first check if we need to terminate */ if (!keep_stressing()) break; if (ret) { /* * A SIGFPE occurred, check the error code * matches the expected code */ (void)feclearexcept(FE_ALL_EXCEPT); #if defined(SA_SIGINFO) if ((g_opt_flags & OPT_FLAGS_VERIFY) && (siginfo.si_code >= 0) && (siginfo.si_code != expected_err_code)) { pr_fail("%s: got SIGFPE error %d (%s), expecting %d (%s)\n", args->name, siginfo.si_code, stress_sigfpe_errstr(siginfo.si_code), expected_err_code, stress_sigfpe_errstr(expected_err_code)); } #endif inc_counter(args); } else { #if defined(SA_SIGINFO) siginfo.si_code = 0; #endif switch(exception) { case SNG_FLTDIV: float_put(1.0 / (float)zero); break; case SNG_INTDIV: uint64_put(1 / zero); break; default: /* Raise fault otherwise */ (void)feraiseexcept(exception); break; } } i++; i %= SIZEOF_ARRAY(fpe_errs); } (void)feclearexcept(FE_ALL_EXCEPT); return EXIT_SUCCESS; }