#include "gromacs/mdrun/legacymdrunoptions.h"
#include "gromacs/mdtypes/mdrunoptions.h"
-// Above are headers for dependencies.
-// Following are public headers for the current module.
#include "gmxapi/context.h"
#include "gmxapi/session.h"
{
/*!
- * \brief Context implementation base class.
+ * \brief Provide RAII management of communications resource state.
*
- * Execution contexts have a uniform interface specified by the API. Implementations for
- * particular execution environments can specialize / derive from this base.
+ * To acquire an MpiContextManager is to have assurance that any external MPI
+ * environment is ready to use. When the MpiContextManager is released or
+ * goes out of scope, the destructor finalizes the resources.
+ *
+ * Note that thread-MPI chooses the number of ranks and constructs its
+ * MPI communicator internally, so does not and is unlikely to ever
+ * participate here.
+ *
+ * \todo There is no resource for logging or reporting errors during initialization
*
- * \todo Separate interface and implementation.
* \ingroup gmxapi
*/
-class ContextImpl final : public std::enable_shared_from_this<ContextImpl>
+class MpiContextManager
{
public:
+ MpiContextManager();
+
+ ~MpiContextManager();
+
/*!
- * \brief Default constructor.
+ * \brief Exclusive ownership of a scoped context means copying is impossible.
*
- * Don't use this. Use create() to get a shared pointer right away.
- * Otherwise, shared_from_this() is potentially dangerous.
+ * \{
+ */
+ MpiContextManager(const MpiContextManager&) = delete;
+ MpiContextManager& operator=(const MpiContextManager&) = delete;
+ //! \}
+
+ /*!
+ * \brief Move semantics are non-trivial.
*
- * \todo Make default constructor private or otherwise reduce brittleness of construction.
+ * \{
*/
- ContextImpl();
+ MpiContextManager(MpiContextManager&&) noexcept = delete;
+ MpiContextManager& operator=(MpiContextManager&&) noexcept = delete;
+ //! \}
+};
+
+/*!
+ * \brief Context implementation.
+ *
+ * Execution contexts have a uniform interface specified by the API. Implementations for
+ * particular execution environments can specialize / derive from this base.
+ *
+ * \todo Separate interface and implementation.
+ *
+ * \warning Definition and semantics depend on configure-time details. For example,
+ * MPI-enabled libraries always hold a valid MPI communicator via MpiContextManager,
+ * whereas tMPI and non-MPI builds hold a meaningless MpiContextManager.
+ *
+ * \todo Provide functions or traits for introspection.
+ *
+ * \ingroup gmxapi
+ */
+class ContextImpl final : public std::enable_shared_from_this<ContextImpl>
+{
+public:
+ ~ContextImpl();
/*!
* \brief Factory function
* that it never exists without a shared_ptr owning it.
*
* If we can confirm `shared_from_this` is no longer necessary, implementation may change.
+ * \todo: Use registration/deregistration of launched Sessions to log warnings on shutdown
+ * instead of letting Session keep ContextImpl alive.
*
* \return ownership of a new object
*/
- static std::shared_ptr<gmxapi::ContextImpl> create();
+ static std::shared_ptr<ContextImpl> create();
/*!
* \brief Copy disallowed because Session state would become ambiguous.
/*!
* \brief Objects are not trivial to move.
*
- * \todo Implement move semantics.
+ * \todo Implement move semantics. Requires a moveable const MpiContextManager and
+ * LegacyMdrunOptions members.
+ *
* \{
*/
ContextImpl(ContextImpl&&) = delete;
* are still evolving.
* \todo Hide lifetime management and ownership from handle object.
* We can achieve the necessary aspects of this shared_ptr at a lower level of implementation.
+ * Note also that returned value policies can be implemented in higher level wrappers to ensure
+ * correct object lifetime scope. (See pybind, for instance.)
*/
std::shared_ptr<Session> launch(const Workflow& work);
*
* The client owns the Session launched by a Context, but it is helpful
* for the Context to know if it has an active Session associated with it.
+ *
+ * \todo Use registration/deregistration protocol instead.
+ * Requires logging facility.
*/
std::weak_ptr<Session> session_;
* duplicate definitions e.g. of command-line options.
*/
gmx::LegacyMdrunOptions options_;
+
+ /*!
+ * \brief Scoped MPI management.
+ *
+ * Part of the ContextImpl invariant establishes a point where MPI initialization status is
+ * known.
+ *
+ * To ensure the MpiContextManager is initialized only once, we use a const member that must
+ * be initialized at construction.
+ */
+ const MpiContextManager mpi_;
+
+private:
+ /*!
+ * \brief Basic constructor.
+ *
+ * Don't use this. Use create() to get a shared pointer right away.
+ * Otherwise, shared_from_this() is potentially dangerous.
+ */
+ explicit ContextImpl() noexcept(std::is_nothrow_constructible_v<gmx::LegacyMdrunOptions>);
+};
+
+
+class CommHandle
+{
+public:
+ using commType = MPI_Comm;
+ MPI_Comm communicator{ MPI_COMM_NULL };
};
} // end namespace gmxapi