// -*- C++ -*- // Exception.h: Exceptions used by Asap // // Copyright (C) 2001-2011 Jakob Schiotz and Center for Individual // Nanoparticle Functionality, Department of Physics, Technical // University of Denmark. Email: schiotz@fysik.dtu.dk // // This file is part of Asap version 3. // Asap is released under the GNU Lesser Public License (LGPL) version 3. // However, the parts of Asap distributed within the OpenKIM project // (including this file) are also released under the Common Development // and Distribution License (CDDL) version 1.0. // // This program is free software: you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public License // version 3 as published by the Free Software Foundation. Permission // to use other versions of the GNU Lesser General Public License may // granted by Jakob Schiotz or the head of department of the // Department of Physics, Technical University of Denmark, as // described in section 14 of the GNU General Public License. // // 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 // and the GNU Lesser Public License along with this program. If not, // see . // DESIGN NOTE: // ============ // // Error conditions in Asap are usually handled by throwing an AsapError // exception. This exception is caught by the Python Interface methods, // and converted to a Python exception. If errors are generated by Python // in Python calls from Asap, the Python error condition is left in place, // and the C++ code throws an AsapPythonError. This error is also caught // by the Python Interface methods, but in this case the preexisting Python // error condition is left unchanged, and the error condition is reported // back to Python. This results in slightly strange tracebacks, as the // path through the C++ code will be missing. A subclass of AsapPythonError // is AsapNotImplementedError, which is thrown without a corresponding // Python error, and converted into Python's NotImplementedError. Finally, // assert statements can be changed to emit an AssertionFailed error that is // also turned into a Python AssertionFailed error. This latter behaviour // is normally disabled, and is totally incompatible with OpenMP. // // OpenMP note: OpenMP place so severe restrictions on throwing exceptions // inside parallel sections that exceptions become almost useless, even if // parallelism is disabled at runtime. Asap handles this by replacing the // throw statement with a THROW() macro inside OpenMP enabled regions. If // compiled without OpenMP support, this macro just expands to the throw // statement. If OpenMP is enabled, it instead expands to a helper function // that just stores the exception in a global variable. Subsequent function // calls are then supposed to return immediately (thanks to the // RETURNIFASAPERROR macro in the beginning of the functions) until control // leaves the parallel section, and the exception is thrown by the // PROPAGATEASAPERROR macro. These latter macros are empty if OpenMP is // not enabled at compile time. #ifndef _EXCEPTION_H #define _EXCEPTION_H #include "Asap.h" #include #include #ifndef ASAPASSERT #include #endif // ASAPASSERT using std::stringstream; using std::string; namespace ASAPSPACE { // this AsapError class can be used as follows: // // throw AsapError("Error"); // // throw AsapError("Error ") << n + 7 << " while opening file: " << filename; class ASAP_PUBLIC AsapErrorBase { public: virtual ~AsapErrorBase() {}; }; class ASAP_PUBLIC AsapError : public AsapErrorBase { public: AsapError(const char *m); AsapError(const AsapError& ex); virtual ~AsapError(); template AsapError& operator<<(const T& x) { message << x; return *this; } string GetMessage() const; private: stringstream message; }; /// An exception for indicating that a Python error has occurred and /// should be propagated. class ASAP_PUBLIC AsapPythonError : public AsapErrorBase { public: AsapPythonError() {}; }; /// An exception mapping to a Python NotImplementedError class ASAP_PUBLIC AsapNotImplementedError : public AsapPythonError { public: AsapNotImplementedError(const char *m); }; class ASAP_PUBLIC AssertionFailed : public AsapErrorBase { public: AssertionFailed(const char *expression, const char *file, int line, const char *func = NULL); AssertionFailed(const AssertionFailed& ex); ~AssertionFailed(); string GetMessage() const; private: stringstream message; }; /// A helper define #define NOTHREADSERROR throw AsapError("Threads not supported. ") << __FILE__ << ":" << __LINE__ /// Defining our own assert macro that throws an exception #ifdef ASAPASSERT #undef assert #ifdef __GNUC__ #define assert(EX) if (!(EX)) \ throw AssertionFailed(#EX, __FILE__, __LINE__, __PRETTY_FUNCTION__) #else // __GNUC__ #define assert(EX) if (!(EX)) \ throw AssertionFailed(#EX, __FILE__, __LINE__, __func__) #endif // __GNUC__ #endif // ASAPASSERT // Define macros and helper functions for throwing exceptions within OpenMP constructs. #ifdef _OPENMP extern AsapErrorBase *AsapGlobalException; void AsapThrowHelper(const AsapError &err); void AsapThrowHelper(const AsapPythonError &err); #define THROW(x) AsapThrowHelper(x) #define THROW_RETURN(x) {AsapThrowHelper(x); return;} #define CHECKNOASAPERROR assert(AsapGlobalException == NULL) #define RETURNIFASAPERROR if (AsapGlobalException != NULL) return #define RETURNIFASAPERROR2(x) if (AsapGlobalException != NULL) return (x) #define PROPAGATEASAPERROR if (AsapGlobalException != NULL) { \ AsapError *err = dynamic_cast(AsapGlobalException); \ AsapPythonError *perr = dynamic_cast(AsapGlobalException); \ AsapGlobalException = NULL; \ std::cerr << "Propagating ASAP error [" << __FILE__ << ":" << __LINE__ << "] ..." << std::endl; \ if (err != NULL) throw *err; \ if (perr != NULL) throw *perr; \ throw AsapError("Error throwing exception."); } #else // _OPENMP #define THROW(x) throw x #define THROW_RETURN(x) throw x #define CHECKNOASAPERROR #define RETURNIFASAPERROR #define RETURNIFASAPERROR2(x) #define PROPAGATEASAPERROR #endif // _OPENMP } // end namespace #endif // _EXCEPTION_H