1 // -*- C++ -*- 2 // Exception.h: Exceptions used by Asap 3 // 4 // Copyright (C) 2001-2011 Jakob Schiotz and Center for Individual 5 // Nanoparticle Functionality, Department of Physics, Technical 6 // University of Denmark. Email: schiotz@fysik.dtu.dk 7 // 8 // This file is part of Asap version 3. 9 // Asap is released under the GNU Lesser Public License (LGPL) version 3. 10 // However, the parts of Asap distributed within the OpenKIM project 11 // (including this file) are also released under the Common Development 12 // and Distribution License (CDDL) version 1.0. 13 // 14 // This program is free software: you can redistribute it and/or 15 // modify it under the terms of the GNU Lesser General Public License 16 // version 3 as published by the Free Software Foundation. Permission 17 // to use other versions of the GNU Lesser General Public License may 18 // granted by Jakob Schiotz or the head of department of the 19 // Department of Physics, Technical University of Denmark, as 20 // described in section 14 of the GNU General Public License. 21 // 22 // This program is distributed in the hope that it will be useful, 23 // but WITHOUT ANY WARRANTY; without even the implied warranty of 24 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 25 // GNU General Public License for more details. 26 // 27 // You should have received a copy of the GNU General Public License 28 // and the GNU Lesser Public License along with this program. If not, 29 // see <http://www.gnu.org/licenses/>. 30 31 32 // DESIGN NOTE: 33 // ============ 34 // 35 // Error conditions in Asap are usually handled by throwing an AsapError 36 // exception. This exception is caught by the Python Interface methods, 37 // and converted to a Python exception. If errors are generated by Python 38 // in Python calls from Asap, the Python error condition is left in place, 39 // and the C++ code throws an AsapPythonError. This error is also caught 40 // by the Python Interface methods, but in this case the preexisting Python 41 // error condition is left unchanged, and the error condition is reported 42 // back to Python. This results in slightly strange tracebacks, as the 43 // path through the C++ code will be missing. A subclass of AsapPythonError 44 // is AsapNotImplementedError, which is thrown without a corresponding 45 // Python error, and converted into Python's NotImplementedError. Finally, 46 // assert statements can be changed to emit an AssertionFailed error that is 47 // also turned into a Python AssertionFailed error. This latter behaviour 48 // is normally disabled, and is totally incompatible with OpenMP. 49 // 50 // OpenMP note: OpenMP place so severe restrictions on throwing exceptions 51 // inside parallel sections that exceptions become almost useless, even if 52 // parallelism is disabled at runtime. Asap handles this by replacing the 53 // throw statement with a THROW() macro inside OpenMP enabled regions. If 54 // compiled without OpenMP support, this macro just expands to the throw 55 // statement. If OpenMP is enabled, it instead expands to a helper function 56 // that just stores the exception in a global variable. Subsequent function 57 // calls are then supposed to return immediately (thanks to the 58 // RETURNIFASAPERROR macro in the beginning of the functions) until control 59 // leaves the parallel section, and the exception is thrown by the 60 // PROPAGATEASAPERROR macro. These latter macros are empty if OpenMP is 61 // not enabled at compile time. 62 63 64 #ifndef _EXCEPTION_H 65 #define _EXCEPTION_H 66 67 #include "Asap.h" 68 #include <sstream> 69 #include <iostream> 70 #ifndef ASAPASSERT 71 #include <assert.h> 72 #include <exception> 73 #endif // ASAPASSERT 74 75 using std::stringstream; 76 using std::string; 77 78 #ifndef _NOEXCEPT 79 #define _NOEXCEPT throw() 80 #endif 81 82 namespace ASAPSPACE { 83 84 // this AsapError class can be used as follows: 85 // 86 // throw AsapError("Error"); 87 // 88 // throw AsapError("Error ") << n + 7 << " while opening file: " << filename; 89 90 class ASAP_PUBLIC AsapErrorBase : std::exception 91 { 92 public: ~AsapErrorBase()93 virtual ~AsapErrorBase() _NOEXCEPT {}; 94 }; 95 96 class ASAP_PUBLIC AsapError : public AsapErrorBase 97 { 98 public: 99 AsapError(const char *m); 100 AsapError(const AsapError& ex); ~AsapError()101 virtual ~AsapError() _NOEXCEPT {}; 102 template<class T> AsapError& operator<<(const T& x) 103 { 104 message << x; 105 return *this; 106 } 107 string GetMessage() const; 108 private: 109 stringstream message; 110 }; 111 112 /// An exception for indicating that a Python error has occurred and 113 /// should be propagated. 114 class ASAP_PUBLIC AsapPythonError : public AsapErrorBase 115 { 116 public: AsapPythonError()117 AsapPythonError() {}; ~AsapPythonError()118 virtual ~AsapPythonError() _NOEXCEPT {}; 119 }; 120 121 #ifdef ASAP_FOR_KIM 122 // This definition is used when an ASAP potential is exported to OpenKIM, 123 // where there is no Python. 124 class ASAP_PUBLIC AsapNotImplementedError : public AsapError 125 { 126 public: AsapNotImplementedError(const char * m)127 AsapNotImplementedError(const char *m) : AsapError(m) {}; 128 }; 129 #else // ASAP_FOR_KIM 130 // The NORMAL version is here ! 131 /// An exception mapping to a Python NotImplementedError 132 class ASAP_PUBLIC AsapNotImplementedError : public AsapPythonError 133 { 134 public: 135 AsapNotImplementedError(const char *m); 136 }; 137 #endif //ASAP_FOR_KIM 138 139 class ASAP_PUBLIC AssertionFailed : public AsapErrorBase 140 { 141 public: 142 AssertionFailed(const char *expression, const char *file, int line, 143 const char *func = NULL); 144 AssertionFailed(const AssertionFailed& ex); ~AssertionFailed()145 ~AssertionFailed() _NOEXCEPT {}; 146 string GetMessage() const; 147 private: 148 stringstream message; 149 }; 150 151 /// A helper define 152 #define NOTHREADSERROR throw AsapError("Threads not supported. ") << __FILE__ << ":" << __LINE__ 153 154 /// Defining our own assert macro that throws an exception 155 #ifdef ASAPASSERT 156 #ifdef __GNUC__ 157 #define ASSERT(EX) if (!(EX)) \ 158 throw AssertionFailed(#EX, __FILE__, __LINE__, __PRETTY_FUNCTION__) 159 #else // __GNUC__ 160 #define ASSERT(EX) if (!(EX)) \ 161 throw AssertionFailed(#EX, __FILE__, __LINE__, __func__) 162 #endif // __GNUC__ 163 #else // ASAPASSERT 164 #define ASSERT(EX) assert(EX) 165 #endif // ASAPASSERT 166 167 #ifdef SLOWASSERT 168 // We need the semicolon below, although it looks wrong, to allow SASSERT to vanish altogether. 169 #define SASSERT(x) ASSERT(x); 170 #else // SLOWASSERT 171 #define SASSERT(x) 172 #endif // SLOWASSERT 173 174 175 // Define macros and helper functions for throwing exceptions within OpenMP constructs. 176 #ifdef _OPENMP 177 178 extern AsapErrorBase *AsapGlobalException; 179 void AsapThrowHelper(const AsapError &err); 180 void AsapThrowHelper(const AsapPythonError &err); 181 182 #define THROW(x) AsapThrowHelper(x) 183 #define THROW_RETURN(x) {AsapThrowHelper(x); return;} 184 #define CHECKNOASAPERROR ASSERT(AsapGlobalException == NULL) 185 #define RETURNIFASAPERROR if (AsapGlobalException != NULL) return 186 #define RETURNIFASAPERROR2(x) if (AsapGlobalException != NULL) return (x) 187 #define PROPAGATEASAPERROR if (AsapGlobalException != NULL) { \ 188 AsapError *err = dynamic_cast<AsapError*>(AsapGlobalException); \ 189 AsapPythonError *perr = dynamic_cast<AsapPythonError*>(AsapGlobalException); \ 190 AsapGlobalException = NULL; \ 191 std::cerr << "Propagating ASAP error [" << __FILE__ << ":" << __LINE__ << "] ..." << std::endl; \ 192 if (err != NULL) throw *err; \ 193 if (perr != NULL) throw *perr; \ 194 throw AsapError("Error throwing exception."); } 195 196 #else // _OPENMP 197 198 #define THROW(x) throw x 199 #define THROW_RETURN(x) throw x 200 #define CHECKNOASAPERROR 201 #define RETURNIFASAPERROR 202 #define RETURNIFASAPERROR2(x) 203 #define PROPAGATEASAPERROR 204 205 #endif // _OPENMP 206 207 } // end namespace 208 209 #endif // _EXCEPTION_H 210