1 /* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */
2 /*
3 * Copyright (c) 2013 Mellanox Technologies, Inc.
4 * All rights reserved.
5 * Copyright (c) 2015 Los Alamos National Security, LLC. All rights
6 * reserved.
7 * $COPYRIGHT$
8 *
9 * Additional copyrights may follow
10 *
11 * $HEADER$
12 */
13 /**
14 * @file
15 *
16 * Top-level description of requests
17 */
18
19 #ifndef OSHMEM_REQUEST_H
20 #define OSHMEM_REQUEST_H
21
22 #include "oshmem_config.h"
23 #include "oshmem/constants.h"
24
25 #include "opal/class/opal_free_list.h"
26 #include "opal/class/opal_pointer_array.h"
27 #include "opal/threads/condition.h"
28
29 BEGIN_C_DECLS
30
31 /**
32 * Request class
33 */
34 /*OSHMEM_DECLSPEC OBJ_CLASS_DECLARATION(oshmem_request_t);*/
35 OSHMEM_DECLSPEC OBJ_CLASS_DECLARATION(oshmem_request_t);
36
37 /*
38 * The following include pulls in shared typedefs with debugger plugins.
39 * For more information on why we do this see the Notice to developers
40 * comment at the top of the oshmem_msgq_dll.c file.
41 */
42
43 #include "request_dbg.h"
44
45 struct oshmem_request_t;
46
47 typedef struct oshmem_request_t *SHMEM_Request;
48 typedef struct oshmem_status_public_t SHMEM_Status;
49
50 /* This constants are used to check status of request->req_status.SHMEM_ERROR */
51 #define SHMEM_SUCCESS 0
52 #define SHMEM_ERR_IN_STATUS 18
53
54 /*
55 * SHMEM_Status
56 */
57 struct oshmem_status_public_t {
58 int SHMEM_SOURCE;
59 /*int MPI_TAG;*/
60 int SHMEM_ERROR;
61 int _count;
62 int _cancelled;
63 };
64 typedef struct oshmem_status_public_t oshmem_status_public_t;
65
66 typedef int (SHMEM_Grequest_query_function)(void *, SHMEM_Status *);
67 typedef int (SHMEM_Grequest_free_function)(void *);
68 typedef int (SHMEM_Grequest_cancel_function)(void *, int);
69
70 #define SHMEM_REQUEST_NULL OSHMEM_PREDEFINED_GLOBAL(SHMEM_Request, oshmem_request_null)
71
72 /*
73 * Required function to free the request and any associated resources.
74 */
75 typedef int (*oshmem_request_free_fn_t)(struct oshmem_request_t** rptr);
76
77 /*
78 * Optional function to cancel a pending request.
79 */
80 typedef int (*oshmem_request_cancel_fn_t)(struct oshmem_request_t* request,
81 int flag);
82
83 /*
84 * Optional function called when the request is completed from the SHMEM
85 * library perspective. This function is not allowed to release any
86 * ressources related to the request.
87 */
88 typedef int (*oshmem_request_complete_fn_t)(struct oshmem_request_t* request);
89
90 /* TODO: decide whether to remove comm */
91 /**
92 * Forward declaration
93 */
94 struct oshmem_group_t;
95
96 /**
97 * Forward declaration
98 */
99 /*struct oshmem_file_t;*/
100
101 /**
102 * Union for holding several different SHMEM pointer types on the request
103 */
104 typedef union oshmem_shmem_object_t {
105 struct oshmem_group_t *comm;
106 /* struct oshmem_file_t *file;*/
107 } oshmem_shmem_object_t;
108
109 /**
110 * Main top-level request struct definition
111 */
112 struct oshmem_request_t {
113 opal_free_list_item_t super; /**< Base type *//*TODO: Implement in shmem */
114 oshmem_request_type_t req_type; /**< Enum indicating the type of the request */
115 oshmem_status_public_t req_status; /**< Completion status */
116 volatile bool req_complete; /**< Flag indicating completion on a request */
117 volatile oshmem_request_state_t req_state; /**< enum indicate the state of the request */
118 bool req_persistent; /* TODO: NOT Required */
119 /**< flag indicating if this is a persistent request */
120 int req_f_to_c_index; /* TODO: NOT Required */
121 /**< Index in Fortran <-> C translation array */
122 oshmem_request_free_fn_t req_free; /**< Called by free */
123 oshmem_request_cancel_fn_t req_cancel; /* TODO: Not Required */
124 /**< Optional function to cancel the request */
125 oshmem_request_complete_fn_t req_complete_cb; /**< Called when the request is SHMEM completed */
126 void *req_complete_cb_data;
127 oshmem_shmem_object_t req_shmem_object; /**< Pointer to SHMEM object that created this request */
128 };
129
130 /**
131 * Convenience typedef
132 */
133 typedef struct oshmem_request_t oshmem_request_t;
134
135 /**
136 * Padded struct to maintain back compatibiltiy.
137 * See oshmem/communicator/communicator.h comments with struct oshmem_group_t
138 * for full explanation why we chose the following padding construct for predefines.
139 */
140 #define PREDEFINED_REQUEST_PAD 256
141
142 struct oshmem_predefined_request_t {
143 struct oshmem_request_t request;
144 char padding[PREDEFINED_REQUEST_PAD - sizeof(oshmem_request_t)];
145 };
146
147 typedef struct oshmem_predefined_request_t oshmem_predefined_request_t;
148
149 /**
150 * Initialize a request. This is a macro to avoid function call
151 * overhead, since this is typically invoked in the critical
152 * performance path (since requests may be re-used, it is possible
153 * that we will have to initialize a request multiple times).
154 */
155 #define OSHMEM_REQUEST_INIT(request, persistent) \
156 do { \
157 (request)->req_complete = false; \
158 (request)->req_state = OSHMEM_REQUEST_INACTIVE; \
159 (request)->req_persistent = (persistent); \
160 } while (0);
161
162 /**
163 * Finalize a request. This is a macro to avoid function call
164 * overhead, since this is typically invoked in the critical
165 * performance path (since requests may be re-used, it is possible
166 * that we will have to finalize a request multiple times).
167 *
168 * When finalizing a request, if MPI_Request_f2c() was previously
169 * invoked on that request, then this request was added to the f2c
170 * table, and we need to remove it
171 *
172 * This function should be called only from the SHMEM layer. It should
173 * never be called from the SPML. It take care of the upper level clean-up.
174 * When the user call MPI_Request_free we should release all SHMEM level
175 * ressources, so we have to call this function too.
176 */
177 #define OSHMEM_REQUEST_FINI(request) \
178 do { \
179 (request)->req_state = OSHMEM_REQUEST_INVALID; \
180 if (SHMEM_UNDEFINED != (request)->req_f_to_c_index) { \
181 opal_pointer_array_set_item(&oshmem_request_f_to_c_table, \
182 (request)->req_f_to_c_index, NULL); \
183 (request)->req_f_to_c_index = SHMEM_UNDEFINED; \
184 } \
185 } while (0);
186
187 /**
188 * Non-blocking test for request completion.
189 *
190 * @param request (IN) Array of requests
191 * @param complete (OUT) Flag indicating if index is valid (a request completed).
192 * @param status (OUT) Status of completed request.
193 * @return OSHMEM_SUCCESS or failure status.
194 *
195 * Note that upon completion, the request is freed, and the
196 * request handle at index set to NULL.
197 */
198 typedef int (*oshmem_request_test_fn_t)(oshmem_request_t ** rptr,
199 int *completed,
200 oshmem_status_public_t * status);
201 /**
202 * Non-blocking test for request completion.
203 *
204 * @param count (IN) Number of requests
205 * @param request (IN) Array of requests
206 * @param index (OUT) Index of first completed request.
207 * @param complete (OUT) Flag indicating if index is valid (a request completed).
208 * @param status (OUT) Status of completed request.
209 * @return OSHMEM_SUCCESS or failure status.
210 *
211 * Note that upon completion, the request is freed, and the
212 * request handle at index set to NULL.
213 */
214 typedef int (*oshmem_request_test_any_fn_t)(size_t count,
215 oshmem_request_t ** requests,
216 int *index,
217 int *completed,
218 oshmem_status_public_t * status);
219 /**
220 * Non-blocking test for request completion.
221 *
222 * @param count (IN) Number of requests
223 * @param requests (IN) Array of requests
224 * @param completed (OUT) Flag indicating wether all requests completed.
225 * @param statuses (OUT) Array of completion statuses.
226 * @return OSHMEM_SUCCESS or failure status.
227 *
228 * This routine returns completed==true if all requests have completed.
229 * The statuses parameter is only updated if all requests completed. Likewise,
230 * the requests array is not modified (no requests freed), unless all requests
231 * have completed.
232 */
233 typedef int (*oshmem_request_test_all_fn_t)(size_t count,
234 oshmem_request_t ** requests,
235 int *completed,
236 oshmem_status_public_t * statuses);
237 /**
238 * Non-blocking test for some of N requests to complete.
239 *
240 * @param count (IN) Number of requests
241 * @param requests (INOUT) Array of requests
242 * @param outcount (OUT) Number of finished requests
243 * @param indices (OUT) Indices of the finished requests
244 * @param statuses (OUT) Array of completion statuses.
245 * @return OSHMEM_SUCCESS, OSHMEM_ERR_IN_STATUS or failure status.
246 *
247 */
248 typedef int (*oshmem_request_test_some_fn_t)(size_t count,
249 oshmem_request_t ** requests,
250 int * outcount,
251 int * indices,
252 oshmem_status_public_t * statuses);
253 /**
254 * Wait (blocking-mode) for one requests to complete.
255 *
256 * @param request (IN) Pointer to request.
257 * @param status (OUT) Status of completed request.
258 * @return OSHMEM_SUCCESS or failure status.
259 *
260 */
261 typedef int (*oshmem_request_wait_fn_t)(oshmem_request_t ** req_ptr,
262 oshmem_status_public_t * status);
263 /**
264 * Wait (blocking-mode) for one of N requests to complete.
265 *
266 * @param count (IN) Number of requests
267 * @param requests (IN) Array of requests
268 * @param index (OUT) Index into request array of completed request.
269 * @param status (OUT) Status of completed request.
270 * @return OSHMEM_SUCCESS or failure status.
271 *
272 */
273 typedef int (*oshmem_request_wait_any_fn_t)(size_t count,
274 oshmem_request_t ** requests,
275 int *index,
276 oshmem_status_public_t * status);
277 /**
278 * Wait (blocking-mode) for all of N requests to complete.
279 *
280 * @param count (IN) Number of requests
281 * @param requests (IN) Array of requests
282 * @param statuses (OUT) Array of completion statuses.
283 * @return OSHMEM_SUCCESS or failure status.
284 *
285 */
286 typedef int (*oshmem_request_wait_all_fn_t)(size_t count,
287 oshmem_request_t ** requests,
288 oshmem_status_public_t * statuses);
289 /**
290 * Wait (blocking-mode) for some of N requests to complete.
291 *
292 * @param count (IN) Number of requests
293 * @param requests (INOUT) Array of requests
294 * @param outcount (OUT) Number of finished requests
295 * @param indices (OUT) Indices of the finished requests
296 * @param statuses (OUT) Array of completion statuses.
297 * @return OSHMEM_SUCCESS, OSHMEM_ERR_IN_STATUS or failure status.
298 *
299 */
300 typedef int (*oshmem_request_wait_some_fn_t)(size_t count,
301 oshmem_request_t ** requests,
302 int * outcount,
303 int * indices,
304 oshmem_status_public_t * statuses);
305
306 /**
307 * Replaceable request functions
308 */
309 typedef struct oshmem_request_fns_t {
310 oshmem_request_test_fn_t req_test;
311 oshmem_request_test_any_fn_t req_test_any;
312 oshmem_request_test_all_fn_t req_test_all;
313 oshmem_request_test_some_fn_t req_test_some;
314 oshmem_request_wait_fn_t req_wait;
315 oshmem_request_wait_any_fn_t req_wait_any;
316 oshmem_request_wait_all_fn_t req_wait_all;
317 oshmem_request_wait_some_fn_t req_wait_some;
318 } oshmem_request_fns_t;
319
320 /**
321 * Globals used for tracking requests and request completion.
322 */
323 OSHMEM_DECLSPEC extern opal_pointer_array_t oshmem_request_f_to_c_table;
324 OSHMEM_DECLSPEC extern size_t oshmem_request_waiting;
325 OSHMEM_DECLSPEC extern size_t oshmem_request_completed;
326 OSHMEM_DECLSPEC extern int32_t oshmem_request_poll;
327 OSHMEM_DECLSPEC extern opal_mutex_t oshmem_request_lock;
328 OSHMEM_DECLSPEC extern opal_condition_t oshmem_request_cond;
329 OSHMEM_DECLSPEC extern oshmem_predefined_request_t oshmem_request_null;
330 OSHMEM_DECLSPEC extern oshmem_request_t oshmem_request_empty;
331 OSHMEM_DECLSPEC extern oshmem_status_public_t oshmem_status_empty;
332 OSHMEM_DECLSPEC extern oshmem_request_fns_t oshmem_request_functions;
333
334 /**
335 * Initialize the OSHMEM_Request subsystem; invoked during SHMEM_INIT.
336 */
337 int oshmem_request_init(void);
338
339 /**
340 * Free a persistent request to a MPI_PROC_NULL peer (there's no
341 * freelist to put it back to, so we have to actually OBJ_RELEASE it).
342 */
343 OSHMEM_DECLSPEC int oshmem_request_persistent_proc_null_free(oshmem_request_t **request);
344
345 /**
346 * Shut down the SHMEM_Request subsystem; invoked during SHMEM_FINALIZE.
347 */
348 int oshmem_request_finalize(void);
349
350 /**
351 * Cancel a pending request.
352 */
oshmem_request_cancel(oshmem_request_t * request)353 static inline int oshmem_request_cancel(oshmem_request_t* request)
354 {
355 if (request->req_cancel != NULL ) {
356 return request->req_cancel(request, true);
357 }
358 return OSHMEM_SUCCESS;
359 }
360
361 /**
362 * Free a request.
363 *
364 * @param request (INOUT) Pointer to request.
365 */
oshmem_request_free(oshmem_request_t ** request)366 static inline int oshmem_request_free(oshmem_request_t** request)
367 {
368 return (*request)->req_free(request);
369 }
370
371 #define oshmem_request_test (oshmem_request_functions.req_test)
372 #define oshmem_request_test_any (oshmem_request_functions.req_test_any)
373 #define oshmem_request_test_all (oshmem_request_functions.req_test_all)
374 #define oshmem_request_test_some (oshmem_request_functions.req_test_some)
375 #define oshmem_request_wait (oshmem_request_functions.req_wait)
376 #define oshmem_request_wait_any (oshmem_request_functions.req_wait_any)
377 #define oshmem_request_wait_all (oshmem_request_functions.req_wait_all)
378 #define oshmem_request_wait_some (oshmem_request_functions.req_wait_some)
379
380 /**
381 * Wait for any completion. It is a caller responsibility to check for
382 * condition and call us again if needed.
383 */
oshmem_request_wait_any_completion(void)384 static inline void oshmem_request_wait_any_completion(void)
385 {
386 OPAL_THREAD_LOCK(&oshmem_request_lock);
387 oshmem_request_waiting++;
388 opal_condition_wait(&oshmem_request_cond, &oshmem_request_lock);
389 oshmem_request_waiting--;
390 OPAL_THREAD_UNLOCK(&oshmem_request_lock);
391 }
392
393 /**
394 * Wait a particular request for completion
395 */
oshmem_request_wait_completion(oshmem_request_t * req)396 static inline void oshmem_request_wait_completion(oshmem_request_t *req)
397 {
398 if (false == req->req_complete) {
399 #if OPAL_ENABLE_PROGRESS_THREADS
400 if(opal_progress_spin(&req->req_complete)) {
401 return;
402 }
403 #endif
404 OPAL_THREAD_LOCK(&oshmem_request_lock);
405 oshmem_request_waiting++;
406 while (false == req->req_complete) {
407 opal_condition_wait(&oshmem_request_cond, &oshmem_request_lock);
408 }
409 oshmem_request_waiting--;
410 OPAL_THREAD_UNLOCK(&oshmem_request_lock);
411 }
412 }
413
414 /**
415 * Signal or mark a request as complete. If with_signal is true this will
416 * wake any thread pending on the request and oshmem_request_lock should be
417 * held while calling this function. If with_signal is false, there will
418 * signal generated, and no lock required. This is a special case when
419 * the function is called from the critical path for small messages, where
420 * we know the current execution flow created the request, and is still
421 * in the _START macro.
422 */
oshmem_request_complete(oshmem_request_t * request,bool with_signal)423 static inline int oshmem_request_complete(oshmem_request_t* request,
424 bool with_signal)
425 {
426 if (NULL != request->req_complete_cb) {
427 request->req_complete_cb(request);
428 }
429 oshmem_request_completed++;
430 request->req_complete = true;
431 if (with_signal && oshmem_request_waiting) {
432 /* Broadcast the condition, otherwise if there is already a thread
433 * waiting on another request it can use all signals.
434 */
435 opal_condition_broadcast(&oshmem_request_cond);
436 }
437 return OSHMEM_SUCCESS;
438 }
439
440 END_C_DECLS
441
442 #endif
443