From 9559d5013ae5073ff5b435ddd42a38e1575ce21c Mon Sep 17 00:00:00 2001
From: Lukas Nellen <lukas@nucleares.unam.mx>
Date: Tue, 15 Jan 2019 00:38:47 -0600
Subject: [PATCH] Linux / OSX portable floating point exception enable/disable

---
 Documentation/Examples/cascade_example.cc |  3 +-
 Framework/Utilities/CMakeLists.txt        | 13 +++-
 Framework/Utilities/CorsikaFenv.cc        | 90 +++++++++++++++++++++++
 Framework/Utilities/CorsikaFenv.h         | 35 +++++++++
 Framework/Utilities/testCorsikaFenv.cc    | 33 +++++++++
 5 files changed, 171 insertions(+), 3 deletions(-)
 create mode 100644 Framework/Utilities/CorsikaFenv.cc
 create mode 100644 Framework/Utilities/CorsikaFenv.h
 create mode 100644 Framework/Utilities/testCorsikaFenv.cc

diff --git a/Documentation/Examples/cascade_example.cc b/Documentation/Examples/cascade_example.cc
index 2ca239e5..8e21990c 100644
--- a/Documentation/Examples/cascade_example.cc
+++ b/Documentation/Examples/cascade_example.cc
@@ -31,10 +31,11 @@
 
 #include <corsika/random/RNGManager.h>
 
+#include <corsika/utl/CorsikaFenv.h>
+
 #include <boost/type_index.hpp>
 using boost::typeindex::type_id_with_cvr;
 
-#include <fenv.h>
 #include <iostream>
 #include <limits>
 #include <typeinfo>
diff --git a/Framework/Utilities/CMakeLists.txt b/Framework/Utilities/CMakeLists.txt
index 5b21e927..4f68582b 100644
--- a/Framework/Utilities/CMakeLists.txt
+++ b/Framework/Utilities/CMakeLists.txt
@@ -2,13 +2,14 @@
 set (
   UTILITIES_SOURCES  
   COMBoost.cc
-  )
+  CorsikaFenv.cc)
 
 set (
   UTILITIES_HEADERS
   COMBoost.h
   Bit.h
   Singleton.h
+  CorsikaFenv.h
   )
 
 set (
@@ -58,5 +59,13 @@ target_link_libraries (
   CORSIKAutilities
   CORSIKAthirdparty # for catch2
   )
-CORSIKA_ADD_TEST(testCOMBoost)
 
+add_executable (testCorsikaFenv testCorsikaFenv.cc)
+
+target_link_libraries (
+  testCorsikaFenv
+  CORSIKAutilities
+  CORSIKAthirdparty # for catch2
+)
+CORSIKA_ADD_TEST(testCOMBoost)
+add_test(testCorsikaFenv testCorsikaFenv)
diff --git a/Framework/Utilities/CorsikaFenv.cc b/Framework/Utilities/CorsikaFenv.cc
new file mode 100644
index 00000000..145adb47
--- /dev/null
+++ b/Framework/Utilities/CorsikaFenv.cc
@@ -0,0 +1,90 @@
+/**
+ * (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu
+ *
+ * See file AUTHORS for a list of contributors.
+ *
+ * This software is distributed under the terms of the GNU General Public
+ * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
+ * the license.
+ *
+ * Provide portable or fallback versions of feenableexcept() and fedisableexcept()
+ * Exist by default in glibc since version 2.2, but not in the standard
+ * fenv.h / cfenv headers for C 99 or C++ 11
+ *
+ * \author Lukas Nellen
+ * \date 14 Jan 2019
+ *
+ */
+
+#include <corsika/utl/CorsikaFenv.h>
+#include <cfenv>
+
+#if defined(__GLIBC__)
+// do nothing functions exist
+
+#elif defined(__APPLE__) && defined(__MACH__)
+// Implementation of OS X on intel X64_86
+// code from https://stackoverflow.com/questions/37819235/how-do-you-enable-floating-point-exceptions-for-clang-in-os-x
+// based on http://www-personal.umich.edu/~williams/archive/computation/fe-handling-example.c
+
+extern "C" {
+
+  int
+  feenableexcept(int excepts) {
+    static fenv_t fenv;
+    int new_excepts = excepts & FE_ALL_EXCEPT;
+    // previous masks
+    int old_excepts;
+
+    if (fegetenv(&fenv)) {
+      return -1;
+    }
+    old_excepts = fenv.__control & FE_ALL_EXCEPT;
+
+    // unmask
+    fenv.__control &= ~new_excepts;
+    fenv.__mxcsr &= ~(new_excepts << 7);
+
+    return fesetenv(&fenv) ? -1 : old_excepts;
+  }
+
+  int
+  fedisableexcept(int excepts) {
+    static fenv_t fenv;
+    int new_excepts = excepts & FE_ALL_EXCEPT;
+    // all previous masks
+    int old_excepts;
+
+    if (fegetenv(&fenv)) {
+      return -1;
+    }
+    old_excepts = fenv.__control & FE_ALL_EXCEPT;
+
+    // mask
+    fenv.__control |= new_excepts;
+    fenv.__mxcsr |= new_excepts << 7;
+
+    return fesetenv(&fenv) ? -1 : old_excepts;
+  }
+
+}
+
+#else
+// unknown environment, dummy implementations
+
+extern "C" {
+#warning No enabling/disabling of floating point exceptions
+
+  int feenableexcept(int excepts)
+  {
+    return -1;
+  }
+
+  int fedisableexcept(int excepts)
+  {
+    return -1;
+  }
+
+}
+
+#endif
diff --git a/Framework/Utilities/CorsikaFenv.h b/Framework/Utilities/CorsikaFenv.h
new file mode 100644
index 00000000..eeaecef9
--- /dev/null
+++ b/Framework/Utilities/CorsikaFenv.h
@@ -0,0 +1,35 @@
+/**
+ * (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu
+ *
+ * See file AUTHORS for a list of contributors.
+ *
+ * This software is distributed under the terms of the GNU General Public
+ * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
+ * the license.
+ *
+ * Provide portable or fallback versions of feenableexcept() and fedisableexcept()
+ * Exist by default in glibc since version 2.2, but not in the standard
+ * fenv.h / cfenv headers for C 99 or C++ 11
+ *
+ * \author Lukas Nellen
+ * \date 14 Jan 2019
+ *
+ */
+
+#ifndef CORSIKA_CORSIKAFENV_H
+#define CORSIKA_CORSIKAFENV_H
+
+#include <cfenv>
+
+#if !defined(__GLIBC__)
+extern "C" {
+
+  int
+  feenableexcept(int excepts);
+  int
+  fedisableexcept(int excepts);
+
+}
+#endif
+
+#endif //CORSIKA_CORSIKAFENV_H
diff --git a/Framework/Utilities/testCorsikaFenv.cc b/Framework/Utilities/testCorsikaFenv.cc
new file mode 100644
index 00000000..9cae9469
--- /dev/null
+++ b/Framework/Utilities/testCorsikaFenv.cc
@@ -0,0 +1,33 @@
+/**
+ * (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu
+ *
+ * See file AUTHORS for a list of contributors.
+ *
+ * This software is distributed under the terms of the GNU General Public
+ * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
+ * the license.
+ */
+
+#include <corsika/utl/CorsikaFenv.h>
+
+#include <cmath>
+#include <iostream>
+#include <csignal>
+
+extern "C" {
+  static void
+  handle_fpe(int /*signo*/ ) {
+    exit(0);
+  }
+}
+
+
+int
+main() {
+  feenableexcept(FE_ALL_EXCEPT);
+  signal(SIGFPE, handle_fpe);
+
+  std::cout << std::log(0.) << std::endl;
+
+  exit(1);
+}
\ No newline at end of file
-- 
GitLab