Merge release-5-0 into master
[alexxy/gromacs.git] / src / gromacs / utility / fatalerror.cpp
similarity index 62%
rename from src/gromacs/gmxlib/gmx_fatal.c
rename to src/gromacs/utility/fatalerror.cpp
index 002fb2d200af04246aa667eff1cef31eb54d1033..179b91005e48762966a0dac588b517b63fd3c0eb 100644 (file)
  * 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;
 }
 
@@ -128,7 +121,7 @@ void _where(const char *file, int line)
 
 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)
@@ -150,175 +143,127 @@ static void quit_gmx(const char *msg)
         }
         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);
 }
 
 /*
@@ -337,7 +282,7 @@ void init_debug(const int dbglevel, const char *dbgfile)
     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)
         {
@@ -347,17 +292,6 @@ void init_debug(const int dbglevel, const char *dbgfile)
     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 {
@@ -375,11 +309,9 @@ char *gmx_strerror(const char *key)
         { "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)
     {
@@ -387,49 +319,24 @@ char *gmx_strerror(const char *key)
     }
     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,