• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (C) 2006 Douglas Gregor.
2 
3 // Use, modification and distribution is subject to the Boost Software
4 // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
5 // http://www.boost.org/LICENSE_1_0.txt)
6 #include <boost/mpi/request.hpp>
7 #include <boost/mpi/status.hpp>
8 #include <boost/mpi/communicator.hpp>
9 #include <boost/mpi/detail/request_handlers.hpp>
10 
11 namespace boost { namespace mpi {
12 
request()13 request::request()
14   : m_handler() {}
15 
16 void
preserve(boost::shared_ptr<void> d)17 request::preserve(boost::shared_ptr<void> d) {
18   if (!m_preserved) {
19     m_preserved = d;
20   } else {
21     boost::shared_ptr<void> cdr = m_preserved;
22     typedef std::pair<boost::shared_ptr<void>, boost::shared_ptr<void> > cons;
23     boost::shared_ptr<cons> p(new cons(d, cdr));
24     m_preserved = p;
25   }
26 }
make_dynamic()27 request request::make_dynamic() { return request(new dynamic_handler()); }
28 
29 request
make_bottom_send(communicator const & comm,int dest,int tag,MPI_Datatype tp)30 request::make_bottom_send(communicator const& comm, int dest, int tag, MPI_Datatype tp) {
31   trivial_handler* handler = new trivial_handler;
32   BOOST_MPI_CHECK_RESULT(MPI_Isend,
33                          (MPI_BOTTOM, 1, tp,
34                           dest, tag, comm, &handler->m_request));
35   return request(handler);
36 }
37 
38 request
make_empty_send(communicator const & comm,int dest,int tag)39 request::make_empty_send(communicator const& comm, int dest, int tag) {
40   trivial_handler* handler = new trivial_handler;
41   BOOST_MPI_CHECK_RESULT(MPI_Isend,
42                          (MPI_BOTTOM, 0, MPI_PACKED,
43                           dest, tag, comm, &handler->m_request));
44   return request(handler);
45 }
46 
47 request
make_bottom_recv(communicator const & comm,int dest,int tag,MPI_Datatype tp)48 request::make_bottom_recv(communicator const& comm, int dest, int tag, MPI_Datatype tp) {
49   trivial_handler* handler = new trivial_handler;
50   BOOST_MPI_CHECK_RESULT(MPI_Irecv,
51                          (MPI_BOTTOM, 1, tp,
52                           dest, tag, comm, &handler->m_request));
53   return request(handler);
54 }
55 
56 request
make_empty_recv(communicator const & comm,int dest,int tag)57 request::make_empty_recv(communicator const& comm, int dest, int tag) {
58   trivial_handler* handler = new trivial_handler;
59   BOOST_MPI_CHECK_RESULT(MPI_Irecv,
60                          (MPI_BOTTOM, 0, MPI_PACKED,
61                           dest, tag, comm, &handler->m_request));
62   return request(handler);
63 }
64 
65 request
make_packed_send(communicator const & comm,int dest,int tag,void const * buffer,std::size_t n)66 request::make_packed_send(communicator const& comm, int dest, int tag, void const* buffer, std::size_t n) {
67 #if defined(BOOST_MPI_USE_IMPROBE)
68   {
69     trivial_handler* handler = new trivial_handler;
70     BOOST_MPI_CHECK_RESULT(MPI_Isend,
71                            (const_cast<void*>(buffer), n, MPI_PACKED,
72                             dest, tag, comm, &handler->m_request));
73     return request(handler);
74   }
75 #else
76   {
77     dynamic_handler *handler = new dynamic_handler;
78     request req(handler);
79     shared_ptr<std::size_t> size(new std::size_t(n));
80     req.preserve(size);
81     BOOST_MPI_CHECK_RESULT(MPI_Isend,
82                            (size.get(), 1,
83                             get_mpi_datatype(*size),
84                             dest, tag, comm, handler->m_requests));
85     BOOST_MPI_CHECK_RESULT(MPI_Isend,
86                            (const_cast<void*>(buffer), *size,
87                             MPI_PACKED,
88                             dest, tag, comm, handler->m_requests+1));
89     return req;
90   }
91 #endif
92 }
93 
94 /***************************************************************************
95  * handlers                                                                *
96  ***************************************************************************/
97 
~handler()98 request::handler::~handler() {}
99 
100 optional<MPI_Request&>
trivial()101 request::legacy_handler::trivial() {
102   return boost::none;
103 }
104 
105 bool
active() const106 request::legacy_handler::active() const {
107   return m_requests[0] != MPI_REQUEST_NULL || m_requests[1] != MPI_REQUEST_NULL;
108 }
109 
110 // trivial handler
111 
trivial_handler()112 request::trivial_handler::trivial_handler()
113     : m_request(MPI_REQUEST_NULL) {}
114 
115 status
wait()116 request::trivial_handler::wait()
117 {
118   status result;
119   BOOST_MPI_CHECK_RESULT(MPI_Wait, (&m_request, &result.m_status));
120   return result;
121 }
122 
123 
124 optional<status>
test()125 request::trivial_handler::test()
126 {
127   status result;
128   int flag = 0;
129   BOOST_MPI_CHECK_RESULT(MPI_Test,
130                          (&m_request, &flag, &result.m_status));
131   return flag != 0? optional<status>(result) : optional<status>();
132 }
133 
134 void
cancel()135 request::trivial_handler::cancel()
136 {
137   BOOST_MPI_CHECK_RESULT(MPI_Cancel, (&m_request));
138 }
139 
140 bool
active() const141 request::trivial_handler::active() const
142 {
143   return m_request != MPI_REQUEST_NULL;
144 }
145 
146 optional<MPI_Request&>
trivial()147 request::trivial_handler::trivial()
148 {
149   return m_request;
150 }
151 
152 // dynamic handler
153 
dynamic_handler()154 request::dynamic_handler::dynamic_handler()
155 {
156   m_requests[0] = MPI_REQUEST_NULL;
157   m_requests[1] = MPI_REQUEST_NULL;
158 }
159 
160 status
wait()161 request::dynamic_handler::wait()
162 {
163   // This request is a send of a serialized type, broken into two
164   // separate messages. Complete both sends at once.
165   MPI_Status stats[2];
166   int error_code = MPI_Waitall(2, m_requests, stats);
167   if (error_code == MPI_ERR_IN_STATUS) {
168     // Dig out which status structure has the error, and use that
169     // one when throwing the exception.
170     if (stats[0].MPI_ERROR == MPI_SUCCESS
171         || stats[0].MPI_ERROR == MPI_ERR_PENDING)
172       boost::throw_exception(exception("MPI_Waitall", stats[1].MPI_ERROR));
173     else
174       boost::throw_exception(exception("MPI_Waitall", stats[0].MPI_ERROR));
175   } else if (error_code != MPI_SUCCESS) {
176     // There was an error somewhere in the MPI_Waitall call; throw
177     // an exception for it.
178     boost::throw_exception(exception("MPI_Waitall", error_code));
179   }
180 
181   // No errors. Returns the first status structure.
182   status result;
183   result.m_status = stats[0];
184   return result;
185 }
186 
187 optional<status>
test()188 request::dynamic_handler::test()
189 {
190   // This request is a send of a serialized type, broken into two
191   // separate messages. We only get a result if both complete.
192   MPI_Status stats[2];
193   int flag = 0;
194   int error_code = MPI_Testall(2, m_requests, &flag, stats);
195   if (error_code == MPI_ERR_IN_STATUS) {
196     // Dig out which status structure has the error, and use that
197     // one when throwing the exception.
198     if (stats[0].MPI_ERROR == MPI_SUCCESS
199         || stats[0].MPI_ERROR == MPI_ERR_PENDING)
200       boost::throw_exception(exception("MPI_Testall", stats[1].MPI_ERROR));
201     else
202       boost::throw_exception(exception("MPI_Testall", stats[0].MPI_ERROR));
203   } else if (error_code != MPI_SUCCESS) {
204     // There was an error somewhere in the MPI_Testall call; throw
205     // an exception for it.
206     boost::throw_exception(exception("MPI_Testall", error_code));
207   }
208 
209   // No errors. Returns the second status structure if the send has
210   // completed.
211   if (flag != 0) {
212     status result;
213     result.m_status = stats[1];
214     return result;
215   } else {
216     return optional<status>();
217   }
218 }
219 
220 void
cancel()221 request::dynamic_handler::cancel()
222 {
223   BOOST_MPI_CHECK_RESULT(MPI_Cancel, (&m_requests[0]));
224   BOOST_MPI_CHECK_RESULT(MPI_Cancel, (&m_requests[1]));
225 }
226 
227 bool
active() const228 request::dynamic_handler::active() const
229 {
230   return (m_requests[0] != MPI_REQUEST_NULL
231           || m_requests[1] != MPI_REQUEST_NULL);
232 }
233 
234 optional<MPI_Request&>
trivial()235 request::dynamic_handler::trivial() {
236   return boost::none;
237 }
238 
239 } } // end namespace boost::mpi
240