1 /*
2  * Copyright (C) by Argonne National Laboratory
3  *     See COPYRIGHT in top-level directory
4  */
5 
6 #include "mpidimpl.h"
7 
8 /* FIXME: Consider using function pointers for invoking persistent requests;
9    if we made those part of the public request structure, the top-level routine
10    could implement startall unless the device wanted to study the requests
11    and reorder them */
12 
13 /* FIXME: Where is the memory registration call in the init routines,
14    in case the channel wishes to take special action (such as pinning for DMA)
15    the memory? This was part of the design. */
16 
17 /* This macro initializes all of the fields in a persistent request */
18 #define MPIDI_Request_create_psreq(sreq_, mpi_errno_, FAIL_)		\
19 {									\
20     (sreq_) = MPIR_Request_create(MPIR_REQUEST_KIND__PREQUEST_SEND);                  \
21     if ((sreq_) == NULL)						\
22     {									\
23 	MPL_DBG_MSG(MPIDI_CH3_DBG_OTHER,VERBOSE,"send request allocation failed");\
24 	(mpi_errno_) = MPIR_ERR_MEMALLOCFAILED;				\
25 	FAIL_;								\
26     }									\
27 									\
28     MPIR_Object_set_ref((sreq_), 1);					\
29     MPIR_cc_set(&(sreq_)->cc, 0);                                       \
30     (sreq_)->comm = comm;						\
31     MPIR_Comm_add_ref(comm);						\
32     (sreq_)->dev.match.parts.rank = rank;				\
33     (sreq_)->dev.match.parts.tag = tag;					\
34     (sreq_)->dev.match.parts.context_id = comm->context_id + context_offset;	\
35     (sreq_)->dev.user_buf = (void *) buf;				\
36     (sreq_)->dev.user_count = count;					\
37     (sreq_)->dev.datatype = datatype;					\
38     (sreq_)->u.persist.real_request = NULL;                             \
39 }
40 
41 
42 /*
43  * MPID_Startall()
44  */
MPID_Startall(int count,MPIR_Request * requests[])45 int MPID_Startall(int count, MPIR_Request * requests[])
46 {
47     int i;
48     int rc;
49     int mpi_errno = MPI_SUCCESS;
50     MPIR_FUNC_VERBOSE_STATE_DECL(MPID_STATE_MPID_STARTALL);
51 
52     MPIR_FUNC_VERBOSE_ENTER(MPID_STATE_MPID_STARTALL);
53 
54     for (i = 0; i < count; i++)
55     {
56 	MPIR_Request * const preq = requests[i];
57 
58         /* continue if the source/dest is MPI_PROC_NULL */
59         if (preq->dev.match.parts.rank == MPI_PROC_NULL)
60             continue;
61 
62 	/* FIXME: The odd 7th arg (match.context_id - comm->context_id)
63 	   is probably to get the context offset.  Do we really need the
64 	   context offset? Is there any case where the offset isn't zero? */
65 	switch (MPIDI_Request_get_type(preq))
66 	{
67 	    case MPIDI_REQUEST_TYPE_RECV:
68 	    {
69 		rc = MPID_Irecv(preq->dev.user_buf, preq->dev.user_count, preq->dev.datatype, preq->dev.match.parts.rank,
70 		    preq->dev.match.parts.tag, preq->comm, preq->dev.match.parts.context_id - preq->comm->recvcontext_id,
71 		    &preq->u.persist.real_request);
72 		break;
73 	    }
74 
75 	    case MPIDI_REQUEST_TYPE_SEND:
76 	    {
77 		rc = MPID_Isend(preq->dev.user_buf, preq->dev.user_count, preq->dev.datatype, preq->dev.match.parts.rank,
78 		    preq->dev.match.parts.tag, preq->comm, preq->dev.match.parts.context_id - preq->comm->context_id,
79 		    &preq->u.persist.real_request);
80 		break;
81 	    }
82 
83 	    case MPIDI_REQUEST_TYPE_RSEND:
84 	    {
85 		rc = MPID_Irsend(preq->dev.user_buf, preq->dev.user_count, preq->dev.datatype, preq->dev.match.parts.rank,
86 		    preq->dev.match.parts.tag, preq->comm, preq->dev.match.parts.context_id - preq->comm->context_id,
87 		    &preq->u.persist.real_request);
88 		break;
89 	    }
90 
91 	    case MPIDI_REQUEST_TYPE_SSEND:
92 	    {
93 		rc = MPID_Issend(preq->dev.user_buf, preq->dev.user_count, preq->dev.datatype, preq->dev.match.parts.rank,
94 		    preq->dev.match.parts.tag, preq->comm, preq->dev.match.parts.context_id - preq->comm->context_id,
95 		    &preq->u.persist.real_request);
96 		break;
97 	    }
98 
99 	    case MPIDI_REQUEST_TYPE_BSEND:
100 	    {
101                 rc = MPIR_Bsend_isend(preq->dev.user_buf, preq->dev.user_count,
102                                       preq->dev.datatype, preq->dev.match.parts.rank,
103                                       preq->dev.match.parts.tag, preq->comm,
104                                       &preq->u.persist.real_request);
105                 if (rc == MPI_SUCCESS) {
106                     preq->status.MPI_ERROR = MPI_SUCCESS;
107                     preq->cc_ptr = &preq->cc;
108                     /* bsend is local-complete */
109                     MPIR_cc_set(preq->cc_ptr, 0);
110                     goto fn_exit;
111                 }
112 		break;
113 	    }
114 
115 	    default:
116 	    {
117 		/* --BEGIN ERROR HANDLING-- */
118 		rc = MPIR_Err_create_code(MPI_SUCCESS, MPIR_ERR_FATAL, __func__, __LINE__, MPI_ERR_INTERN, "**ch3|badreqtype",
119 					  "**ch3|badreqtype %d", MPIDI_Request_get_type(preq));
120 		/* --END ERROR HANDLING-- */
121 	    }
122 	}
123 
124 	if (rc == MPI_SUCCESS)
125 	{
126 	    preq->status.MPI_ERROR = MPI_SUCCESS;
127 	    preq->cc_ptr = &preq->u.persist.real_request->cc;
128 	}
129 	/* --BEGIN ERROR HANDLING-- */
130 	else
131 	{
132 	    /* If a failure occurs attempting to start the request, then we
133 	       assume that partner request was not created, and stuff
134 	       the error code in the persistent request.  The wait and test
135 	       routines will look at the error code in the persistent
136 	       request if a partner request is not present. */
137 	    preq->u.persist.real_request = NULL;
138 	    preq->status.MPI_ERROR = rc;
139 	    preq->cc_ptr = &preq->cc;
140             MPIR_cc_set(&preq->cc, 0);
141 	}
142 	/* --END ERROR HANDLING-- */
143     }
144 
145   fn_exit:
146     MPIR_FUNC_VERBOSE_EXIT(MPID_STATE_MPID_STARTALL);
147     return mpi_errno;
148 }
149 
150 /* FIXME:
151    Move the routines that initialize the persistent requests into this file,
152    since startall must be used with all of them */
153 
154 /*
155  * MPID_Send_init()
156  */
MPID_Send_init(const void * buf,int count,MPI_Datatype datatype,int rank,int tag,MPIR_Comm * comm,int context_offset,MPIR_Request ** request)157 int MPID_Send_init(const void * buf, int count, MPI_Datatype datatype, int rank, int tag, MPIR_Comm * comm, int context_offset,
158 		   MPIR_Request ** request)
159 {
160     MPIR_Request * sreq;
161     int mpi_errno = MPI_SUCCESS;
162     MPIR_FUNC_VERBOSE_STATE_DECL(MPID_STATE_MPID_SEND_INIT);
163 
164     MPIR_FUNC_VERBOSE_ENTER(MPID_STATE_MPID_SEND_INIT);
165 
166     MPIDI_Request_create_psreq(sreq, mpi_errno, goto fn_exit);
167     MPIDI_Request_set_type(sreq, MPIDI_REQUEST_TYPE_SEND);
168     if (!HANDLE_IS_BUILTIN(datatype))
169     {
170 	MPIR_Datatype_get_ptr(datatype, sreq->dev.datatype_ptr);
171     MPIR_Datatype_ptr_add_ref(sreq->dev.datatype_ptr);
172     }
173     *request = sreq;
174 
175   fn_exit:
176     MPIR_FUNC_VERBOSE_EXIT(MPID_STATE_MPID_SEND_INIT);
177     return mpi_errno;
178 }
179 
180 /*
181  * MPID_Ssend_init()
182  */
MPID_Ssend_init(const void * buf,int count,MPI_Datatype datatype,int rank,int tag,MPIR_Comm * comm,int context_offset,MPIR_Request ** request)183 int MPID_Ssend_init(const void * buf, int count, MPI_Datatype datatype, int rank, int tag, MPIR_Comm * comm, int context_offset,
184 		    MPIR_Request ** request)
185 {
186     MPIR_Request * sreq;
187     int mpi_errno = MPI_SUCCESS;
188     MPIR_FUNC_VERBOSE_STATE_DECL(MPID_STATE_MPID_SSEND_INIT);
189 
190     MPIR_FUNC_VERBOSE_ENTER(MPID_STATE_MPID_SSEND_INIT);
191 
192     MPIDI_Request_create_psreq(sreq, mpi_errno, goto fn_exit);
193     MPIDI_Request_set_type(sreq, MPIDI_REQUEST_TYPE_SSEND);
194     if (!HANDLE_IS_BUILTIN(datatype))
195     {
196 	MPIR_Datatype_get_ptr(datatype, sreq->dev.datatype_ptr);
197     MPIR_Datatype_ptr_add_ref(sreq->dev.datatype_ptr);
198     }
199     *request = sreq;
200 
201   fn_exit:
202     MPIR_FUNC_VERBOSE_EXIT(MPID_STATE_MPID_SSEND_INIT);
203     return mpi_errno;
204 }
205 
206 /*
207  * MPID_Rsend_init()
208  */
MPID_Rsend_init(const void * buf,int count,MPI_Datatype datatype,int rank,int tag,MPIR_Comm * comm,int context_offset,MPIR_Request ** request)209 int MPID_Rsend_init(const void * buf, int count, MPI_Datatype datatype, int rank, int tag, MPIR_Comm * comm, int context_offset,
210 		    MPIR_Request ** request)
211 {
212     MPIR_Request * sreq;
213     int mpi_errno = MPI_SUCCESS;
214     MPIR_FUNC_VERBOSE_STATE_DECL(MPID_STATE_MPID_RSEND_INIT);
215 
216     MPIR_FUNC_VERBOSE_ENTER(MPID_STATE_MPID_RSEND_INIT);
217 
218     MPIDI_Request_create_psreq(sreq, mpi_errno, goto fn_exit);
219     MPIDI_Request_set_type(sreq, MPIDI_REQUEST_TYPE_RSEND);
220     if (!HANDLE_IS_BUILTIN(datatype))
221     {
222 	MPIR_Datatype_get_ptr(datatype, sreq->dev.datatype_ptr);
223     MPIR_Datatype_ptr_add_ref(sreq->dev.datatype_ptr);
224     }
225     *request = sreq;
226 
227   fn_exit:
228     MPIR_FUNC_VERBOSE_EXIT(MPID_STATE_MPID_RSEND_INIT);
229     return mpi_errno;
230 }
231 
232 /*
233  * MPID_Bsend_init()
234  */
MPID_Bsend_init(const void * buf,int count,MPI_Datatype datatype,int rank,int tag,MPIR_Comm * comm,int context_offset,MPIR_Request ** request)235 int MPID_Bsend_init(const void * buf, int count, MPI_Datatype datatype, int rank, int tag, MPIR_Comm * comm, int context_offset,
236 		    MPIR_Request ** request)
237 {
238     MPIR_Request * sreq;
239     int mpi_errno = MPI_SUCCESS;
240     MPIR_FUNC_VERBOSE_STATE_DECL(MPID_STATE_MPID_BSEND_INIT);
241 
242     MPIR_FUNC_VERBOSE_ENTER(MPID_STATE_MPID_BSEND_INIT);
243 
244     MPIDI_Request_create_psreq(sreq, mpi_errno, goto fn_exit);
245     MPIDI_Request_set_type(sreq, MPIDI_REQUEST_TYPE_BSEND);
246     if (!HANDLE_IS_BUILTIN(datatype))
247     {
248 	MPIR_Datatype_get_ptr(datatype, sreq->dev.datatype_ptr);
249     MPIR_Datatype_ptr_add_ref(sreq->dev.datatype_ptr);
250     }
251     *request = sreq;
252 
253   fn_exit:
254     MPIR_FUNC_VERBOSE_EXIT(MPID_STATE_MPID_BSEND_INIT);
255     return mpi_errno;
256 }
257 
258 /*
259  * FIXME: The ch3 implmentation of the persistent routines should
260  * be very simple and use common code as much as possible.  All
261  * persistent routine should be in the same file, along with
262  * startall.  Consider using function pointers to specify the
263  * start functions, as if these were generalized requests,
264  * rather than having MPID_Startall look at the request type.
265  */
266 /*
267  * MPID_Recv_init()
268  */
MPID_Recv_init(void * buf,int count,MPI_Datatype datatype,int rank,int tag,MPIR_Comm * comm,int context_offset,MPIR_Request ** request)269 int MPID_Recv_init(void * buf, int count, MPI_Datatype datatype, int rank, int tag, MPIR_Comm * comm, int context_offset,
270 		   MPIR_Request ** request)
271 {
272     MPIR_Request * rreq;
273     int mpi_errno = MPI_SUCCESS;
274     MPIR_FUNC_VERBOSE_STATE_DECL(MPID_STATE_MPID_RECV_INIT);
275 
276     MPIR_FUNC_VERBOSE_ENTER(MPID_STATE_MPID_RECV_INIT);
277 
278     rreq = MPIR_Request_create(MPIR_REQUEST_KIND__PREQUEST_RECV);
279     if (rreq == NULL)
280     {
281 	/* --BEGIN ERROR HANDLING-- */
282 	mpi_errno = MPIR_Err_create_code(MPI_SUCCESS, MPIR_ERR_FATAL, __func__, __LINE__, MPI_ERR_OTHER, "**nomemreq", 0);
283 	/* --END ERROR HANDLING-- */
284 	goto fn_exit;
285     }
286 
287     MPIR_Object_set_ref(rreq, 1);
288     rreq->comm = comm;
289     MPIR_cc_set(&rreq->cc, 0);
290     MPIR_Comm_add_ref(comm);
291     rreq->dev.match.parts.rank = rank;
292     rreq->dev.match.parts.tag = tag;
293     rreq->dev.match.parts.context_id = comm->recvcontext_id + context_offset;
294     rreq->dev.user_buf = (void *) buf;
295     rreq->dev.user_count = count;
296     rreq->dev.datatype = datatype;
297     rreq->u.persist.real_request = NULL;
298     MPIDI_Request_set_type(rreq, MPIDI_REQUEST_TYPE_RECV);
299     if (!HANDLE_IS_BUILTIN(datatype))
300     {
301 	MPIR_Datatype_get_ptr(datatype, rreq->dev.datatype_ptr);
302     MPIR_Datatype_ptr_add_ref(rreq->dev.datatype_ptr);
303     }
304     *request = rreq;
305 
306   fn_exit:
307     MPIR_FUNC_VERBOSE_EXIT(MPID_STATE_MPID_RECV_INIT);
308     return mpi_errno;
309 }
310