# HG changeset patch # User Paul Boddie # Date 1548454364 -3600 # Node ID 6671fd0215a06e7295ffdf51e3e39e2092040050 # Parent ce0e10d3ad2fb8fdf06045c385536245c6a6752d Introduced signal usage, replacing fenv for floating point exception handling. diff -r ce0e10d3ad2f -r 6671fd0215a0 generator.py --- a/generator.py Fri Jan 25 14:17:30 2019 +0100 +++ b/generator.py Fri Jan 25 23:12:44 2019 +0100 @@ -192,6 +192,7 @@ #include #include #include "gc.h" +#include "signals.h" #include "types.h" #include "exceptions.h" #include "ops.h" @@ -1298,6 +1299,8 @@ GC_INIT(); + __signals_install_handlers(); + __Try {""" diff -r ce0e10d3ad2f -r 6671fd0215a0 templates/Makefile --- a/templates/Makefile Fri Jan 25 14:17:30 2019 +0100 +++ b/templates/Makefile Fri Jan 25 23:12:44 2019 +0100 @@ -2,7 +2,7 @@ include modules.mk include options.mk -SRC += calls.c exceptions.c main.c ops.c progops.c progtypes.c +SRC += calls.c exceptions.c main.c ops.c progops.c progtypes.c signals.c OBJ = $(SRC:.c=.o) CFLAGS += -Wall -Wno-maybe-uninitialized -I. -finput-charset=UTF-8 LDFLAGS += -lm -lgc diff -r ce0e10d3ad2f -r 6671fd0215a0 templates/native/float.c --- a/templates/native/float.c Fri Jan 25 14:17:30 2019 +0100 +++ b/templates/native/float.c Fri Jan 25 23:12:44 2019 +0100 @@ -16,7 +16,8 @@ this program. If not, see . */ -#include /* feclearexcept, fetestexcept */ +#include +#include #include /* pow */ #include /* snprintf */ #include /* errno */ @@ -66,32 +67,7 @@ /* Floating point exception handling. */ -static void init_env(fenv_t *envp, int excepts) -{ - fegetenv(envp); - feclearexcept(excepts); -} - -static int test_env(fenv_t *envp, int excepts) -{ - if (fetestexcept(excepts)) - { - fesetenv(envp); - return 1; - } - return 0; -} - -static int have_result(fenv_t *envp, int excepts) -{ - return !fetestexcept(excepts); -} - -static __attr make_result(fenv_t *envp, double result) -{ - fesetenv(envp); - return __new_float(result); -} +extern jmp_buf __fpe_env; /* Floating point operations. */ @@ -100,21 +76,17 @@ /* self and other interpreted as float */ double i = __TOFLOAT(self); double j = __TOFLOAT(other); - double result; - - /* Preserve environment, clear exception state. */ - fenv_t env; - init_env(&env, FE_OVERFLOW); - - result = i + j; + int signum; - /* Test for result, restore state, return the new float. */ - if (have_result(&env, FE_OVERFLOW)) - return make_result(&env, result); + /* Perform the operation while handling exceptions. */ + signum = setjmp(__fpe_env); + if (!signum) + return __new_float(i + j); - /* Restore state, raise exception. */ - if (test_env(&env, FE_OVERFLOW)) + /* Exception occurred. */ + if (signum == FPE_FLTOVF) __raise_overflow_error(); + return __NULL; } @@ -123,21 +95,17 @@ /* self and other interpreted as float */ double i = __TOFLOAT(self); double j = __TOFLOAT(other); - double result; - - /* Preserve environment, clear exception state. */ - fenv_t env; - init_env(&env, FE_OVERFLOW); - - result = i - j; + int signum; - /* Test for result, restore state, return the new float. */ - if (have_result(&env, FE_OVERFLOW)) - return make_result(&env, result); + /* Perform the operation while handling exceptions. */ + signum = setjmp(__fpe_env); + if (!signum) + return __new_float(i - j); - /* Restore state, raise exception. */ - if (test_env(&env, FE_OVERFLOW)) + /* Exception occurred. */ + if (signum == FPE_FLTOVF) __raise_overflow_error(); + return __NULL; } @@ -146,23 +114,19 @@ /* self and other interpreted as float */ double i = __TOFLOAT(self); double j = __TOFLOAT(other); - double result; + int signum; - /* Preserve environment, clear exception state. */ - fenv_t env; - init_env(&env, FE_OVERFLOW | FE_UNDERFLOW); - - result = i * j; + /* Perform the operation while handling exceptions. */ + signum = setjmp(__fpe_env); + if (!signum) + return __new_float(i * j); - /* Test for result, restore state, return the new float. */ - if (have_result(&env, FE_OVERFLOW | FE_UNDERFLOW)) - return make_result(&env, result); + /* Exception occurred. */ + if (signum == FPE_FLTOVF) + __raise_overflow_error(); + else if (signum == FPE_FLTUND) + __raise_underflow_error(); - /* Restore state, raise exception. */ - if (test_env(&env, FE_OVERFLOW)) - __raise_overflow_error(); - if (test_env(&env, FE_UNDERFLOW)) - __raise_underflow_error(); return __NULL; } @@ -171,25 +135,21 @@ /* self and other interpreted as float */ double i = __TOFLOAT(self); double j = __TOFLOAT(other); - double result; + int signum; - /* Preserve environment, clear exception state. */ - fenv_t env; - init_env(&env, FE_OVERFLOW | FE_UNDERFLOW | FE_DIVBYZERO); - - result = i / j; + /* Perform the operation while handling exceptions. */ + signum = setjmp(__fpe_env); + if (!signum) + return __new_float(i / j); - /* Test for result, restore state, return the new float. */ - if (have_result(&env, FE_OVERFLOW | FE_UNDERFLOW | FE_DIVBYZERO)) - return make_result(&env, result); + /* Exception occurred. */ + if (signum == FPE_FLTOVF) + __raise_overflow_error(); + else if (signum == FPE_FLTUND) + __raise_underflow_error(); + else if (signum == FPE_FLTDIV) + __raise_zero_division_error(); - /* Restore state, raise exception. */ - if (test_env(&env, FE_OVERFLOW)) - __raise_overflow_error(); - if (test_env(&env, FE_UNDERFLOW)) - __raise_underflow_error(); - if (test_env(&env, FE_DIVBYZERO)) - __raise_zero_division_error(); return __NULL; } @@ -198,23 +158,19 @@ /* self and other interpreted as float */ double i = __TOFLOAT(self); double j = __TOFLOAT(other); - double result; + int signum; - /* Preserve environment, clear exception state. */ - fenv_t env; - init_env(&env, FE_OVERFLOW | FE_DIVBYZERO); - - result = fmod(i, j); + /* Perform the operation while handling exceptions. */ + signum = setjmp(__fpe_env); + if (!signum) + return __new_float(fmod(i, j)); - /* Test for result, restore state, return the new float. */ - if (have_result(&env, FE_OVERFLOW | FE_DIVBYZERO)) - return make_result(&env, result); + /* Exception occurred. */ + if (signum == FPE_FLTOVF) + __raise_overflow_error(); + else if (signum == FPE_FLTDIV) + __raise_zero_division_error(); - /* Restore state, raise exception. */ - if (test_env(&env, FE_OVERFLOW)) - __raise_overflow_error(); - if (test_env(&env, FE_DIVBYZERO)) - __raise_zero_division_error(); return __NULL; } @@ -222,21 +178,17 @@ { /* self interpreted as float */ double i = __TOFLOAT(self); - double result; - - /* Preserve environment, clear exception state. */ - fenv_t env; - init_env(&env, FE_OVERFLOW); - - result = -i; + int signum; - /* Test for result, restore state, return the new float. */ - if (have_result(&env, FE_OVERFLOW)) - return make_result(&env, result); + /* Perform the operation while handling exceptions. */ + signum = setjmp(__fpe_env); + if (!signum) + return __new_float(-i); - /* Restore state, raise exception. */ - if (test_env(&env, FE_OVERFLOW)) + /* Exception occurred. */ + if (signum == FPE_FLTOVF) __raise_overflow_error(); + return __NULL; } diff -r ce0e10d3ad2f -r 6671fd0215a0 templates/signals.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/templates/signals.c Fri Jan 25 23:12:44 2019 +0100 @@ -0,0 +1,45 @@ +/* Signal handling. + +Copyright (C) 2019 Paul Boddie + +This program is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free Software +Foundation; either version 3 of the License, or (at your option) any later +version. + +This program is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +details. + +You should have received a copy of the GNU General Public License along with +this program. If not, see . +*/ + +#include +#include +#include + +#include "signals.h" + +void __signals_install_handlers() +{ + struct sigaction context; + + context.sa_flags = SA_SIGINFO; + context.sa_sigaction = __signals_fpe_handler; + sigemptyset(&context.sa_mask); + + /* NOTE: Should test for -1 and errno. */ + + sigaction(SIGFPE, &context, NULL); +} + +jmp_buf __fpe_env; + +void __signals_fpe_handler(int signum, siginfo_t *siginfo, void *context) +{ + /* Return from setjmp with the signal number. */ + + longjmp(__fpe_env, siginfo->si_code); +} diff -r ce0e10d3ad2f -r 6671fd0215a0 templates/signals.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/templates/signals.h Fri Jan 25 23:12:44 2019 +0100 @@ -0,0 +1,27 @@ +/* Signal handling. + +Copyright (C) 2019 Paul Boddie + +This program is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free Software +Foundation; either version 3 of the License, or (at your option) any later +version. + +This program is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +details. + +You should have received a copy of the GNU General Public License along with +this program. If not, see . +*/ + +#ifndef __SIGNALS_H__ +#define __SIGNALS_H__ + +#include + +void __signals_install_handlers(); +void __signals_fpe_handler(int signum, siginfo_t *siginfo, void *context); + +#endif /* __SIGNALS_H__ */