int
main(int argc, char *argv[])
{
+ ProgramInfo::init(argc, argv);
try
{
AnalysisTemplate module;
}
catch (const std::exception &ex)
{
- fprintf(stderr, "%s", gmx::formatErrorMessage(ex).c_str());
+ gmx::printFatalErrorMessage(stderr, ex);
return 1;
}
}
}
catch (const std::exception &ex)
{
- fprintf(stderr, "%s", gmx::formatErrorMessage(ex).c_str());
+ gmx::printFatalErrorMessage(stderr, ex);
return 1;
}
}
#include <string>
+#include "gromacs/utility/exceptions.h"
#include "gromacs/utility/stringutil.h"
#include "gmx_fatal.h"
}
return gmx_strdup(result.c_str());
}
- catch (const std::bad_alloc &)
- {
- gmx_fatal(FARGS, "Out of memory");
- }
- return gmx_strdup(s);
+ GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR;
}
static char *repallww(const char *s,int nsr,const t_sandr sa[])
}
return gmx_strdup(result.c_str());
}
- catch (const std::bad_alloc &)
- {
- gmx_fatal(FARGS, "Out of memory");
- }
- return gmx_strdup(s);
+ GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR;
}
static char *html_xref(char *s,const char *program, t_linkdata *links,gmx_bool bWiki)
#include "trajectoryanalysis/analysissettings.h"
#include "trajectoryanalysis/cmdlinerunner.h"
#include "utility/exceptions.h"
+#include "utility/programinfo.h"
#include "utility/stringutil.h"
#endif
*
* \author Teemu Murtola <teemu.murtola@cbr.su.se>
*/
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <gromacs/options/basicoptions.h>
-#include <gromacs/options/options.h>
-#include <gromacs/selection/selection.h>
-#include <gromacs/selection/selectionoption.h>
-#include <gromacs/trajectoryanalysis/analysismodule.h>
-#include <gromacs/trajectoryanalysis/analysissettings.h>
-#include <gromacs/trajectoryanalysis/cmdlinerunner.h>
-#include <gromacs/utility/exceptions.h>
-#include <gromacs/utility/stringutil.h>
+#include "gromacs/options/basicoptions.h"
+#include "gromacs/options/options.h"
+#include "gromacs/selection/selection.h"
+#include "gromacs/selection/selectionoption.h"
+#include "gromacs/trajectoryanalysis/analysismodule.h"
+#include "gromacs/trajectoryanalysis/analysissettings.h"
+#include "gromacs/trajectoryanalysis/cmdlinerunner.h"
+#include "gromacs/utility/exceptions.h"
+#include "gromacs/utility/programinfo.h"
+#include "gromacs/utility/stringutil.h"
namespace gmx
{
int
main(int argc, char *argv[])
{
+ gmx::ProgramInfo::init(argc, argv);
try
{
gmx::SelectionTester module;
}
catch (const std::exception &ex)
{
- fprintf(stderr, "%s", gmx::formatErrorMessage(ex).c_str());
+ gmx::printFatalErrorMessage(stderr, ex);
return 1;
}
}
*/
#include "gromacs/utility/errorcodes.h"
-#include <cstdarg>
-#include <cstdio>
#include <cstdlib>
+#include "gromacs/legacyheaders/thread_mpi/mutex.h"
+
#include "errorformat.h"
// This has to match the enum in errorcodes.h
const char *file, int line)
{
const char *title = getErrorCodeString(retcode);
- fprintf(stderr, "%s",
- internal::formatFatalError(title, msg, NULL, file, line).c_str());
+ internal::printFatalError(stderr, title, msg, NULL, file, line);
std::exit(1);
}
static ErrorHandlerFunc error_handler = standardErrorHandler;
+static tMPI::mutex handler_mutex;
ErrorHandlerFunc setFatalErrorHandler(ErrorHandlerFunc handler)
{
- // TODO: Acquire a mutex here
+ tMPI::lock_guard<tMPI::mutex> lock(handler_mutex);
ErrorHandlerFunc old_handler = error_handler;
error_handler = handler;
- // TODO: Release the mutex here
return old_handler;
}
void fatalError(int retcode, const char *msg, const char *file, int line)
{
- // TODO: Acquire a mutex here
- ErrorHandlerFunc handler = error_handler;
- // TODO: Release the mutex here
+ ErrorHandlerFunc handler = NULL;
+ {
+ tMPI::lock_guard<tMPI::mutex> lock(handler_mutex);
+ handler = error_handler;
+ }
if (handler != NULL)
{
handler(retcode, msg, file, line);
*/
#include "gromacs/utility/errorformat.h"
-#include <string>
+#include <cstdio>
#include "gromacs/legacyheaders/copyrite.h"
namespace internal
{
-std::string formatFatalError(const char *title, const char *details,
- const char *func, const char *file, int line)
+void printFatalError(FILE *fp, const char *title, const char *details,
+ const char *func, const char *file, int line)
{
- std::string result;
- result.append("\n-------------------------------------------------------\n");
- const char *programName = ProgramInfo::getInstance().programName().c_str();
- result.append(formatString("Program %s, %s\n", programName, GromacsVersion()));
+ // In case ProgramInfo is not initialized and there is an issue with the
+ // initialization, fall back to "GROMACS".
+ const char *programName = "GROMACS";
+ try
+ {
+ programName = ProgramInfo::getInstance().programName().c_str();
+ }
+ catch (const std::exception &)
+ {
+ }
+
+ std::fprintf(fp, "\n-------------------------------------------------------\n");
+ std::fprintf(fp, "Program %s, %s\n", programName, GromacsVersion());
if (func != NULL)
{
- result.append(formatString("In function %s\n", func));
+ std::fprintf(fp, "In function: %s\n", func);
}
// TODO: Strip away absolute paths from file names (CMake seems to generate those)
if (file != NULL)
{
- result.append(formatString("Source file %s, line %d\n\n", file, line));
- }
- else
- {
- result.append("\n");
+ std::fprintf(fp, "Source file %s, line %d\n", file, line);
}
- result.append(formatString("%s:\n%s\n", title, details));
- result.append("For more information and tips for troubleshooting, please check the GROMACS\n"
- "website at http://www.gromacs.org/Documentation/Errors");
- result.append("\n-------------------------------------------------------\n");
- return result;
+ std::fprintf(fp, "\n");
+ std::fprintf(fp, "%s:\n", title);
+ // TODO: Line wrapping
+ std::fprintf(fp, "%s\n", details);
+ std::fprintf(fp, "For more information and tips for troubleshooting, please check the GROMACS\n"
+ "website at http://www.gromacs.org/Documentation/Errors");
+ std::fprintf(fp, "\n-------------------------------------------------------\n");
}
} // namespace internal
#ifndef GMX_UTILITY_ERRORFORMAT_H
#define GMX_UTILITY_ERRORFORMAT_H
-#include <string>
+#include <cstdio>
namespace gmx
{
/*! \internal \brief
* Formats common headers and footers for error messages.
*
+ * Does not throw.
+ *
* \ingroup module_utility
*/
-std::string formatFatalError(const char *title, const char *details,
- const char *func, const char *file, int line);
+void printFatalError(FILE *fp, const char *title, const char *details,
+ const char *func, const char *file, int line);
} // namespace internal
//! \endcond
* Global functions
*/
-std::string formatErrorMessage(const std::exception &ex)
+void printFatalErrorMessage(FILE *fp, const std::exception &ex)
{
const char *title = "Unknown exception";
- const char *func = NULL;
- const char *file = NULL;
- int line = 0;
const GromacsException *gmxEx = dynamic_cast<const GromacsException *>(&ex);
// TODO: Also treat common standard exceptions
if (gmxEx != NULL)
{
title = getErrorCodeString(gmxEx->errorCode());
- func = *boost::get_error_info<boost::throw_function>(*gmxEx);
- file = *boost::get_error_info<boost::throw_file>(*gmxEx);
- line = *boost::get_error_info<boost::throw_line>(*gmxEx);
+ }
+ else if (dynamic_cast<const std::bad_alloc *>(&ex) != NULL)
+ {
+ title = "Memory allocation failed";
+ }
+ // We can't call get_error_info directly on ex since our internal boost
+ // needs to be compiled with BOOST_NO_RTTI. So we do the dynamic_cast
+ // here instead.
+ const char *const *funcPtr = NULL;
+ const char *const *filePtr = NULL;
+ const int *linePtr = NULL;
+ const boost::exception *boostEx = dynamic_cast<const boost::exception *>(&ex);
+ if (boostEx != NULL)
+ {
+ funcPtr = boost::get_error_info<boost::throw_function>(*boostEx);
+ filePtr = boost::get_error_info<boost::throw_file>(*boostEx);
+ linePtr = boost::get_error_info<boost::throw_line>(*boostEx);
}
// TODO: Treat errno information in boost exceptions
- return internal::formatFatalError(title, ex.what(), func, file, line);
+ internal::printFatalError(fp, title, ex.what(),
+ funcPtr != NULL ? *funcPtr : NULL,
+ filePtr != NULL ? *filePtr : NULL,
+ linePtr != NULL ? *linePtr : 0);
}
} // namespace gmx
#ifndef GMX_UTILITY_EXCEPTIONS_H
#define GMX_UTILITY_EXCEPTIONS_H
+#include <cstdio>
+#include <cstdlib>
+
#include <exception>
#include <string>
} while(0)
/*! \brief
- * Formats a standard error message for reporting an error.
+ * Formats a standard fatal error message for reporting an exception.
+ *
+ * Does not throw. If memory allocation fails or some other error occurs
+ * while formatting the error, tries to print a reasonable alternative message.
*
* Normal usage in Gromacs command-line programs is like this:
* \code
int main(int argc, char *argv[])
{
+ gmx::ProgramInfo::init(argc, argv);
try
{
// The actual code for the program
}
catch (const std::exception &ex)
{
- fprintf(stderr, "%s", gmx::formatErrorMessage(ex).c_str());
+ gmx::printFatalErrorMessage(stderr, ex);
return 1;
}
}
* \endcode
*/
-std::string formatErrorMessage(const std::exception &ex);
+void printFatalErrorMessage(FILE *fp, const std::exception &ex);
/*! \brief
* Converts an exception into a return code.
/*!\}*/
+/*! \cond libapi */
+/*! \libinternal \brief
+ * Macro for catching exceptions at C++ -> C boundary.
+ *
+ * This macro is intended for uniform handling of exceptions when C++ code is
+ * called from C code within Gromacs. Since most existing code is written
+ * using the assumption that fatal errors terminate the program, this macro
+ * implements this behavior for exceptions. It should only be used in cases
+ * where the error cannot be propagated upwards using return values or such.
+ *
+ * Having this as a macro instead of having the same code in each place makes
+ * it easy to 1) find all such locations in the code, and 2) change the exact
+ * behavior if needed.
+ *
+ * Usage:
+ * \code
+try
+{
+ // C++ code
+}
+GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR;
+ * \endcode
+ *
+ * \inlibraryapi
+ */
+#define GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR \
+ catch (const std::exception &ex) { \
+ ::gmx::printFatalErrorMessage(stderr, ex); \
+ std::exit(1); \
+ }
+//! \endcond
+
} // namespace gmx
#endif
void assertHandler(const char *condition, const char *msg,
const char *func, const char *file, int line)
{
- std::string text =
- formatFatalError("Assertion failed",
- formatString("Condition: %s\n%s", condition, msg).c_str(),
- func, file, line);
- std::fprintf(stderr, "%s", text.c_str());
+ try
+ {
+ std::string title = formatString("Condition: %s\n%s", condition, msg);
+ printFatalError(stderr, "Assertion failed", title.c_str(),
+ func, file, line);
+ }
+ catch (const std::bad_alloc &)
+ {
+ printFatalError(stderr, "Assertion failed",
+ "(memory allocation failed while formatting the error message)",
+ func, file, line);
+ }
std::abort();
}
#include <cstdlib>
#include <cstring>
-#include <new>
#include <string>
#include <boost/scoped_ptr.hpp>
#include "gromacs/legacyheaders/statutil.h"
+#include "gromacs/utility/exceptions.h"
#include "gromacs/utility/path.h"
#include "gromacs/utility/stringutil.h"
g_programInfo.reset(new ProgramInfo(realBinaryName, argc, argv));
return *g_programInfo;
}
- catch (const std::bad_alloc &)
+ catch (const std::exception &ex)
{
- // TODO: Report error.
+ printFatalErrorMessage(stderr, ex);
std::exit(1);
}
}
}
catch (const std::exception &ex)
{
- fprintf(stderr, "%s", gmx::formatErrorMessage(ex).c_str());
+ gmx::printFatalErrorMessage(stderr, ex);
return 1;
}
}
}
swap(commandLine, s_commandLine);
}
- catch (const std::bad_alloc &)
+ catch (const std::exception &ex)
{
- std::fprintf(stderr, "Out of memory\n");
+ printFatalErrorMessage(stderr, ex);
std::exit(1);
}
::gmx::setFatalErrorHandler(NULL);