1 /*
2  * Copyright (C) by Argonne National Laboratory
3  *     See COPYRIGHT in top-level directory
4  */
5 
6 #include "mpiimpl.h"
7 
8 #if !defined(MPIR_REQUEST_PTR_ARRAY_SIZE)
9 #define MPIR_REQUEST_PTR_ARRAY_SIZE 16
10 #endif
11 
12 /* -- Begin Profiling Symbol Block for routine MPI_Testany */
13 #if defined(HAVE_PRAGMA_WEAK)
14 #pragma weak MPI_Testany = PMPI_Testany
15 #elif defined(HAVE_PRAGMA_HP_SEC_DEF)
16 #pragma _HP_SECONDARY_DEF PMPI_Testany  MPI_Testany
17 #elif defined(HAVE_PRAGMA_CRI_DUP)
18 #pragma _CRI duplicate MPI_Testany as PMPI_Testany
19 #elif defined(HAVE_WEAK_ATTRIBUTE)
20 int MPI_Testany(int count, MPI_Request array_of_requests[], int *indx, int *flag,
21                 MPI_Status * status) __attribute__ ((weak, alias("PMPI_Testany")));
22 #endif
23 /* -- End Profiling Symbol Block */
24 
25 /* Define MPICH_MPI_FROM_PMPI if weak symbols are not supported to build
26    the MPI routines */
27 #ifndef MPICH_MPI_FROM_PMPI
28 #undef MPI_Testany
29 #define MPI_Testany PMPI_Testany
30 
MPIR_Testany_state(int count,MPIR_Request * request_ptrs[],int * indx,int * flag,MPI_Status * status,MPID_Progress_state * state)31 int MPIR_Testany_state(int count, MPIR_Request * request_ptrs[],
32                        int *indx, int *flag, MPI_Status * status, MPID_Progress_state * state)
33 {
34     int i;
35     int n_inactive = 0;
36     int mpi_errno = MPI_SUCCESS;
37 
38     mpi_errno = MPID_Progress_test(state);
39     /* --BEGIN ERROR HANDLING-- */
40     MPIR_ERR_CHECK(mpi_errno);
41     /* --END ERROR HANDLING-- */
42 
43     for (i = 0; i < count; i++) {
44         if ((i + 1) % MPIR_CVAR_REQUEST_POLL_FREQ == 0) {
45             mpi_errno = MPID_Progress_test(state);
46             MPIR_ERR_CHECK(mpi_errno);
47         }
48 
49         if (request_ptrs[i] != NULL && MPIR_Request_has_poll_fn(request_ptrs[i])) {
50             mpi_errno = MPIR_Grequest_poll(request_ptrs[i], status);
51             if (mpi_errno != MPI_SUCCESS)
52                 goto fn_fail;
53         }
54         if (!MPIR_Request_is_active(request_ptrs[i])) {
55             n_inactive += 1;
56         } else if (MPIR_Request_is_complete(request_ptrs[i])) {
57             *flag = TRUE;
58             *indx = i;
59             goto fn_exit;
60         }
61     }
62 
63     if (n_inactive == count) {
64         *flag = TRUE;
65         *indx = MPI_UNDEFINED;
66     }
67 
68   fn_exit:
69     return mpi_errno;
70   fn_fail:
71     goto fn_exit;
72 }
73 
MPIR_Testany_impl(int count,MPIR_Request * request_ptrs[],int * indx,int * flag,MPI_Status * status)74 int MPIR_Testany_impl(int count, MPIR_Request * request_ptrs[],
75                       int *indx, int *flag, MPI_Status * status)
76 {
77     return MPIR_Testany_state(count, request_ptrs, indx, flag, status, NULL);
78 }
79 
80 #endif
81 
82 /*@
83     MPI_Testany - Tests for completion of any previdously initiated
84                   requests
85 
86 Input Parameters:
87 + count - list length (integer)
88 - array_of_requests - array of requests (array of handles)
89 
90 Output Parameters:
91 + indx - index of operation that completed, or 'MPI_UNDEFINED'  if none
92   completed (integer)
93 . flag - true if one of the operations is complete (logical)
94 - status - status object (Status).  May be 'MPI_STATUS_IGNORE'.
95 
96 Notes:
97 
98 While it is possible to list a request handle more than once in the
99 'array_of_requests', such an action is considered erroneous and may cause the
100 program to unexecpectedly terminate or produce incorrect results.
101 
102 .N ThreadSafe
103 
104 .N waitstatus
105 
106 .N Fortran
107 
108 .N Errors
109 .N MPI_SUCCESS
110 @*/
MPI_Testany(int count,MPI_Request array_of_requests[],int * indx,int * flag,MPI_Status * status)111 int MPI_Testany(int count, MPI_Request array_of_requests[], int *indx,
112                 int *flag, MPI_Status * status)
113 {
114     MPIR_Request *request_ptr_array[MPIR_REQUEST_PTR_ARRAY_SIZE];
115     MPIR_Request **request_ptrs = request_ptr_array;
116     int i;
117     int n_inactive;
118     int last_disabled_anysource = -1;
119     int first_nonnull = count;
120     int mpi_errno = MPI_SUCCESS;
121     MPIR_CHKLMEM_DECL(1);
122     MPIR_FUNC_TERSE_STATE_DECL(MPID_STATE_MPI_TESTANY);
123 
124     MPIR_ERRTEST_INITIALIZED_ORDIE();
125 
126     MPID_THREAD_CS_ENTER(GLOBAL, MPIR_THREAD_GLOBAL_ALLFUNC_MUTEX);
127     MPIR_FUNC_TERSE_REQUEST_ENTER(MPID_STATE_MPI_TESTANY);
128 
129     /* Check the arguments */
130 #ifdef HAVE_ERROR_CHECKING
131     {
132         MPID_BEGIN_ERROR_CHECKS;
133         {
134             MPIR_ERRTEST_COUNT(count, mpi_errno);
135 
136             if (count != 0) {
137                 MPIR_ERRTEST_ARGNULL(array_of_requests, "array_of_requests", mpi_errno);
138                 /* NOTE: MPI_STATUS_IGNORE != NULL */
139                 MPIR_ERRTEST_ARGNULL(status, "status", mpi_errno);
140             }
141             MPIR_ERRTEST_ARGNULL(indx, "indx", mpi_errno);
142             MPIR_ERRTEST_ARGNULL(flag, "flag", mpi_errno);
143 
144             for (i = 0; i < count; i++) {
145                 MPIR_ERRTEST_ARRAYREQUEST_OR_NULL(array_of_requests[i], i, mpi_errno);
146             }
147         }
148         MPID_END_ERROR_CHECKS;
149     }
150 #endif /* HAVE_ERROR_CHECKING */
151 
152     /* ... body of routine ...  */
153 
154     /* Convert MPI request handles to a request object pointers */
155     if (count > MPIR_REQUEST_PTR_ARRAY_SIZE) {
156         MPIR_CHKLMEM_MALLOC_ORJUMP(request_ptrs, MPIR_Request **, count * sizeof(MPIR_Request *),
157                                    mpi_errno, "request pointers", MPL_MEM_OBJECT);
158     }
159 
160     n_inactive = 0;
161     *flag = FALSE;
162     *indx = MPI_UNDEFINED;
163 
164     for (i = 0; i < count; i++) {
165         if (array_of_requests[i] != MPI_REQUEST_NULL) {
166             MPIR_Request_get_ptr(array_of_requests[i], request_ptrs[i]);
167             /* Validate object pointers if error checking is enabled */
168 #ifdef HAVE_ERROR_CHECKING
169             {
170                 MPID_BEGIN_ERROR_CHECKS;
171                 {
172                     MPIR_Request_valid_ptr(request_ptrs[i], mpi_errno);
173                     if (mpi_errno)
174                         goto fn_fail;
175                 }
176                 MPID_END_ERROR_CHECKS;
177             }
178 #endif
179             if (unlikely(MPIR_Request_is_anysrc_mismatched(request_ptrs[i]))) {
180                 last_disabled_anysource = i;
181             }
182 
183             if (MPIR_Request_is_complete(request_ptrs[i])) {
184                 if (MPIR_Request_is_active(request_ptrs[i])) {
185                     *indx = i;
186                     *flag = TRUE;
187                     break;
188                 } else {
189                     request_ptrs[i] = NULL;
190                 }
191             } else {
192                 if (first_nonnull == count)
193                     first_nonnull = i;
194             }
195         } else {
196             request_ptrs[i] = NULL;
197             n_inactive += 1;
198         }
199     }
200 
201     if (n_inactive == count) {
202         *flag = TRUE;
203         *indx = MPI_UNDEFINED;
204         if (status != NULL)     /* could be null if count=0 */
205             MPIR_Status_set_empty(status);
206         goto fn_exit;
207     }
208 
209     if (*indx == MPI_UNDEFINED) {
210         mpi_errno =
211             MPID_Testany(count - first_nonnull, &request_ptrs[first_nonnull], indx, flag, status);
212         /* --BEGIN ERROR HANDLING-- */
213         if (mpi_errno != MPI_SUCCESS) {
214             goto fn_fail;
215         }
216         /* --END ERROR HANDLING-- */
217 
218         if (*indx != MPI_UNDEFINED) {
219             *indx += first_nonnull;
220         }
221     }
222 
223     if (*indx != MPI_UNDEFINED) {
224         mpi_errno = MPIR_Request_completion_processing(request_ptrs[*indx], status);
225         if (!MPIR_Request_is_persistent(request_ptrs[*indx])) {
226             MPIR_Request_free(request_ptrs[*indx]);
227             array_of_requests[*indx] = MPI_REQUEST_NULL;
228         }
229         MPIR_ERR_CHECK(mpi_errno);
230         goto fn_exit;
231     }
232 
233     /* If none of the requests completed, mark the last anysource request as
234      * pending failure. */
235     if (unlikely(last_disabled_anysource != -1)) {
236         MPIR_ERR_SET(mpi_errno, MPIX_ERR_PROC_FAILED_PENDING, "**failure_pending");
237         if (status != MPI_STATUS_IGNORE)
238             status->MPI_ERROR = mpi_errno;
239         *flag = TRUE;
240         goto fn_fail;
241     }
242 
243     /* ... end of body of routine ... */
244 
245   fn_exit:
246     if (count > MPIR_REQUEST_PTR_ARRAY_SIZE) {
247         MPIR_CHKLMEM_FREEALL();
248     }
249 
250     MPIR_FUNC_TERSE_REQUEST_EXIT(MPID_STATE_MPI_TESTANY);
251     MPID_THREAD_CS_EXIT(GLOBAL, MPIR_THREAD_GLOBAL_ALLFUNC_MUTEX);
252     return mpi_errno;
253 
254   fn_fail:
255     /* --BEGIN ERROR HANDLING-- */
256 #ifdef HAVE_ERROR_CHECKING
257     {
258         mpi_errno =
259             MPIR_Err_create_code(mpi_errno, MPIR_ERR_RECOVERABLE, __func__, __LINE__, MPI_ERR_OTHER,
260                                  "**mpi_testany", "**mpi_testany %d %p %p %p %p", count,
261                                  array_of_requests, indx, flag, status);
262     }
263 #endif
264     mpi_errno = MPIR_Err_return_comm(NULL, __func__, mpi_errno);
265     goto fn_exit;
266     /* --END ERROR HANDLING-- */
267 }
268