MySources/boost_graph/libs/mpi/src/request.cpp

240 lines
6.9 KiB
C++

// Copyright (C) 2006 Douglas Gregor.
// Use, modification and distribution is subject to the Boost Software
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// 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
}
/***************************************************************************
* handlers *
***************************************************************************/
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::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()
{
// 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>();
}
}
void
request::dynamic_handler::cancel()
{
BOOST_MPI_CHECK_RESULT(MPI_Cancel, (&m_requests[0]));
BOOST_MPI_CHECK_RESULT(MPI_Cancel, (&m_requests[1]));
}
bool
request::dynamic_handler::active() const
{
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