]> git.proxmox.com Git - ceph.git/blobdiff - ceph/src/boost/libs/mpi/src/request.cpp
import new upstream nautilus stable release 14.2.8
[ceph.git] / ceph / src / boost / libs / mpi / src / request.cpp
index 9bc842f2ea1898c5ef9fcd965199943e0cf69702..3ba5695aa71b66cd70ebb238a511edb6d5ef41d2 100644 (file)
 // http://www.boost.org/LICENSE_1_0.txt)
 #include <boost/mpi/request.hpp>
 #include <boost/mpi/status.hpp>
+#include <boost/mpi/communicator.hpp>
+#include <boost/mpi/detail/request_handlers.hpp>
 
 namespace boost { namespace mpi {
 
+request::request() 
+  : m_handler() {}
+
+void
+request::preserve(boost::shared_ptr<void> d) {
+  if (!m_preserved) {
+    m_preserved = d; 
+  } else {
+    boost::shared_ptr<void> cdr = m_preserved;
+    typedef std::pair<boost::shared_ptr<void>, boost::shared_ptr<void> > cons;
+    boost::shared_ptr<cons> p(new cons(d, cdr));
+    m_preserved = p;
+  }
+}
+request request::make_dynamic() { return request(new dynamic_handler()); }
+
+request
+request::make_bottom_send(communicator const& comm, int dest, int tag, MPI_Datatype tp) {
+  trivial_handler* handler = new trivial_handler;
+  BOOST_MPI_CHECK_RESULT(MPI_Isend,
+                         (MPI_BOTTOM, 1, tp,
+                          dest, tag, comm, &handler->m_request));
+  return request(handler);
+}
+
+request
+request::make_empty_send(communicator const& comm, int dest, int tag) {
+  trivial_handler* handler = new trivial_handler;
+  BOOST_MPI_CHECK_RESULT(MPI_Isend,
+                         (MPI_BOTTOM, 0, MPI_PACKED,
+                          dest, tag, comm, &handler->m_request));
+  return request(handler);
+}
+
+request
+request::make_bottom_recv(communicator const& comm, int dest, int tag, MPI_Datatype tp) {
+  trivial_handler* handler = new trivial_handler;
+  BOOST_MPI_CHECK_RESULT(MPI_Irecv,
+                         (MPI_BOTTOM, 1, tp,
+                          dest, tag, comm, &handler->m_request));
+  return request(handler);
+}
+
+request
+request::make_empty_recv(communicator const& comm, int dest, int tag) {
+  trivial_handler* handler = new trivial_handler;
+  BOOST_MPI_CHECK_RESULT(MPI_Irecv,
+                         (MPI_BOTTOM, 0, MPI_PACKED,
+                          dest, tag, comm, &handler->m_request));
+  return request(handler);
+}
+
+request
+request::make_packed_send(communicator const& comm, int dest, int tag, void const* buffer, std::size_t n) {
+#if defined(BOOST_MPI_USE_IMPROBE)
+  {
+    trivial_handler* handler = new trivial_handler;
+    BOOST_MPI_CHECK_RESULT(MPI_Isend,
+                           (const_cast<void*>(buffer), n, MPI_PACKED,
+                            dest, tag, comm, &handler->m_request));
+    return request(handler);
+  }
+#else
+  {
+    dynamic_handler *handler = new dynamic_handler;
+    request req(handler);
+    shared_ptr<std::size_t> size(new std::size_t(n));
+    req.preserve(size);
+    BOOST_MPI_CHECK_RESULT(MPI_Isend,
+                           (size.get(), 1, 
+                            get_mpi_datatype(*size), 
+                            dest, tag, comm, handler->m_requests));
+    BOOST_MPI_CHECK_RESULT(MPI_Isend,
+                           (const_cast<void*>(buffer), *size,
+                            MPI_PACKED,
+                            dest, tag, comm, handler->m_requests+1));
+    return req;
+  }
+#endif
+}
+
 /***************************************************************************
- * request                                                                 *
+ * handlers                                                                *
  ***************************************************************************/
-request::request()
-  : m_handler(0), m_data()
+
+request::handler::~handler() {}
+    
+optional<MPI_Request&>
+request::legacy_handler::trivial() {
+  return boost::none;
+}
+
+bool
+request::legacy_handler::active() const {
+  return m_requests[0] != MPI_REQUEST_NULL || m_requests[1] != MPI_REQUEST_NULL;
+}
+
+// trivial handler
+
+request::trivial_handler::trivial_handler()
+    : m_request(MPI_REQUEST_NULL) {}
+  
+status
+request::trivial_handler::wait()
+{
+  status result;
+  BOOST_MPI_CHECK_RESULT(MPI_Wait, (&m_request, &result.m_status));
+  return result;  
+}
+
+
+optional<status>
+request::trivial_handler::test() 
+{
+  status result;
+  int flag = 0;
+  BOOST_MPI_CHECK_RESULT(MPI_Test, 
+                         (&m_request, &flag, &result.m_status));
+  return flag != 0? optional<status>(result) : optional<status>();
+}
+
+void
+request::trivial_handler::cancel()
+{
+  BOOST_MPI_CHECK_RESULT(MPI_Cancel, (&m_request));
+}
+  
+bool
+request::trivial_handler::active() const
+{
+  return m_request != MPI_REQUEST_NULL; 
+}
+
+optional<MPI_Request&>
+request::trivial_handler::trivial() 
+{ 
+  return m_request; 
+}
+  
+// dynamic handler
+
+request::dynamic_handler::dynamic_handler()
 {
   m_requests[0] = MPI_REQUEST_NULL;
   m_requests[1] = MPI_REQUEST_NULL;
 }
-
-status request::wait()
+  
+status
+request::dynamic_handler::wait()
+{
+  // This request is a send of a serialized type, broken into two
+  // separate messages. Complete both sends at once.
+  MPI_Status stats[2];
+  int error_code = MPI_Waitall(2, m_requests, stats);
+  if (error_code == MPI_ERR_IN_STATUS) {
+    // Dig out which status structure has the error, and use that
+    // one when throwing the exception.
+    if (stats[0].MPI_ERROR == MPI_SUCCESS 
+        || stats[0].MPI_ERROR == MPI_ERR_PENDING)
+      boost::throw_exception(exception("MPI_Waitall", stats[1].MPI_ERROR));
+    else
+      boost::throw_exception(exception("MPI_Waitall", stats[0].MPI_ERROR));
+  } else if (error_code != MPI_SUCCESS) {
+    // There was an error somewhere in the MPI_Waitall call; throw
+    // an exception for it.
+    boost::throw_exception(exception("MPI_Waitall", error_code));
+  } 
+  
+  // No errors. Returns the first status structure.
+  status result;
+  result.m_status = stats[0];
+  return result;
+}
+optional<status>
+request::dynamic_handler::test()
 {
-  if (m_handler) {
-    // This request is a receive for a serialized type. Use the
-    // handler to wait for completion.
-    return *m_handler(this, ra_wait);
-  } else if (m_requests[1] == MPI_REQUEST_NULL) {
-    // This request is either a send or a receive for a type with an
-    // associated MPI datatype, or a serialized datatype that has been
-    // packed into a single message. Just wait on the one receive/send
-    // and return the status to the user.
+  // This request is a send of a serialized type, broken into two
+  // separate messages. We only get a result if both complete.
+  MPI_Status stats[2];
+  int flag = 0;
+  int error_code = MPI_Testall(2, m_requests, &flag, stats);
+  if (error_code == MPI_ERR_IN_STATUS) {
+    // Dig out which status structure has the error, and use that
+    // one when throwing the exception.
+    if (stats[0].MPI_ERROR == MPI_SUCCESS 
+        || stats[0].MPI_ERROR == MPI_ERR_PENDING)
+      boost::throw_exception(exception("MPI_Testall", stats[1].MPI_ERROR));
+    else
+      boost::throw_exception(exception("MPI_Testall", stats[0].MPI_ERROR));
+  } else if (error_code != MPI_SUCCESS) {
+    // There was an error somewhere in the MPI_Testall call; throw
+    // an exception for it.
+    boost::throw_exception(exception("MPI_Testall", error_code));
+  }
+  
+  // No errors. Returns the second status structure if the send has
+  // completed.
+  if (flag != 0) {
     status result;
-    BOOST_MPI_CHECK_RESULT(MPI_Wait, (&m_requests[0], &result.m_status));
+    result.m_status = stats[1];
     return result;
   } else {
-    // This request is a send of a serialized type, broken into two
-    // separate messages. Complete both sends at once.
-    MPI_Status stats[2];
-    int error_code = MPI_Waitall(2, m_requests, stats);
-    if (error_code == MPI_ERR_IN_STATUS) {
-      // Dig out which status structure has the error, and use that
-      // one when throwing the exception.
-      if (stats[0].MPI_ERROR == MPI_SUCCESS 
-          || stats[0].MPI_ERROR == MPI_ERR_PENDING)
-        boost::throw_exception(exception("MPI_Waitall", stats[1].MPI_ERROR));
-      else
-        boost::throw_exception(exception("MPI_Waitall", stats[0].MPI_ERROR));
-    } else if (error_code != MPI_SUCCESS) {
-      // There was an error somewhere in the MPI_Waitall call; throw
-      // an exception for it.
-      boost::throw_exception(exception("MPI_Waitall", error_code));
-    } 
-
-    // No errors. Returns the first status structure.
-    status result;
-    result.m_status = stats[0];
-    return result;
+    return optional<status>();
   }
 }
 
-optional<status> request::test()
+void
+request::dynamic_handler::cancel()
 {
-  if (m_handler) {
-    // This request is a receive for a serialized type. Use the
-    // handler to test for completion.
-    return m_handler(this, ra_test);
-  } else if (m_requests[1] == MPI_REQUEST_NULL) {
-    // This request is either a send or a receive for a type with an
-    // associated MPI datatype, or a serialized datatype that has been
-    // packed into a single message. Just test the one receive/send
-    // and return the status to the user if it has completed.
-    status result;
-    int flag = 0;
-    BOOST_MPI_CHECK_RESULT(MPI_Test, 
-                           (&m_requests[0], &flag, &result.m_status));
-    return flag != 0? optional<status>(result) : optional<status>();
-  } else {
-    // This request is a send of a serialized type, broken into two
-    // separate messages. We only get a result if both complete.
-    MPI_Status stats[2];
-    int flag = 0;
-    int error_code = MPI_Testall(2, m_requests, &flag, stats);
-    if (error_code == MPI_ERR_IN_STATUS) {
-      // Dig out which status structure has the error, and use that
-      // one when throwing the exception.
-      if (stats[0].MPI_ERROR == MPI_SUCCESS 
-          || stats[0].MPI_ERROR == MPI_ERR_PENDING)
-        boost::throw_exception(exception("MPI_Testall", stats[1].MPI_ERROR));
-      else
-        boost::throw_exception(exception("MPI_Testall", stats[0].MPI_ERROR));
-    } else if (error_code != MPI_SUCCESS) {
-      // There was an error somewhere in the MPI_Testall call; throw
-      // an exception for it.
-      boost::throw_exception(exception("MPI_Testall", error_code));
-    }
-
-    // No errors. Returns the second status structure if the send has
-    // completed.
-    if (flag != 0) {
-      status result;
-      result.m_status = stats[1];
-      return result;
-    } else {
-      return optional<status>();
-    }
-  }
+  BOOST_MPI_CHECK_RESULT(MPI_Cancel, (&m_requests[0]));
+  BOOST_MPI_CHECK_RESULT(MPI_Cancel, (&m_requests[1]));
 }
 
-void request::cancel()
+bool
+request::dynamic_handler::active() const
 {
-  if (m_handler) {
-    m_handler(this, ra_cancel);
-  } else {
-    BOOST_MPI_CHECK_RESULT(MPI_Cancel, (&m_requests[0]));
-    if (m_requests[1] != MPI_REQUEST_NULL)
-      BOOST_MPI_CHECK_RESULT(MPI_Cancel, (&m_requests[1]));
-  }
+  return (m_requests[0] != MPI_REQUEST_NULL
+          || m_requests[1] != MPI_REQUEST_NULL);
 }
 
+optional<MPI_Request&>
+request::dynamic_handler::trivial() {
+  return boost::none;
+}
+  
 } } // end namespace boost::mpi