3.1 --- a/templates/native/float.c Fri Jan 25 14:17:30 2019 +0100
3.2 +++ b/templates/native/float.c Fri Jan 25 23:12:44 2019 +0100
3.3 @@ -16,7 +16,8 @@
3.4 this program. If not, see <http://www.gnu.org/licenses/>.
3.5 */
3.6
3.7 -#include <fenv.h> /* feclearexcept, fetestexcept */
3.8 +#include <setjmp.h>
3.9 +#include <signal.h>
3.10 #include <math.h> /* pow */
3.11 #include <stdio.h> /* snprintf */
3.12 #include <errno.h> /* errno */
3.13 @@ -66,32 +67,7 @@
3.14
3.15 /* Floating point exception handling. */
3.16
3.17 -static void init_env(fenv_t *envp, int excepts)
3.18 -{
3.19 - fegetenv(envp);
3.20 - feclearexcept(excepts);
3.21 -}
3.22 -
3.23 -static int test_env(fenv_t *envp, int excepts)
3.24 -{
3.25 - if (fetestexcept(excepts))
3.26 - {
3.27 - fesetenv(envp);
3.28 - return 1;
3.29 - }
3.30 - return 0;
3.31 -}
3.32 -
3.33 -static int have_result(fenv_t *envp, int excepts)
3.34 -{
3.35 - return !fetestexcept(excepts);
3.36 -}
3.37 -
3.38 -static __attr make_result(fenv_t *envp, double result)
3.39 -{
3.40 - fesetenv(envp);
3.41 - return __new_float(result);
3.42 -}
3.43 +extern jmp_buf __fpe_env;
3.44
3.45 /* Floating point operations. */
3.46
3.47 @@ -100,21 +76,17 @@
3.48 /* self and other interpreted as float */
3.49 double i = __TOFLOAT(self);
3.50 double j = __TOFLOAT(other);
3.51 - double result;
3.52 -
3.53 - /* Preserve environment, clear exception state. */
3.54 - fenv_t env;
3.55 - init_env(&env, FE_OVERFLOW);
3.56 -
3.57 - result = i + j;
3.58 + int signum;
3.59
3.60 - /* Test for result, restore state, return the new float. */
3.61 - if (have_result(&env, FE_OVERFLOW))
3.62 - return make_result(&env, result);
3.63 + /* Perform the operation while handling exceptions. */
3.64 + signum = setjmp(__fpe_env);
3.65 + if (!signum)
3.66 + return __new_float(i + j);
3.67
3.68 - /* Restore state, raise exception. */
3.69 - if (test_env(&env, FE_OVERFLOW))
3.70 + /* Exception occurred. */
3.71 + if (signum == FPE_FLTOVF)
3.72 __raise_overflow_error();
3.73 +
3.74 return __NULL;
3.75 }
3.76
3.77 @@ -123,21 +95,17 @@
3.78 /* self and other interpreted as float */
3.79 double i = __TOFLOAT(self);
3.80 double j = __TOFLOAT(other);
3.81 - double result;
3.82 -
3.83 - /* Preserve environment, clear exception state. */
3.84 - fenv_t env;
3.85 - init_env(&env, FE_OVERFLOW);
3.86 -
3.87 - result = i - j;
3.88 + int signum;
3.89
3.90 - /* Test for result, restore state, return the new float. */
3.91 - if (have_result(&env, FE_OVERFLOW))
3.92 - return make_result(&env, result);
3.93 + /* Perform the operation while handling exceptions. */
3.94 + signum = setjmp(__fpe_env);
3.95 + if (!signum)
3.96 + return __new_float(i - j);
3.97
3.98 - /* Restore state, raise exception. */
3.99 - if (test_env(&env, FE_OVERFLOW))
3.100 + /* Exception occurred. */
3.101 + if (signum == FPE_FLTOVF)
3.102 __raise_overflow_error();
3.103 +
3.104 return __NULL;
3.105 }
3.106
3.107 @@ -146,23 +114,19 @@
3.108 /* self and other interpreted as float */
3.109 double i = __TOFLOAT(self);
3.110 double j = __TOFLOAT(other);
3.111 - double result;
3.112 + int signum;
3.113
3.114 - /* Preserve environment, clear exception state. */
3.115 - fenv_t env;
3.116 - init_env(&env, FE_OVERFLOW | FE_UNDERFLOW);
3.117 -
3.118 - result = i * j;
3.119 + /* Perform the operation while handling exceptions. */
3.120 + signum = setjmp(__fpe_env);
3.121 + if (!signum)
3.122 + return __new_float(i * j);
3.123
3.124 - /* Test for result, restore state, return the new float. */
3.125 - if (have_result(&env, FE_OVERFLOW | FE_UNDERFLOW))
3.126 - return make_result(&env, result);
3.127 + /* Exception occurred. */
3.128 + if (signum == FPE_FLTOVF)
3.129 + __raise_overflow_error();
3.130 + else if (signum == FPE_FLTUND)
3.131 + __raise_underflow_error();
3.132
3.133 - /* Restore state, raise exception. */
3.134 - if (test_env(&env, FE_OVERFLOW))
3.135 - __raise_overflow_error();
3.136 - if (test_env(&env, FE_UNDERFLOW))
3.137 - __raise_underflow_error();
3.138 return __NULL;
3.139 }
3.140
3.141 @@ -171,25 +135,21 @@
3.142 /* self and other interpreted as float */
3.143 double i = __TOFLOAT(self);
3.144 double j = __TOFLOAT(other);
3.145 - double result;
3.146 + int signum;
3.147
3.148 - /* Preserve environment, clear exception state. */
3.149 - fenv_t env;
3.150 - init_env(&env, FE_OVERFLOW | FE_UNDERFLOW | FE_DIVBYZERO);
3.151 -
3.152 - result = i / j;
3.153 + /* Perform the operation while handling exceptions. */
3.154 + signum = setjmp(__fpe_env);
3.155 + if (!signum)
3.156 + return __new_float(i / j);
3.157
3.158 - /* Test for result, restore state, return the new float. */
3.159 - if (have_result(&env, FE_OVERFLOW | FE_UNDERFLOW | FE_DIVBYZERO))
3.160 - return make_result(&env, result);
3.161 + /* Exception occurred. */
3.162 + if (signum == FPE_FLTOVF)
3.163 + __raise_overflow_error();
3.164 + else if (signum == FPE_FLTUND)
3.165 + __raise_underflow_error();
3.166 + else if (signum == FPE_FLTDIV)
3.167 + __raise_zero_division_error();
3.168
3.169 - /* Restore state, raise exception. */
3.170 - if (test_env(&env, FE_OVERFLOW))
3.171 - __raise_overflow_error();
3.172 - if (test_env(&env, FE_UNDERFLOW))
3.173 - __raise_underflow_error();
3.174 - if (test_env(&env, FE_DIVBYZERO))
3.175 - __raise_zero_division_error();
3.176 return __NULL;
3.177 }
3.178
3.179 @@ -198,23 +158,19 @@
3.180 /* self and other interpreted as float */
3.181 double i = __TOFLOAT(self);
3.182 double j = __TOFLOAT(other);
3.183 - double result;
3.184 + int signum;
3.185
3.186 - /* Preserve environment, clear exception state. */
3.187 - fenv_t env;
3.188 - init_env(&env, FE_OVERFLOW | FE_DIVBYZERO);
3.189 -
3.190 - result = fmod(i, j);
3.191 + /* Perform the operation while handling exceptions. */
3.192 + signum = setjmp(__fpe_env);
3.193 + if (!signum)
3.194 + return __new_float(fmod(i, j));
3.195
3.196 - /* Test for result, restore state, return the new float. */
3.197 - if (have_result(&env, FE_OVERFLOW | FE_DIVBYZERO))
3.198 - return make_result(&env, result);
3.199 + /* Exception occurred. */
3.200 + if (signum == FPE_FLTOVF)
3.201 + __raise_overflow_error();
3.202 + else if (signum == FPE_FLTDIV)
3.203 + __raise_zero_division_error();
3.204
3.205 - /* Restore state, raise exception. */
3.206 - if (test_env(&env, FE_OVERFLOW))
3.207 - __raise_overflow_error();
3.208 - if (test_env(&env, FE_DIVBYZERO))
3.209 - __raise_zero_division_error();
3.210 return __NULL;
3.211 }
3.212
3.213 @@ -222,21 +178,17 @@
3.214 {
3.215 /* self interpreted as float */
3.216 double i = __TOFLOAT(self);
3.217 - double result;
3.218 -
3.219 - /* Preserve environment, clear exception state. */
3.220 - fenv_t env;
3.221 - init_env(&env, FE_OVERFLOW);
3.222 -
3.223 - result = -i;
3.224 + int signum;
3.225
3.226 - /* Test for result, restore state, return the new float. */
3.227 - if (have_result(&env, FE_OVERFLOW))
3.228 - return make_result(&env, result);
3.229 + /* Perform the operation while handling exceptions. */
3.230 + signum = setjmp(__fpe_env);
3.231 + if (!signum)
3.232 + return __new_float(-i);
3.233
3.234 - /* Restore state, raise exception. */
3.235 - if (test_env(&env, FE_OVERFLOW))
3.236 + /* Exception occurred. */
3.237 + if (signum == FPE_FLTOVF)
3.238 __raise_overflow_error();
3.239 +
3.240 return __NULL;
3.241 }
3.242
4.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
4.2 +++ b/templates/signals.c Fri Jan 25 23:12:44 2019 +0100
4.3 @@ -0,0 +1,45 @@
4.4 +/* Signal handling.
4.5 +
4.6 +Copyright (C) 2019 Paul Boddie <paul@boddie.org.uk>
4.7 +
4.8 +This program is free software; you can redistribute it and/or modify it under
4.9 +the terms of the GNU General Public License as published by the Free Software
4.10 +Foundation; either version 3 of the License, or (at your option) any later
4.11 +version.
4.12 +
4.13 +This program is distributed in the hope that it will be useful, but WITHOUT
4.14 +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
4.15 +FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
4.16 +details.
4.17 +
4.18 +You should have received a copy of the GNU General Public License along with
4.19 +this program. If not, see <http://www.gnu.org/licenses/>.
4.20 +*/
4.21 +
4.22 +#include <setjmp.h>
4.23 +#include <signal.h>
4.24 +#include <stdlib.h>
4.25 +
4.26 +#include "signals.h"
4.27 +
4.28 +void __signals_install_handlers()
4.29 +{
4.30 + struct sigaction context;
4.31 +
4.32 + context.sa_flags = SA_SIGINFO;
4.33 + context.sa_sigaction = __signals_fpe_handler;
4.34 + sigemptyset(&context.sa_mask);
4.35 +
4.36 + /* NOTE: Should test for -1 and errno. */
4.37 +
4.38 + sigaction(SIGFPE, &context, NULL);
4.39 +}
4.40 +
4.41 +jmp_buf __fpe_env;
4.42 +
4.43 +void __signals_fpe_handler(int signum, siginfo_t *siginfo, void *context)
4.44 +{
4.45 + /* Return from setjmp with the signal number. */
4.46 +
4.47 + longjmp(__fpe_env, siginfo->si_code);
4.48 +}
5.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
5.2 +++ b/templates/signals.h Fri Jan 25 23:12:44 2019 +0100
5.3 @@ -0,0 +1,27 @@
5.4 +/* Signal handling.
5.5 +
5.6 +Copyright (C) 2019 Paul Boddie <paul@boddie.org.uk>
5.7 +
5.8 +This program is free software; you can redistribute it and/or modify it under
5.9 +the terms of the GNU General Public License as published by the Free Software
5.10 +Foundation; either version 3 of the License, or (at your option) any later
5.11 +version.
5.12 +
5.13 +This program is distributed in the hope that it will be useful, but WITHOUT
5.14 +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
5.15 +FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
5.16 +details.
5.17 +
5.18 +You should have received a copy of the GNU General Public License along with
5.19 +this program. If not, see <http://www.gnu.org/licenses/>.
5.20 +*/
5.21 +
5.22 +#ifndef __SIGNALS_H__
5.23 +#define __SIGNALS_H__
5.24 +
5.25 +#include <signal.h>
5.26 +
5.27 +void __signals_install_handlers();
5.28 +void __signals_fpe_handler(int signum, siginfo_t *siginfo, void *context);
5.29 +
5.30 +#endif /* __SIGNALS_H__ */