* To help us fund GROMACS development, we humbly ask that you cite
* the research papers on the package. Check out http://www.gromacs.org.
*/
-#include "gmx_fatal.h"
-#include "gmx_fatal_collective.h"
+#include "fatalerror.h"
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
-#include <ctype.h>
-#include <errno.h>
-#include <stdarg.h>
-#include <string.h>
+#include <cerrno>
+#include <cstdarg>
+#include <cstdlib>
+#include <cstring>
-#include "thread_mpi/threads.h"
+#include <exception>
-#include "main.h"
-#include "types/commrec.h"
-#include "network.h"
-#include "copyrite.h"
-#include "macros.h"
+#include "thread_mpi/threads.h"
-#include "gromacs/fileio/futil.h"
-#include "gromacs/fileio/gmxfio.h"
+#include "gromacs/utility/basenetwork.h"
+#include "gromacs/utility/baseversion.h"
+#include "gromacs/utility/common.h"
#include "gromacs/utility/cstringutil.h"
+#include "gromacs/utility/futil.h"
#include "gromacs/utility/gmxmpi.h"
+#include "gromacs/utility/programcontext.h"
#include "gromacs/utility/smalloc.h"
static gmx_bool bDebug = FALSE;
static FILE *log_file = NULL;
-static tMPI_Thread_mutex_t debug_mutex = TMPI_THREAD_MUTEX_INITIALIZER;
-static tMPI_Thread_mutex_t where_mutex = TMPI_THREAD_MUTEX_INITIALIZER;
+static tMPI_Thread_mutex_t debug_mutex = TMPI_THREAD_MUTEX_INITIALIZER;
+static tMPI_Thread_mutex_t where_mutex = TMPI_THREAD_MUTEX_INITIALIZER;
+
+static const char *const gmxuser
+ = "Please report this to the mailing list (gmx-users@gromacs.org)";
gmx_bool bDebugMode(void)
{
- gmx_bool ret;
-#if 0
- tMPI_Thread_mutex_lock(&debug_mutex);
-#endif
- ret = bDebug;
-#if 0
- tMPI_Thread_mutex_unlock(&debug_mutex);
-#endif
return bDebug;
}
static int fatal_errno = 0;
-static void quit_gmx(const char *msg)
+static void default_error_handler(const char *msg)
{
tMPI_Thread_mutex_lock(&debug_mutex);
if (fatal_errno == 0)
}
perror(msg);
}
+ tMPI_Thread_mutex_unlock(&debug_mutex);
+}
-#ifdef GMX_LIB_MPI
- if (gmx_mpi_initialized())
- {
- int nnodes;
- int noderank;
+static void (*gmx_error_handler)(const char *msg) = default_error_handler;
- nnodes = gmx_node_num();
- noderank = gmx_node_rank();
+void set_gmx_error_handler(void (*func)(const char *msg))
+{
+ // TODO: Either this is unnecessary, or also reads to the handler should be
+ // protected by a mutex.
+ tMPI_Thread_mutex_lock(&debug_mutex);
+ gmx_error_handler = func;
+ tMPI_Thread_mutex_unlock(&debug_mutex);
+}
- if (nnodes > 1)
- {
- fprintf(stderr, "Error on node %d, will try to stop all the nodes\n",
- noderank);
- }
- gmx_abort(noderank, nnodes, -1);
- }
-#endif
+static void call_error_handler(const char *key, const char *file, int line, const char *msg)
+{
+ char buf[10240], errerrbuf[1024];
+ const char *llines = "-------------------------------------------------------";
+ char *strerr;
- if (debug)
+ if (msg == NULL)
{
- fflush(debug);
+ sprintf(errerrbuf, "Empty fatal_error message. %s", gmxuser);
}
- if (bDebugMode())
+ // In case ProgramInfo is not initialized and there is an issue with the
+ // initialization, fall back to "GROMACS".
+ const char *programName = "GROMACS";
+ try
+ {
+ programName = gmx::getProgramContext().displayName();
+ }
+ catch (const std::exception &)
{
- fprintf(stderr, "dump core (y/n):");
- fflush(stderr);
- if (toupper(getc(stdin)) != 'N')
- {
- (void) abort();
- }
}
- exit(fatal_errno);
- tMPI_Thread_mutex_unlock(&debug_mutex);
+ strerr = gmx_strerror(key);
+ sprintf(buf, "\n%s\nProgram %s, %s\n"
+ "Source code file: %s, line: %d\n\n"
+ "%s:\n%s\nFor more information and tips for troubleshooting, please check the GROMACS\n"
+ "website at http://www.gromacs.org/Documentation/Errors\n%s\n",
+ llines, programName, gmx_version(), file, line,
+ strerr, msg ? msg : errerrbuf, llines);
+ free(strerr);
+
+ gmx_error_handler(buf);
}
-/* The function below should be identical to quit_gmx,
- * except that is does not actually quit and call gmx_abort.
- */
-static void quit_gmx_noquit(const char *msg)
+GMX_ATTRIBUTE_NORETURN static void do_exit(bool bMaster, bool bFinalize)
{
- tMPI_Thread_mutex_lock(&debug_mutex);
- if (!fatal_errno)
- {
- if (log_file)
- {
- fprintf(log_file, "%s\n", msg);
- }
- fprintf(stderr, "%s\n", msg);
- /* we set it to no-zero because if this function is called, something
- has gone wrong */
- fatal_errno = 255;
- }
- else
- {
- if (fatal_errno != -1)
- {
- errno = fatal_errno;
- }
- perror(msg);
- }
-
-#ifndef GMX_LIB_MPI
if (debug)
{
fflush(debug);
}
- if (bDebugMode())
+
+#ifdef GMX_MPI
+ if (gmx_mpi_initialized())
{
- fprintf(stderr, "dump core (y/n):");
- fflush(stderr);
- if (toupper(getc(stdin)) != 'N')
+ if (bFinalize)
{
- (void) abort();
+ /* Broadcast the fatal error number possibly modified
+ * on the master process, in case the user would like
+ * to use the return status on a non-master process.
+ * The master process in cr and dd always has global rank 0.
+ */
+ MPI_Bcast(&fatal_errno, sizeof(fatal_errno), MPI_BYTE,
+ 0, MPI_COMM_WORLD);
+
+ /* Finalize nicely instead of aborting */
+ MPI_Finalize();
}
- }
+ else if (bMaster)
+ {
+#ifdef GMX_LIB_MPI
+ gmx_abort(1);
#endif
-
- tMPI_Thread_mutex_unlock(&debug_mutex);
-}
-
-void gmx_fatal(int f_errno, const char *file, int line, const char *fmt, ...)
-{
- va_list ap;
- char msg[STRLEN];
-
- va_start(ap, fmt);
- vsprintf(msg, fmt, ap);
- va_end(ap);
-
- tMPI_Thread_mutex_lock(&debug_mutex);
- fatal_errno = f_errno;
- tMPI_Thread_mutex_unlock(&debug_mutex);
-
- _gmx_error("fatal", msg, file, line);
-}
-
-void gmx_fatal_collective(int f_errno, const char *file, int line,
- const t_commrec *cr, gmx_domdec_t *dd,
- const char *fmt, ...)
-{
- gmx_bool bFinalize;
- va_list ap;
- char msg[STRLEN];
-#ifdef GMX_MPI
- int result;
+ }
+ else
+ {
+ /* Let all other processes wait till the master has printed
+ * the error message and issued MPI_Abort.
+ */
+ MPI_Barrier(MPI_COMM_WORLD);
+ }
+ }
+#else
+ GMX_UNUSED_VALUE(bMaster);
+ GMX_UNUSED_VALUE(bFinalize);
#endif
- bFinalize = TRUE;
-
-#ifdef GMX_MPI
- /* Check if we are calling on all processes in MPI_COMM_WORLD */
- if (cr != NULL)
- {
- MPI_Comm_compare(cr->mpi_comm_mysim, MPI_COMM_WORLD, &result);
- }
- else
+ if (bDebugMode())
{
- MPI_Comm_compare(dd->mpi_comm_all, MPI_COMM_WORLD, &result);
+ std::abort();
}
- /* Any result except MPI_UNEQUAL allows us to call MPI_Finalize */
- bFinalize = (result != MPI_UNEQUAL);
-#endif
+ std::exit(1);
+}
- if ((cr != NULL && MASTER(cr) ) ||
- (dd != NULL && DDMASTER(dd)))
+void gmx_fatal_mpi_va(int f_errno, const char *file, int line,
+ gmx_bool bMaster, gmx_bool bFinalize,
+ const char *fmt, va_list ap)
+{
+ if (bMaster)
{
- va_start(ap, fmt);
+ char msg[STRLEN];
vsprintf(msg, fmt, ap);
- va_end(ap);
tMPI_Thread_mutex_lock(&debug_mutex);
fatal_errno = f_errno;
tMPI_Thread_mutex_unlock(&debug_mutex);
- if (bFinalize)
- {
- /* Use an error handler that does not quit */
- set_gmx_error_handler(quit_gmx_noquit);
- }
-
- _gmx_error("fatal", msg, file, line);
+ call_error_handler("fatal", file, line, msg);
}
-#ifdef GMX_MPI
- if (bFinalize)
- {
- /* Broadcast the fatal error number possibly modified
- * on the master process, in case the user would like
- * to use the return status on a non-master process.
- * The master process in cr and dd always has global rank 0.
- */
- MPI_Bcast(&fatal_errno, sizeof(fatal_errno), MPI_BYTE,
- 0, MPI_COMM_WORLD);
-
- /* Finalize nicely instead of aborting */
- MPI_Finalize();
- }
- else
- {
- /* Let all other processes wait till the master has printed
- * the error message and issued MPI_Abort.
- */
- MPI_Barrier(MPI_COMM_WORLD);
- }
-#endif
+ do_exit(bMaster, bFinalize);
+}
- exit(fatal_errno);
+void gmx_fatal(int f_errno, const char *file, int line, const char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ gmx_fatal_mpi_va(f_errno, file, line, TRUE, FALSE, fmt, ap);
+ va_end(ap);
}
/*
if (!bDebug) /* another thread hasn't already run this*/
{
no_buffers();
- debug = gmx_fio_fopen(dbgfile, "w+");
+ debug = gmx_ffopen(dbgfile, "w+");
bDebug = TRUE;
if (dbglevel >= 2)
{
tMPI_Thread_mutex_unlock(&debug_mutex);
}
-static const char *gmxuser = "Please report this to the mailing list (gmx-users@gromacs.org)";
-
-static void (*gmx_error_handler)(const char *msg) = quit_gmx;
-
-void set_gmx_error_handler(void (*func)(const char *msg))
-{
- tMPI_Thread_mutex_lock(&debug_mutex);
- gmx_error_handler = func;
- tMPI_Thread_mutex_unlock(&debug_mutex);
-}
-
char *gmx_strerror(const char *key)
{
typedef struct {
{ "input", "Input error or input inconsistency" },
{ "mem", "Memory allocation/freeing error" },
{ "open", "Can not open file" },
- { "range", "Range checking error" }
+ { "range", "Range checking error" },
+ { NULL, NULL}
};
-#define NMSG asize(msg)
- char buf[1024];
- size_t i;
if (key == NULL)
{
}
else
{
- for (i = 0; (i < NMSG); i++)
+ for (size_t i = 0; msg[i].key != NULL; ++i)
{
if (strcmp(key, msg[i].key) == 0)
{
- break;
+ return strdup(msg[i].msg);
}
}
- if (i == NMSG)
- {
- sprintf(buf, "No error message associated with key %s\n%s", key, gmxuser);
- return strdup(buf);
- }
- else
- {
- return strdup(msg[i].msg);
- }
+ char buf[1024];
+ sprintf(buf, "No error message associated with key %s\n%s", key, gmxuser);
+ return strdup(buf);
}
}
void _gmx_error(const char *key, const char *msg, const char *file, int line)
{
- char buf[10240], errerrbuf[1024];
- const char *llines = "-------------------------------------------------------";
- char *strerr;
-
- /* protect the audience from suggestive discussions */
-
- if (msg == NULL)
- {
- sprintf(errerrbuf, "Empty fatal_error message. %s", gmxuser);
- }
-
- strerr = gmx_strerror(key);
- sprintf(buf, "\n%s\nProgram %s, %s\n"
- "Source code file: %s, line: %d\n\n"
- "%s:\n%s\nFor more information and tips for troubleshooting, please check the GROMACS\n"
- "website at http://www.gromacs.org/Documentation/Errors\n%s\n",
- llines, ShortProgram(), GromacsVersion(), file, line,
- strerr, msg ? msg : errerrbuf, llines);
- free(strerr);
-
- gmx_error_handler(buf);
+ call_error_handler(key, file, line, msg);
+ do_exit(true, false);
}
void _range_check(int n, int n_min, int n_max, const char *warn_str,