1 /*
2  * Copyright (C) by Argonne National Laboratory
3  *     See COPYRIGHT in top-level directory
4  */
5 
6 #include "mpidimpl.h"
7 #include "mpidrma.h"
8 
MPIDI_CH3U_Handle_send_req(MPIDI_VC_t * vc,MPIR_Request * sreq,int * complete)9 int MPIDI_CH3U_Handle_send_req(MPIDI_VC_t * vc, MPIR_Request * sreq, int *complete)
10 {
11     int mpi_errno = MPI_SUCCESS;
12     int (*reqFn) (MPIDI_VC_t *, MPIR_Request *, int *);
13     MPIR_FUNC_VERBOSE_STATE_DECL(MPID_STATE_MPIDI_CH3U_HANDLE_SEND_REQ);
14 
15     MPIR_FUNC_VERBOSE_ENTER(MPID_STATE_MPIDI_CH3U_HANDLE_SEND_REQ);
16 
17     /* Use the associated function rather than switching on the old ca field */
18     /* Routines can call the attached function directly */
19     reqFn = sreq->dev.OnDataAvail;
20     if (!reqFn) {
21         MPIR_Assert(MPIDI_Request_get_type(sreq) != MPIDI_REQUEST_TYPE_GET_RESP);
22         mpi_errno = MPID_Request_complete(sreq);
23         *complete = 1;
24     }
25     else {
26         mpi_errno = reqFn(vc, sreq, complete);
27     }
28     MPIR_ERR_CHECK(mpi_errno);
29 
30   fn_exit:
31     MPIR_FUNC_VERBOSE_EXIT(MPID_STATE_MPIDI_CH3U_HANDLE_SEND_REQ);
32     return mpi_errno;
33   fn_fail:
34     goto fn_exit;
35 }
36 
37 /* ----------------------------------------------------------------------- */
38 /* Here are the functions that implement the actions that are taken when
39  * data is available for a send request (or other completion operations)
40  * These include "send" requests that are part of the RMA implementation.
41  */
42 /* ----------------------------------------------------------------------- */
43 
MPIDI_CH3_ReqHandler_GetSendComplete(MPIDI_VC_t * vc ATTRIBUTE ((unused)),MPIR_Request * sreq,int * complete)44 int MPIDI_CH3_ReqHandler_GetSendComplete(MPIDI_VC_t * vc ATTRIBUTE((unused)),
45                                          MPIR_Request * sreq, int *complete)
46 {
47     int mpi_errno = MPI_SUCCESS;
48     MPIR_Win *win_ptr;
49     int pkt_flags = sreq->dev.pkt_flags;
50 
51     /* NOTE: It is possible that this request is already completed before
52      * entering this handler. This happens when this req handler is called
53      * within the same req handler on the same request.
54      * Consider this case: req is queued up in SHM queue with ref count of 2:
55      * one is for completing the request and another is for dequeueing from
56      * the queue. The first called req handler on this request completed
57      * this request and decrement ref counter to 1. Request is still in the
58      * queue. Within this handler, we call the req handler on the same request
59      * for the second time (for example when making progress on SHM queue),
60      * and the second called handler also tries to complete this request,
61      * which leads to wrong execution.
62      * Here we check if req is already completed to prevent processing the
63      * same request twice. */
64     if (MPIR_Request_is_complete(sreq)) {
65         *complete = FALSE;
66         goto fn_exit;
67     }
68 
69     MPIR_Win_get_ptr(sreq->dev.target_win_handle, win_ptr);
70 
71     /* here we decrement the Active Target counter to guarantee the GET-like
72      * operation are completed when counter reaches zero. */
73     win_ptr->at_completion_counter--;
74     MPIR_Assert(win_ptr->at_completion_counter >= 0);
75 
76     /* mark data transfer as complete and decrement CC */
77     mpi_errno = MPID_Request_complete(sreq);
78     MPIR_ERR_CHECK(mpi_errno);
79 
80     /* NOTE: finish_op_on_target() must be called after we complete this request,
81      * because inside finish_op_on_target() we may call this request handler
82      * on the same request again (in release_lock()). Marking this request as
83      * completed will prevent us from processing the same request twice. */
84     mpi_errno = finish_op_on_target(win_ptr, vc, TRUE /* has response data */ ,
85                                     pkt_flags, MPI_WIN_NULL);
86     MPIR_ERR_CHECK(mpi_errno);
87 
88     *complete = TRUE;
89 
90   fn_exit:
91     return mpi_errno;
92   fn_fail:
93     goto fn_exit;
94 }
95 
MPIDI_CH3_ReqHandler_GaccumSendComplete(MPIDI_VC_t * vc,MPIR_Request * rreq,int * complete)96 int MPIDI_CH3_ReqHandler_GaccumSendComplete(MPIDI_VC_t * vc, MPIR_Request * rreq, int *complete)
97 {
98     int mpi_errno = MPI_SUCCESS;
99     MPIR_Win *win_ptr;
100     int pkt_flags = rreq->dev.pkt_flags;
101     MPIR_FUNC_VERBOSE_STATE_DECL(MPID_STATE_MPIDI_CH3_REQHANDLER_GACCUMSENDCOMPLETE);
102 
103     MPIR_FUNC_VERBOSE_ENTER(MPID_STATE_MPIDI_CH3_REQHANDLER_GACCUMSENDCOMPLETE);
104 
105     /* NOTE: It is possible that this request is already completed before
106      * entering this handler. This happens when this req handler is called
107      * within the same req handler on the same request.
108      * Consider this case: req is queued up in SHM queue with ref count of 2:
109      * one is for completing the request and another is for dequeueing from
110      * the queue. The first called req handler on this request completed
111      * this request and decrement ref counter to 1. Request is still in the
112      * queue. Within this handler, we call the req handler on the same request
113      * for the second time (for example when making progress on SHM queue),
114      * and the second called handler also tries to complete this request,
115      * which leads to wrong execution.
116      * Here we check if req is already completed to prevent processing the
117      * same request twice. */
118     if (MPIR_Request_is_complete(rreq)) {
119         *complete = FALSE;
120         goto fn_exit;
121     }
122 
123     /* This function is triggered when sending back process of GACC/FOP/CAS
124      * is finished. Only GACC used user_buf. FOP and CAS can fit all data
125      * in response packet. */
126     MPL_free(rreq->dev.user_buf);
127 
128     MPIR_Win_get_ptr(rreq->dev.target_win_handle, win_ptr);
129 
130     /* here we decrement the Active Target counter to guarantee the GET-like
131      * operation are completed when counter reaches zero. */
132     win_ptr->at_completion_counter--;
133     MPIR_Assert(win_ptr->at_completion_counter >= 0);
134 
135     mpi_errno = MPID_Request_complete(rreq);
136     MPIR_ERR_CHECK(mpi_errno);
137 
138     /* NOTE: finish_op_on_target() must be called after we complete this request,
139      * because inside finish_op_on_target() we may call this request handler
140      * on the same request again (in release_lock()). Marking this request as
141      * completed will prevent us from processing the same request twice. */
142     mpi_errno = finish_op_on_target(win_ptr, vc, TRUE /* has response data */ ,
143                                     pkt_flags, MPI_WIN_NULL);
144     MPIR_ERR_CHECK(mpi_errno);
145 
146     *complete = TRUE;
147 
148   fn_exit:
149     MPIR_FUNC_VERBOSE_EXIT(MPID_STATE_MPIDI_CH3_REQHANDLER_GACCUMSENDCOMPLETE);
150     return mpi_errno;
151 
152   fn_fail:
153     goto fn_exit;
154 }
155 
156 
MPIDI_CH3_ReqHandler_CASSendComplete(MPIDI_VC_t * vc,MPIR_Request * rreq,int * complete)157 int MPIDI_CH3_ReqHandler_CASSendComplete(MPIDI_VC_t * vc, MPIR_Request * rreq, int *complete)
158 {
159     int mpi_errno = MPI_SUCCESS;
160     MPIR_Win *win_ptr;
161     int pkt_flags = rreq->dev.pkt_flags;
162     MPIR_FUNC_VERBOSE_STATE_DECL(MPID_STATE_MPIDI_CH3_REQHANDLER_CASSENDCOMPLETE);
163 
164     MPIR_FUNC_VERBOSE_ENTER(MPID_STATE_MPIDI_CH3_REQHANDLER_CASSENDCOMPLETE);
165 
166     /* NOTE: It is possible that this request is already completed before
167      * entering this handler. This happens when this req handler is called
168      * within the same req handler on the same request.
169      * Consider this case: req is queued up in SHM queue with ref count of 2:
170      * one is for completing the request and another is for dequeueing from
171      * the queue. The first called req handler on this request completed
172      * this request and decrement ref counter to 1. Request is still in the
173      * queue. Within this handler, we call the req handler on the same request
174      * for the second time (for example when making progress on SHM queue),
175      * and the second called handler also tries to complete this request,
176      * which leads to wrong execution.
177      * Here we check if req is already completed to prevent processing the
178      * same request twice. */
179     if (MPIR_Request_is_complete(rreq)) {
180         *complete = FALSE;
181         goto fn_exit;
182     }
183 
184     /* This function is triggered when sending back process of GACC/FOP/CAS
185      * is finished. Only GACC used user_buf. FOP and CAS can fit all data
186      * in response packet. */
187     MPL_free(rreq->dev.user_buf);
188 
189     MPIR_Win_get_ptr(rreq->dev.target_win_handle, win_ptr);
190 
191     /* here we decrement the Active Target counter to guarantee the GET-like
192      * operation are completed when counter reaches zero. */
193     win_ptr->at_completion_counter--;
194     MPIR_Assert(win_ptr->at_completion_counter >= 0);
195 
196     mpi_errno = MPID_Request_complete(rreq);
197     MPIR_ERR_CHECK(mpi_errno);
198 
199     /* NOTE: finish_op_on_target() must be called after we complete this request,
200      * because inside finish_op_on_target() we may call this request handler
201      * on the same request again (in release_lock()). Marking this request as
202      * completed will prevent us from processing the same request twice. */
203     mpi_errno = finish_op_on_target(win_ptr, vc, TRUE /* has response data */ ,
204                                     pkt_flags, MPI_WIN_NULL);
205     MPIR_ERR_CHECK(mpi_errno);
206 
207     *complete = TRUE;
208 
209   fn_exit:
210     MPIR_FUNC_VERBOSE_EXIT(MPID_STATE_MPIDI_CH3_REQHANDLER_CASSENDCOMPLETE);
211     return mpi_errno;
212 
213   fn_fail:
214     goto fn_exit;
215 }
216 
MPIDI_CH3_ReqHandler_FOPSendComplete(MPIDI_VC_t * vc,MPIR_Request * rreq,int * complete)217 int MPIDI_CH3_ReqHandler_FOPSendComplete(MPIDI_VC_t * vc, MPIR_Request * rreq, int *complete)
218 {
219     int mpi_errno = MPI_SUCCESS;
220     MPIR_Win *win_ptr;
221     int pkt_flags = rreq->dev.pkt_flags;
222     MPIR_FUNC_VERBOSE_STATE_DECL(MPID_STATE_MPIDI_CH3_REQHANDLER_FOPSENDCOMPLETE);
223 
224     MPIR_FUNC_VERBOSE_ENTER(MPID_STATE_MPIDI_CH3_REQHANDLER_FOPSENDCOMPLETE);
225 
226     /* NOTE: It is possible that this request is already completed before
227      * entering this handler. This happens when this req handler is called
228      * within the same req handler on the same request.
229      * Consider this case: req is queued up in SHM queue with ref count of 2:
230      * one is for completing the request and another is for dequeueing from
231      * the queue. The first called req handler on this request completed
232      * this request and decrement ref counter to 1. Request is still in the
233      * queue. Within this handler, we call the req handler on the same request
234      * for the second time (for example when making progress on SHM queue),
235      * and the second called handler also tries to complete this request,
236      * which leads to wrong execution.
237      * Here we check if req is already completed to prevent processing the
238      * same request twice. */
239     if (MPIR_Request_is_complete(rreq)) {
240         *complete = FALSE;
241         goto fn_exit;
242     }
243 
244     /* This function is triggered when sending back process of GACC/FOP/CAS
245      * is finished. Only GACC used user_buf. FOP and CAS can fit all data
246      * in response packet. */
247     MPL_free(rreq->dev.user_buf);
248 
249     MPIR_Win_get_ptr(rreq->dev.target_win_handle, win_ptr);
250 
251     /* here we decrement the Active Target counter to guarantee the GET-like
252      * operation are completed when counter reaches zero. */
253     win_ptr->at_completion_counter--;
254     MPIR_Assert(win_ptr->at_completion_counter >= 0);
255 
256     mpi_errno = MPID_Request_complete(rreq);
257     MPIR_ERR_CHECK(mpi_errno);
258 
259     /* NOTE: finish_op_on_target() must be called after we complete this request,
260      * because inside finish_op_on_target() we may call this request handler
261      * on the same request again (in release_lock()). Marking this request as
262      * completed will prevent us from processing the same request twice. */
263     mpi_errno = finish_op_on_target(win_ptr, vc, TRUE /* has response data */ ,
264                                     pkt_flags, MPI_WIN_NULL);
265     MPIR_ERR_CHECK(mpi_errno);
266 
267     *complete = TRUE;
268 
269   fn_exit:
270     MPIR_FUNC_VERBOSE_EXIT(MPID_STATE_MPIDI_CH3_REQHANDLER_FOPSENDCOMPLETE);
271     return mpi_errno;
272 
273   fn_fail:
274     goto fn_exit;
275 }
276 
277 
MPIDI_CH3_ReqHandler_SendReloadIOV(MPIDI_VC_t * vc ATTRIBUTE ((unused)),MPIR_Request * sreq,int * complete)278 int MPIDI_CH3_ReqHandler_SendReloadIOV(MPIDI_VC_t * vc ATTRIBUTE((unused)), MPIR_Request * sreq,
279                                        int *complete)
280 {
281     int mpi_errno;
282 
283     /* setting the iov_offset to 0 here is critical, since it is intentionally
284      * not set in the _load_send_iov function */
285     sreq->dev.iov_offset = 0;
286     sreq->dev.iov_count = MPL_IOV_LIMIT;
287     mpi_errno = MPIDI_CH3U_Request_load_send_iov(sreq, sreq->dev.iov, &sreq->dev.iov_count);
288     if (mpi_errno != MPI_SUCCESS) {
289         MPIR_ERR_SETFATALANDJUMP(mpi_errno, MPI_ERR_OTHER, "**ch3|loadsendiov");
290     }
291 
292     *complete = FALSE;
293 
294   fn_fail:
295     return mpi_errno;
296 }
297