Lichen

Changeset

872:6671fd0215a0
2019-01-25 Paul Boddie raw files shortlog changelog graph Introduced signal usage, replacing fenv for floating point exception handling. trailing-data
generator.py (file) templates/Makefile (file) templates/native/float.c (file) templates/signals.c (file) templates/signals.h (file)
     1.1 --- a/generator.py	Fri Jan 25 14:17:30 2019 +0100
     1.2 +++ b/generator.py	Fri Jan 25 23:12:44 2019 +0100
     1.3 @@ -192,6 +192,7 @@
     1.4  #include <string.h>
     1.5  #include <stdio.h>
     1.6  #include "gc.h"
     1.7 +#include "signals.h"
     1.8  #include "types.h"
     1.9  #include "exceptions.h"
    1.10  #include "ops.h"
    1.11 @@ -1298,6 +1299,8 @@
    1.12  
    1.13      GC_INIT();
    1.14  
    1.15 +    __signals_install_handlers();
    1.16 +
    1.17      __Try
    1.18      {"""
    1.19  
     2.1 --- a/templates/Makefile	Fri Jan 25 14:17:30 2019 +0100
     2.2 +++ b/templates/Makefile	Fri Jan 25 23:12:44 2019 +0100
     2.3 @@ -2,7 +2,7 @@
     2.4  include modules.mk
     2.5  include options.mk
     2.6  
     2.7 -SRC += calls.c exceptions.c main.c ops.c progops.c progtypes.c
     2.8 +SRC += calls.c exceptions.c main.c ops.c progops.c progtypes.c signals.c
     2.9  OBJ = $(SRC:.c=.o)
    2.10  CFLAGS += -Wall -Wno-maybe-uninitialized -I. -finput-charset=UTF-8
    2.11  LDFLAGS += -lm -lgc
     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__ */