// 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