/*
* This file is part of the GROMACS molecular simulation package.
*
- * Copyright (c) 2013, by the GROMACS development team, led by
- * David van der Spoel, Berk Hess, Erik Lindahl, and including many
- * others, as listed in the AUTHORS file in the top-level source
- * directory and at http://www.gromacs.org.
+ * Copyright (c) 2013,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
* \author Teemu Murtola <teemu.murtola@gmail.com>
* \ingroup module_utility
*/
-#include "gromacs/utility/init.h"
+#include "gmxpre.h"
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
+#include "init.h"
-#include <cstring>
+#include "config.h"
#ifdef GMX_LIB_MPI
#include "gromacs/utility/gmxmpi.h"
#endif
-#include "gromacs/legacyheaders/network.h"
-#include "gromacs/legacyheaders/smalloc.h"
-#include "gromacs/legacyheaders/types/commrec.h"
-
-#include "gromacs/utility/programinfo.h"
+#include "gromacs/utility/common.h"
+#include "gromacs/utility/gmxassert.h"
namespace gmx
{
-#ifdef GMX_LIB_MPI
namespace
{
+#ifdef GMX_LIB_MPI
+//! Maintains global counter of attempts to initialize MPI
+int g_initializationCounter = 0;
+#endif
+}
-void broadcastArguments(const t_commrec *cr, int *argc, char ***argv)
+void init(int *argc, char ***argv)
{
- gmx_bcast(sizeof(*argc), argc, cr);
-
- if (!MASTER(cr))
- {
- snew(*argv, *argc+1);
- }
- for (int i = 0; i < *argc; i++)
+#ifdef GMX_LIB_MPI
+ int isInitialized = 0, isFinalized = 0;
+ MPI_Finalized(&isFinalized);
+ GMX_RELEASE_ASSERT(!isFinalized, "Invalid attempt to initialize MPI after finalization");
+ MPI_Initialized(&isInitialized);
+ if (isInitialized)
{
- int len;
- if (MASTER(cr))
+ if (0 == g_initializationCounter)
{
- len = std::strlen((*argv)[i])+1;
+ // Some other code has already initialized MPI, so bump the counter so that
+ // we know not to finalize MPI ourselves later.
+ g_initializationCounter++;
}
- gmx_bcast(sizeof(len), &len, cr);
- if (!MASTER(cr))
- {
- snew((*argv)[i], len);
- }
- gmx_bcast(len, (*argv)[i], cr);
}
-}
+ else
+ {
+#ifdef GMX_FAHCORE
+ (void) fah_MPI_Init(argc, argv);
+#else
+ (void) MPI_Init(argc, argv);
+#endif
+ }
+ // Bump the counter to record this initialization event
+ g_initializationCounter++;
-} // namespace
+#else
+ GMX_UNUSED_VALUE(argc);
+ GMX_UNUSED_VALUE(argv);
#endif
+}
-ProgramInfo &init(const char *realBinaryName, int *argc, char ***argv)
+void finalize()
{
#ifdef GMX_LIB_MPI
- // TODO: Rewrite this to not use t_commrec once there is clarity on
- // the approach for MPI in C++ code.
- // TODO: Consider whether the argument broadcast would better be done
- // in CommandLineModuleManager.
- t_commrec cr;
- std::memset(&cr, 0, sizeof(cr));
- gmx_do_mpi_init(argc, argv);
- gmx_fill_commrec_from_mpi(&cr);
- if (PAR(&cr))
+ GMX_RELEASE_ASSERT(0 < g_initializationCounter, "Excess attempt to finalize MPI");
+ // Bump the counter to record this finalization event
+ g_initializationCounter--;
+
+ if (0 == g_initializationCounter)
{
- broadcastArguments(&cr, argc, argv);
+ /* We sync the processes here to try to avoid problems
+ * with buggy MPI implementations that could cause
+ * unfinished processes to terminate.
+ */
+ MPI_Barrier(MPI_COMM_WORLD);
+
+ /* Apparently certain mpich implementations cause problems
+ * with MPI_Finalize. In that case comment out MPI_Finalize.
+ */
+ MPI_Finalize();
}
#endif
- return ProgramInfo::init(realBinaryName, *argc, *argv);
-}
-
-ProgramInfo &init(int *argc, char ***argv)
-{
- return init(NULL, argc, argv);
-}
-
-void finalize()
-{
- gmx_finalize_mpi();
}
} // namespace gmx