Skip to content

Commit dabb318

Browse files
kodiakhq[bot]jngrad
authored andcommitted
Remove MPI static globals (#4858)
Fixes #4856 Description of changes: - fix multiple bugs caused by undefined behavior due to the static initialization order of MPI global objects - ESPResSo is now compatible with Boost 1.84+
1 parent d09de49 commit dabb318

24 files changed

+180
-68
lines changed

src/core/EspressoSystemStandAlone.cpp

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,17 +29,18 @@
2929
#include <utils/Vector.hpp>
3030

3131
#include <boost/mpi.hpp>
32+
#include <boost/mpi/environment.hpp>
3233

3334
#include <memory>
3435

3536
EspressoSystemStandAlone::EspressoSystemStandAlone(int argc, char **argv) {
36-
auto mpi_env = mpi_init(argc, argv);
37+
m_mpi_env = mpi_init(argc, argv);
3738

3839
boost::mpi::communicator world;
3940
head_node = world.rank() == 0;
4041

4142
// initialize the MpiCallbacks framework
42-
Communication::init(mpi_env);
43+
Communication::init(m_mpi_env);
4344

4445
// default-construct global state of the system
4546
#ifdef VIRTUAL_SITES
@@ -50,6 +51,10 @@ EspressoSystemStandAlone::EspressoSystemStandAlone(int argc, char **argv) {
5051
mpi_loop();
5152
}
5253

54+
EspressoSystemStandAlone::~EspressoSystemStandAlone() {
55+
Communication::deinit();
56+
}
57+
5358
void EspressoSystemStandAlone::set_box_l(Utils::Vector3d const &box_l) const {
5459
if (!head_node)
5560
return;

src/core/EspressoSystemStandAlone.hpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,19 +21,29 @@
2121

2222
#include <utils/Vector.hpp>
2323

24+
#include <memory>
25+
26+
namespace boost {
27+
namespace mpi {
28+
class environment;
29+
}
30+
} // namespace boost
31+
2432
/** Manager for a stand-alone ESPResSo system.
2533
* The system is default-initialized, MPI-ready and has no script interface.
2634
*/
2735
class EspressoSystemStandAlone {
2836
public:
2937
EspressoSystemStandAlone(int argc, char **argv);
38+
~EspressoSystemStandAlone();
3039
void set_box_l(Utils::Vector3d const &box_l) const;
3140
void set_node_grid(Utils::Vector3i const &node_grid) const;
3241
void set_time_step(double time_step) const;
3342
void set_skin(double new_skin) const;
3443

3544
private:
3645
bool head_node;
46+
std::shared_ptr<boost::mpi::environment> m_mpi_env;
3747
};
3848

3949
#endif

src/core/MpiCallbacks.hpp

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
#include <boost/mpi/collectives/broadcast.hpp>
4949
#include <boost/mpi/collectives/reduce.hpp>
5050
#include <boost/mpi/communicator.hpp>
51+
#include <boost/mpi/environment.hpp>
5152
#include <boost/optional.hpp>
5253
#include <boost/range/algorithm/remove_if.hpp>
5354

@@ -364,8 +365,8 @@ class MpiCallbacks {
364365
template <typename F, class = std::enable_if_t<std::is_same<
365366
typename detail::functor_types<F>::argument_types,
366367
std::tuple<Args...>>::value>>
367-
CallbackHandle(MpiCallbacks *cb, F &&f)
368-
: m_id(cb->add(std::forward<F>(f))), m_cb(cb) {}
368+
CallbackHandle(std::shared_ptr<MpiCallbacks> cb, F &&f)
369+
: m_id(cb->add(std::forward<F>(f))), m_cb(std::move(cb)) {}
369370

370371
CallbackHandle(CallbackHandle const &) = delete;
371372
CallbackHandle(CallbackHandle &&rhs) noexcept = default;
@@ -374,7 +375,7 @@ class MpiCallbacks {
374375

375376
private:
376377
int m_id;
377-
MpiCallbacks *m_cb;
378+
std::shared_ptr<MpiCallbacks> m_cb;
378379

379380
public:
380381
/**
@@ -400,7 +401,6 @@ class MpiCallbacks {
400401
m_cb->remove(m_id);
401402
}
402403

403-
MpiCallbacks *cb() const { return m_cb; }
404404
int id() const { return m_id; }
405405
};
406406

@@ -419,8 +419,10 @@ class MpiCallbacks {
419419

420420
public:
421421
explicit MpiCallbacks(boost::mpi::communicator comm,
422+
std::shared_ptr<boost::mpi::environment> mpi_env,
422423
bool abort_on_exit = true)
423-
: m_abort_on_exit(abort_on_exit), m_comm(std::move(comm)) {
424+
: m_abort_on_exit(abort_on_exit), m_comm(std::move(comm)),
425+
m_mpi_env(std::move(mpi_env)) {
424426
/* Add a dummy at id 0 for loop abort. */
425427
m_callback_map.add(nullptr);
426428

@@ -738,6 +740,11 @@ class MpiCallbacks {
738740
*/
739741
boost::mpi::communicator m_comm;
740742

743+
/**
744+
* The MPI environment used for the callbacks.
745+
*/
746+
std::shared_ptr<boost::mpi::environment> m_mpi_env;
747+
741748
/**
742749
* Internal storage for the callback functions.
743750
*/

src/core/communication.cpp

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@
2828
#include <utils/mpi/cart_comm.hpp>
2929

3030
#include <boost/mpi.hpp>
31+
#include <boost/mpi/communicator.hpp>
32+
#include <boost/mpi/environment.hpp>
3133

3234
#include <mpi.h>
3335
#ifdef OPEN_MPI
@@ -39,22 +41,23 @@
3941
#include <cstdlib>
4042
#include <memory>
4143

42-
namespace Communication {
43-
auto const &mpi_datatype_cache = boost::mpi::detail::mpi_datatype_cache();
44-
std::shared_ptr<boost::mpi::environment> mpi_env;
45-
} // namespace Communication
46-
4744
boost::mpi::communicator comm_cart;
4845

4946
namespace Communication {
50-
std::unique_ptr<MpiCallbacks> m_callbacks;
47+
static std::shared_ptr<MpiCallbacks> m_callbacks;
5148

5249
/* We use a singleton callback class for now. */
5350
MpiCallbacks &mpiCallbacks() {
5451
assert(m_callbacks && "Mpi not initialized!");
5552

5653
return *m_callbacks;
5754
}
55+
56+
std::shared_ptr<MpiCallbacks> mpiCallbacksHandle() {
57+
assert(m_callbacks && "Mpi not initialized!");
58+
59+
return m_callbacks;
60+
}
5861
} // namespace Communication
5962

6063
using Communication::mpiCallbacks;
@@ -120,8 +123,6 @@ void openmpi_global_namespace() {
120123

121124
namespace Communication {
122125
void init(std::shared_ptr<boost::mpi::environment> mpi_env) {
123-
Communication::mpi_env = std::move(mpi_env);
124-
125126
MPI_Comm_size(MPI_COMM_WORLD, &n_nodes);
126127
node_grid = Utils::Mpi::dims_create<3>(n_nodes);
127128

@@ -131,12 +132,14 @@ void init(std::shared_ptr<boost::mpi::environment> mpi_env) {
131132
this_node = comm_cart.rank();
132133

133134
Communication::m_callbacks =
134-
std::make_unique<Communication::MpiCallbacks>(comm_cart);
135+
std::make_shared<Communication::MpiCallbacks>(comm_cart, mpi_env);
135136

136-
ErrorHandling::init_error_handling(mpiCallbacks());
137+
ErrorHandling::init_error_handling(Communication::m_callbacks);
137138

138139
on_program_start();
139140
}
141+
142+
void deinit() { Communication::m_callbacks.reset(); }
140143
} // namespace Communication
141144

142145
std::shared_ptr<boost::mpi::environment> mpi_init(int argc, char **argv) {

src/core/communication.hpp

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ namespace Communication {
6363
* @brief Returns a reference to the global callback class instance.
6464
*/
6565
MpiCallbacks &mpiCallbacks();
66+
std::shared_ptr<MpiCallbacks> mpiCallbacksHandle();
6667
} // namespace Communication
6768

6869
/**************************************************
@@ -136,12 +137,9 @@ namespace Communication {
136137
/**
137138
* @brief Init globals for communication.
138139
*
139-
* and calls @ref on_program_start. Keeps a copy of
140-
* the pointer to the mpi environment to keep it alive
141-
* while the program is loaded.
142-
*
143140
* @param mpi_env MPI environment that should be used
144141
*/
145142
void init(std::shared_ptr<boost::mpi::environment> mpi_env);
143+
void deinit();
146144
} // namespace Communication
147145
#endif

src/core/errorhandling.cpp

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
#include <functional>
3535
#include <memory>
3636
#include <string>
37+
#include <utility>
3738
#include <vector>
3839

3940
namespace ErrorHandling {
@@ -45,14 +46,14 @@ namespace {
4546
std::unique_ptr<RuntimeErrorCollector> runtimeErrorCollector;
4647

4748
/** The callback loop we are on. */
48-
Communication::MpiCallbacks *m_callbacks = nullptr;
49+
std::weak_ptr<Communication::MpiCallbacks> m_callbacks;
4950
} // namespace
5051

51-
void init_error_handling(Communication::MpiCallbacks &cb) {
52-
m_callbacks = &cb;
52+
void init_error_handling(std::weak_ptr<Communication::MpiCallbacks> callbacks) {
53+
m_callbacks = std::move(callbacks);
5354

5455
runtimeErrorCollector =
55-
std::make_unique<RuntimeErrorCollector>(m_callbacks->comm());
56+
std::make_unique<RuntimeErrorCollector>(m_callbacks.lock()->comm());
5657
}
5758

5859
RuntimeErrorStream _runtimeMessageStream(RuntimeError::ErrorLevel level,
@@ -69,7 +70,7 @@ static void mpi_gather_runtime_errors_local() {
6970
REGISTER_CALLBACK(mpi_gather_runtime_errors_local)
7071

7172
std::vector<RuntimeError> mpi_gather_runtime_errors() {
72-
m_callbacks->call(mpi_gather_runtime_errors_local);
73+
m_callbacks.lock()->call(mpi_gather_runtime_errors_local);
7374
return runtimeErrorCollector->gather();
7475
}
7576

@@ -83,7 +84,7 @@ std::vector<RuntimeError> mpi_gather_runtime_errors_all(bool is_head_node) {
8384
} // namespace ErrorHandling
8485

8586
void errexit() {
86-
ErrorHandling::m_callbacks->comm().abort(1);
87+
ErrorHandling::m_callbacks.lock()->comm().abort(1);
8788

8889
std::abort();
8990
}

src/core/errorhandling.hpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
#include "error_handling/RuntimeError.hpp"
3232
#include "error_handling/RuntimeErrorStream.hpp"
3333

34+
#include <memory>
3435
#include <string>
3536
#include <vector>
3637

@@ -85,7 +86,7 @@ namespace ErrorHandling {
8586
*
8687
* @param callbacks Callbacks system the error handler should be on.
8788
*/
88-
void init_error_handling(Communication::MpiCallbacks &callbacks);
89+
void init_error_handling(std::weak_ptr<Communication::MpiCallbacks> callbacks);
8990

9091
RuntimeErrorStream _runtimeMessageStream(RuntimeError::ErrorLevel level,
9192
const std::string &file, int line,

src/core/particle_node.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -407,7 +407,7 @@ static int mpi_place_new_particle(int p_id, const Utils::Vector3d &pos) {
407407

408408
void mpi_place_particle_local(int pnode, int p_id) {
409409
if (pnode == this_node) {
410-
Utils::Vector3d pos;
410+
Utils::Vector3d pos{};
411411
comm_cart.recv(0, some_tag, pos);
412412
local_move_particle(p_id, pos);
413413
}

src/core/unit_tests/EspressoSystemStandAlone_test.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -357,5 +357,7 @@ BOOST_FIXTURE_TEST_CASE(espresso_system_stand_alone, ParticleFactory,
357357
int main(int argc, char **argv) {
358358
espresso::system = std::make_unique<EspressoSystemStandAlone>(argc, argv);
359359

360-
return boost::unit_test::unit_test_main(init_unit_test, argc, argv);
360+
int retval = boost::unit_test::unit_test_main(init_unit_test, argc, argv);
361+
espresso::system.reset();
362+
return retval;
361363
}

0 commit comments

Comments
 (0)