+++ /dev/null
-/*
- * This file is part of the GROMACS molecular simulation package.
- *
- * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
- * Copyright (c) 2001-2012, The GROMACS development team.
- * Copyright (c) 2012,2014, by the GROMACS development team, led by
- * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
- * and including many others, as listed in the AUTHORS file in the
- * top-level source directory and at http://www.gromacs.org.
- *
- * GROMACS is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * as published by the Free Software Foundation; either version 2.1
- * of the License, or (at your option) any later version.
- *
- * GROMACS 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with GROMACS; if not, see
- * http://www.gnu.org/licenses, or write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * If you want to redistribute modifications to GROMACS, please
- * consider that scientific software is very special. Version
- * control is crucial - bugs must be traceable. We will be happy to
- * consider code for inclusion in the official distribution, but
- * derived work must not be called official GROMACS. Details are found
- * in the README & COPYING files - if they are missing, get the
- * official version at http://www.gromacs.org.
- *
- * To help us fund GROMACS development, we humbly ask that you cite
- * the research papers on the package. Check out http://www.gromacs.org.
- */
-
-#ifndef _fatal_collective_h
-#define _fatal_collective_h
-
-#include "typedefs.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-
-void
-gmx_fatal_collective(int f_errno, const char *file, int line,
- const t_commrec *cr, gmx_domdec_t *dd,
- const char *fmt, ...);
-/* As gmx_fatal declared in gmx_fatal.h,
- * but only the master process prints the error message.
- * This should only be called one of the following two situations:
- * 1) On all nodes in cr->mpi_comm_mysim, with cr!=NULL,dd==NULL.
- * 2) On all nodes in dd->mpi_comm_all, with cr==NULL,dd!=NULL.
- * This will call MPI_Finalize instead of MPI_Abort when possible,
- * This is useful for handling errors in code that is executed identically
- * for all processes.
- */
-
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _fatal_collective_h */
* the research papers on the package. Check out http://www.gromacs.org.
*/
#include "fatalerror.h"
-#include "gromacs/legacyheaders/gmx_fatal_collective.h"
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
-#include <ctype.h>
-#include <errno.h>
-#include <stdarg.h>
-#include <stdlib.h>
-#include <string.h>
+#include <cerrno>
+#include <cstdarg>
+#include <cstdlib>
+#include <cstring>
#include <exception>
#include "thread_mpi/threads.h"
-#include "gromacs/legacyheaders/types/commrec.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"
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)
{
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)
+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, ...)
-{
- 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
-#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 */
- const bool bFinalize = (result != MPI_UNEQUAL);
-#else
- const bool bFinalize = true;
-#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);
}
/*
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 {
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);
- }
- // 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 &)
- {
- }
-
- 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);
+ 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,
#ifndef GMX_UTILITY_FATALERROR_H
#define GMX_UTILITY_FATALERROR_H
+#include <stdarg.h>
#include <stdio.h>
#include "basedefinitions.h"
/** Prints filename and line to stdlog. */
#define where() _where(__FILE__, __LINE__)
+/*! |brief
+ * Low-level fatal error reporting routine for collective MPI errors.
+ *
+ * This function works as gmx_fatal(), but provides additional control for
+ * cases where it is known that the same error occurs on multiple MPI ranks.
+ * The error handler is called only if \p bMaster is `TRUE`, and MPI_Finalize()
+ * is called instead of MPI_Abort() in MPI-enabled \Gromacs if \p bFinalize is
+ * `TRUE`.
+ *
+ * This is used to implement gmx_fatal_collective() (which cannot be declared
+ * here, since it would bring with it mdrun-specific dependencies).
+ */
+void
+gmx_fatal_mpi_va(int fatal_errno, const char *file, int line, gmx_bool bMaster,
+ gmx_bool bFinalize, const char *fmt, va_list ap) GMX_ATTRIBUTE_NORETURN;
+
/*! \brief
* Fatal error reporting routine for \Gromacs.
*
* The format of \p fmt uses printf()-like formatting.
*
* In case all MPI processes want to stop with the same fatal error,
- * use gmx_fatal_collective(), declared in gmx_fatal_collective.h,
+ * use gmx_fatal_collective(), declared in network.h,
* to avoid having as many error messages as processes.
*
* The first three parameters can be provided through ::FARGS:
/*! \brief
* Sets an error handler for gmx_fatal() and other fatal error routines.
*
- * The default handler prints the message and aborts the program.
- * If you set a custom handler, it must also abort the program, otherwise
- * \Gromacs will behave unpredictably (most likely, it crashes shortly after
- * the fatal error).
+ * The default handler prints the message.
+ * \Gromacs will terminate the program after the error handler returns.
+ * To make gmx_fatal_collective() work, the error handler should not terminate
+ * the program, as it cannot know what is the desired way of termination.
* The string passed to the handler may be a multi-line string.
*
* \see gmx_fatal()