Fix build for external boost 1.56.0
[alexxy/gromacs.git] / src / gromacs / utility / fatalerror.cpp
index 0901d89d3227f6507aa6bd6ba07fc798aeb01d3d..f242e2d4483cd52133a7b552f647b6b067a9bd42 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 "gmxpre.h"
+
 #include "fatalerror.h"
-#include "gromacs/legacyheaders/gmx_fatal_collective.h"
 
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
+#include "config.h"
 
-#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/legacyheaders/network.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 bool                bDebug         = false;
+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;
+FILE                      *debug          = NULL;
+gmx_bool                   gmx_debug_at   = FALSE;
 
-gmx_bool bDebugMode(void)
+static FILE               *log_file       = NULL;
+static tMPI_Thread_mutex_t error_mutex    = TMPI_THREAD_MUTEX_INITIALIZER;
+static const char *const   gmxuser
+    = "Please report this to the mailing list (gmx-users@gromacs.org)";
+
+void gmx_init_debug(const int dbglevel, const char *dbgfile)
 {
-    return bDebug;
+    if (!bDebug)
+    {
+        gmx_disable_file_buffering();
+        debug  = gmx_ffopen(dbgfile, "w+");
+        bDebug = true;
+        if (dbglevel >= 2)
+        {
+            gmx_debug_at = TRUE;
+        }
+    }
 }
 
-void gmx_fatal_set_log_file(FILE *fp)
+gmx_bool bDebugMode(void)
 {
-    log_file = fp;
+    return bDebug;
 }
 
 void _where(const char *file, int line)
@@ -92,7 +102,7 @@ void _where(const char *file, int line)
         if (bFirst) /* we repeat the check in the locked section because things
                        might have changed */
         {
-            if ((temp = getenv("WHERE")) != NULL)
+            if ((temp = getenv("GMX_PRINT_DEBUG_LINES")) != NULL)
             {
                 nskip = strtol(temp, NULL, 10);
             }
@@ -120,11 +130,16 @@ void _where(const char *file, int line)
     }
 }
 
+void gmx_fatal_set_log_file(FILE *fp)
+{
+    log_file = fp;
+}
+
 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);
+    tMPI_Thread_mutex_lock(&error_mutex);
     if (fatal_errno == 0)
     {
         if (log_file)
@@ -144,211 +159,127 @@ static void quit_gmx(const char *msg)
         }
         perror(msg);
     }
+    tMPI_Thread_mutex_unlock(&error_mutex);
+}
 
-#ifdef GMX_LIB_MPI
-    if (gmx_mpi_initialized())
-    {
-        int  nnodes;
-        int  noderank;
-
-        nnodes   = gmx_node_num();
-        noderank = gmx_node_rank();
-
-        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 (*gmx_error_handler)(const char *msg) = default_error_handler;
 
-    if (debug)
-    {
-        fflush(debug);
-    }
-    if (bDebugMode())
-    {
-        fprintf(stderr, "dump core (y/n):");
-        fflush(stderr);
-        if (toupper(getc(stdin)) != 'N')
-        {
-            (void) abort();
-        }
-    }
-
-    exit(fatal_errno);
-    tMPI_Thread_mutex_unlock(&debug_mutex);
+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(&error_mutex);
+    gmx_error_handler = func;
+    tMPI_Thread_mutex_unlock(&error_mutex);
 }
 
-/* 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 call_error_handler(const char *key, const char *file, int line, const char *msg)
 {
-    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
+    char        buf[10240], errerrbuf[1024];
+    const char *llines = "-------------------------------------------------------";
+    char       *strerr;
+
+    if (msg == NULL)
     {
-        if (fatal_errno != -1)
-        {
-            errno = fatal_errno;
-        }
-        perror(msg);
+        sprintf(errerrbuf, "Empty fatal_error message. %s", gmxuser);
     }
-
-#ifndef GMX_LIB_MPI
-    if (debug)
+    // In case ProgramInfo is not initialized and there is an issue with the
+    // initialization, fall back to "GROMACS".
+    const char *programName = "GROMACS";
+    try
     {
-        fflush(debug);
+        programName = gmx::getProgramContext().displayName();
     }
-    if (bDebugMode())
+    catch (const std::exception &)
     {
-        fprintf(stderr, "dump core (y/n):");
-        fflush(stderr);
-        if (toupper(getc(stdin)) != 'N')
-        {
-            (void) abort();
-        }
     }
-#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);
+    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("fatal", msg, file, line);
+    gmx_error_handler(buf);
 }
 
-void gmx_fatal_collective(int f_errno, const char *file, int line,
-                          const t_commrec *cr, gmx_domdec_t *dd,
-                          const char *fmt, ...)
+gmx_noreturn static void do_exit(bool bMaster, bool bFinalize)
 {
-    va_list     ap;
-    char        msg[STRLEN];
-#ifdef GMX_MPI
-    int         result;
-#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 (debug)
     {
-        MPI_Comm_compare(dd->mpi_comm_all, MPI_COMM_WORLD, &result);
+        fflush(debug);
     }
-    /* Any result except MPI_UNEQUAL allows us to call MPI_Finalize */
-    const bool bFinalize = (result != MPI_UNEQUAL);
-#else
-    const bool bFinalize = true;
-#endif
 
-    if ((cr != NULL && MASTER(cr)  ) ||
-        (dd != NULL && DDMASTER(dd)))
+#ifdef GMX_MPI
+    if (gmx_mpi_initialized())
     {
-        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);
-
         if (bFinalize)
         {
-            /* Use an error handler that does not quit */
-            set_gmx_error_handler(quit_gmx_noquit);
+            /* 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
+        }
+        else
+        {
+            /* Let all other processes wait till the master has printed
+             * the error message and issued MPI_Abort.
+             */
+            MPI_Barrier(MPI_COMM_WORLD);
         }
-
-        _gmx_error("fatal", msg, file, line);
     }
+#else
+    GMX_UNUSED_VALUE(bMaster);
+    GMX_UNUSED_VALUE(bFinalize);
+#endif
 
-#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
+    if (bDebugMode())
     {
-        /* Let all other processes wait till the master has printed
-         * the error message and issued MPI_Abort.
-         */
-        MPI_Barrier(MPI_COMM_WORLD);
+        std::abort();
     }
-#endif
-
-    exit(fatal_errno);
+    std::exit(1);
 }
 
-/*
- * These files are global variables in the gromacs preprocessor
- * Every routine in a file that includes gmx_fatal.h can write to these
- * debug channels. Depending on the debuglevel used
- * 0 to 3 of these filed are redirected to /dev/null
- *
- */
-FILE    *debug           = NULL;
-gmx_bool gmx_debug_at    = FALSE;
-
-void init_debug(const int dbglevel, const char *dbgfile)
+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)
 {
-    tMPI_Thread_mutex_lock(&debug_mutex);
-    if (!bDebug) /* another thread hasn't already run this*/
+    if (bMaster)
     {
-        no_buffers();
-        debug  = gmx_fio_fopen(dbgfile, "w+");
-        bDebug = TRUE;
-        if (dbglevel >= 2)
-        {
-            gmx_debug_at = TRUE;
-        }
-    }
-    tMPI_Thread_mutex_unlock(&debug_mutex);
-}
+        char msg[STRLEN];
+        vsprintf(msg, fmt, ap);
 
-static const char *gmxuser = "Please report this to the mailing list (gmx-users@gromacs.org)";
+        tMPI_Thread_mutex_lock(&error_mutex);
+        fatal_errno = f_errno;
+        tMPI_Thread_mutex_unlock(&error_mutex);
 
-static void        (*gmx_error_handler)(const char *msg) = quit_gmx;
+        call_error_handler("fatal", file, line, msg);
+    }
 
-void set_gmx_error_handler(void (*func)(const char *msg))
+    do_exit(bMaster, bFinalize);
+}
+
+void gmx_fatal(int f_errno, const char *file, int line, const char *fmt, ...)
 {
-    tMPI_Thread_mutex_lock(&debug_mutex);
-    gmx_error_handler = func;
-    tMPI_Thread_mutex_unlock(&debug_mutex);
+    va_list ap;
+    va_start(ap, fmt);
+    gmx_fatal_mpi_va(f_errno, file, line, TRUE, FALSE, fmt, ap);
+    va_end(ap);
 }
 
 char *gmx_strerror(const char *key)
@@ -394,37 +325,8 @@ char *gmx_strerror(const char *key)
 
 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,