1 /* -*- Mode: C; c-basic-offset:4 ; -*- */
2 /*
3  *
4  *  (C) 2001 by Argonne National Laboratory.
5  *      See COPYRIGHT in top-level directory.
6  */
7 
8 #include "mpiimpl.h"
9 
10 #undef FUNCNAME
11 #define FUNCNAME MPIR_Progress_wait_request
12 #undef FCNAME
13 #define FCNAME MPIU_QUOTE(FUNCNAME)
14 /*@
15   MPIR_Progress_wait_request
16 
17   A helper routine that implements the very common case of running the progress
18   engine until the given request is complete.
19   @*/
MPIR_Progress_wait_request(MPID_Request * req)20 int MPIR_Progress_wait_request(MPID_Request *req)
21 {
22     int mpi_errno = MPI_SUCCESS;
23 
24     if (!MPID_Request_is_complete(req))
25     {
26         MPID_Progress_state progress_state;
27 
28         MPID_Progress_start(&progress_state);
29         while (!MPID_Request_is_complete(req))
30         {
31             mpi_errno = MPID_Progress_wait(&progress_state);
32             if (mpi_errno != MPI_SUCCESS)
33             {
34                 /* --BEGIN ERROR HANDLING-- */
35                 MPID_Progress_end(&progress_state);
36                 if (mpi_errno) MPIU_ERR_POP(mpi_errno);
37                 /* --END ERROR HANDLING-- */
38             }
39         }
40         MPID_Progress_end(&progress_state);
41     }
42 fn_fail: /* no special err handling at this level */
43 fn_exit:
44     return mpi_errno;
45 }
46 
47 #undef FUNCNAME
48 #define FUNCNAME MPIR_Request_complete
49 #undef FCNAME
50 #define FCNAME MPIU_QUOTE(FUNCNAME)
51 /* Complete a request, saving the status data if necessary.
52    "active" has meaning only if the request is a persistent request; this
53    allows the completion routines to indicate that a persistent request
54    was inactive and did not require any extra completion operation.
55 
56    If debugger information is being provided for pending (user-initiated)
57    send operations, the macros MPIR_SENDQ_FORGET will be defined to
58    call the routine MPIR_Sendq_forget; otherwise that macro will be a no-op.
59    The implementation of the MPIR_Sendq_xxx is in src/mpi/debugger/dbginit.c .
60 */
MPIR_Request_complete(MPI_Request * request,MPID_Request * request_ptr,MPI_Status * status,int * active)61 int MPIR_Request_complete(MPI_Request * request, MPID_Request * request_ptr,
62 			  MPI_Status * status, int * active)
63 {
64     int mpi_errno = MPI_SUCCESS;
65 
66     *active = TRUE;
67     switch(request_ptr->kind)
68     {
69 	case MPID_REQUEST_SEND:
70 	{
71 	    if (status != MPI_STATUS_IGNORE)
72 	    {
73 		status->cancelled = request_ptr->status.cancelled;
74 	    }
75 	    mpi_errno = request_ptr->status.MPI_ERROR;
76 	    /* FIXME: are Ibsend requests added to the send queue? */
77 	    MPIR_SENDQ_FORGET(request_ptr);
78 	    MPID_Request_release(request_ptr);
79 	    *request = MPI_REQUEST_NULL;
80 	    break;
81 	}
82 	case MPID_REQUEST_RECV:
83 	{
84 	    MPIR_Request_extract_status(request_ptr, status);
85 	    mpi_errno = request_ptr->status.MPI_ERROR;
86 	    MPID_Request_release(request_ptr);
87 	    *request = MPI_REQUEST_NULL;
88 	    break;
89 	}
90 
91 	case MPID_PREQUEST_SEND:
92 	{
93 	    if (request_ptr->partner_request != NULL)
94 	    {
95 		MPID_Request * prequest_ptr = request_ptr->partner_request;
96 
97 		/* reset persistent request to inactive state */
98                 MPID_cc_set(&request_ptr->cc, 0);
99 		request_ptr->cc_ptr = &request_ptr->cc;
100 		request_ptr->partner_request = NULL;
101 
102 		if (prequest_ptr->kind != MPID_UREQUEST)
103 		{
104 		    if (status != MPI_STATUS_IGNORE)
105 		    {
106 			status->cancelled = prequest_ptr->status.cancelled;
107 		    }
108 		    mpi_errno = prequest_ptr->status.MPI_ERROR;
109 		}
110 		else
111 		{
112 		    /* This is needed for persistent Bsend requests */
113                     int rc;
114 
115                     rc = MPIR_Grequest_query(prequest_ptr);
116                     if (mpi_errno == MPI_SUCCESS)
117                     {
118                         mpi_errno = rc;
119                     }
120                     if (status != MPI_STATUS_IGNORE)
121                     {
122                         status->cancelled = prequest_ptr->status.cancelled;
123                     }
124                     if (mpi_errno == MPI_SUCCESS)
125                     {
126                         mpi_errno = prequest_ptr->status.MPI_ERROR;
127                     }
128                     rc = MPIR_Grequest_free(prequest_ptr);
129                     if (mpi_errno == MPI_SUCCESS)
130                     {
131                         mpi_errno = rc;
132                     }
133 		}
134 
135 		/* FIXME: MPIR_SENDQ_FORGET(request_ptr); -- it appears that
136 		   persistent sends are not currently being added to the send
137 		   queue.  should they be, or should this release be
138 		   conditional? */
139 		MPID_Request_release(prequest_ptr);
140 	    }
141 	    else
142 	    {
143 		if (request_ptr->status.MPI_ERROR != MPI_SUCCESS)
144 		{
145 		    /* if the persistent request failed to start then make the
146 		       error code available */
147 		    if (status != MPI_STATUS_IGNORE)
148 		    {
149 			status->cancelled = FALSE;
150 		    }
151 		    mpi_errno = request_ptr->status.MPI_ERROR;
152 		}
153 		else
154 		{
155 		    MPIR_Status_set_empty(status);
156 		    *active = FALSE;
157 		}
158 	    }
159 
160 	    break;
161 	}
162 
163 	case MPID_PREQUEST_RECV:
164 	{
165 	    if (request_ptr->partner_request != NULL)
166 	    {
167 		MPID_Request * prequest_ptr = request_ptr->partner_request;
168 
169 		/* reset persistent request to inactive state */
170                 MPID_cc_set(&request_ptr->cc, 0);
171 		request_ptr->cc_ptr = &request_ptr->cc;
172 		request_ptr->partner_request = NULL;
173 
174 		MPIR_Request_extract_status(prequest_ptr, status);
175 		mpi_errno = prequest_ptr->status.MPI_ERROR;
176 
177 		MPID_Request_release(prequest_ptr);
178 	    }
179 	    else
180 	    {
181 		MPIR_Status_set_empty(status);
182 		/* --BEGIN ERROR HANDLING-- */
183 		if (request_ptr->status.MPI_ERROR != MPI_SUCCESS)
184 		{
185 		    /* if the persistent request failed to start then make the
186 		       error code available */
187 		    mpi_errno = request_ptr->status.MPI_ERROR;
188 		}
189 		else
190 		{
191 		    *active = FALSE;
192 		}
193 		/* --END ERROR HANDLING-- */
194 	    }
195 
196 	    break;
197 	}
198 
199 	case MPID_UREQUEST:
200 	{
201             int rc;
202 
203             rc = MPIR_Grequest_query(request_ptr);
204             if (mpi_errno == MPI_SUCCESS)
205             {
206                 mpi_errno = rc;
207             }
208             MPIR_Request_extract_status(request_ptr, status);
209             rc = MPIR_Grequest_free(request_ptr);
210             if (mpi_errno == MPI_SUCCESS)
211             {
212                 mpi_errno = rc;
213             }
214 
215             MPID_Request_release(request_ptr);
216             *request = MPI_REQUEST_NULL;
217 
218 	    break;
219 	}
220 
221         case MPID_COLL_REQUEST:
222         {
223             MPIR_Request_extract_status(request_ptr, status);
224             MPID_Request_release(request_ptr);
225             *request = MPI_REQUEST_NULL;
226             break;
227         }
228 
229 	default:
230 	{
231 	    /* --BEGIN ERROR HANDLING-- */
232 	    /* This should not happen */
233 	    MPIU_ERR_SETANDSTMT1(mpi_errno, MPI_ERR_INTERN,;, "**badcase",
234 		"**badcase %d", request_ptr->kind);
235 	    break;
236 	    /* --END ERROR HANDLING-- */
237 	}
238     }
239 
240     return mpi_errno;
241 }
242 
243 
244 #undef FUNCNAME
245 #define FUNCNAME MPIR_Request_get_error
246 #undef FCNAME
247 #define FCNAME MPIU_QUOTE(FUNCNAME)
248 /* FIXME: What is this routine for?
249  *
250  * [BRT] it is used by testall, although looking at testall now, I think the
251  * algorithm can be change slightly and eliminate the need for this routine
252  */
MPIR_Request_get_error(MPID_Request * request_ptr)253 int MPIR_Request_get_error(MPID_Request * request_ptr)
254 {
255     int mpi_errno = MPI_SUCCESS;
256 
257     switch(request_ptr->kind)
258     {
259 	case MPID_REQUEST_SEND:
260 	case MPID_REQUEST_RECV:
261         case MPID_COLL_REQUEST:
262 	{
263 	    mpi_errno = request_ptr->status.MPI_ERROR;
264 	    break;
265 	}
266 
267 	case MPID_PREQUEST_SEND:
268 	{
269 	    if (request_ptr->partner_request != NULL)
270 	    {
271 		if (request_ptr->partner_request->kind == MPID_UREQUEST)
272 		{
273 		    /* This is needed for persistent Bsend requests */
274 		    mpi_errno = MPIR_Grequest_query(
275 			request_ptr->partner_request);
276 		}
277 		if (mpi_errno == MPI_SUCCESS)
278 		{
279 		    mpi_errno = request_ptr->partner_request->status.MPI_ERROR;
280 		}
281 	    }
282 	    else
283 	    {
284 		mpi_errno = request_ptr->status.MPI_ERROR;
285 	    }
286 
287 	    break;
288 	}
289 
290 	case MPID_PREQUEST_RECV:
291 	{
292 	    if (request_ptr->partner_request != NULL)
293 	    {
294 		mpi_errno = request_ptr->partner_request->status.MPI_ERROR;
295 	    }
296 	    else
297 	    {
298 		mpi_errno = request_ptr->status.MPI_ERROR;
299 	    }
300 
301 	    break;
302 	}
303 
304 	case MPID_UREQUEST:
305 	{
306 	    int rc;
307 
308 	    /* Note that we've acquired the thread private storage above */
309 
310 	    switch (request_ptr->greq_fns->greq_lang)
311 	    {
312 		case MPID_LANG_C:
313 #ifdef HAVE_CXX_BINDING
314 		case MPID_LANG_CXX:
315 #endif
316 		    rc = (request_ptr->greq_fns->query_fn)(
317 			request_ptr->greq_fns->grequest_extra_state,
318 			&request_ptr->status);
319 		    MPIU_ERR_CHKANDSTMT1((rc != MPI_SUCCESS), mpi_errno,
320 			MPI_ERR_OTHER,;, "**user", "**userquery %d", rc);
321 		    break;
322 #ifdef HAVE_FORTRAN_BINDING
323 		case MPID_LANG_FORTRAN:
324 		case MPID_LANG_FORTRAN90:
325 		{
326 		    MPI_Fint ierr;
327 		    MPI_Fint is[sizeof(MPI_Status)/sizeof(int)];
328 		    ((MPIR_Grequest_f77_query_function*)(request_ptr->greq_fns->query_fn))(
329 			request_ptr->greq_fns->grequest_extra_state, is,
330 			&ierr );
331 		    rc = (int) ierr;
332 		    if (rc == MPI_SUCCESS)
333 			PMPI_Status_f2c( is, &request_ptr->status );
334 		    MPIU_ERR_CHKANDSTMT1((rc != MPI_SUCCESS), mpi_errno,
335 			MPI_ERR_OTHER,;, "**user", "**userquery %d", rc);
336 		    break;
337 		}
338 #endif
339 
340 		default:
341 		{
342 		    /* --BEGIN ERROR HANDLING-- */
343 		    /* This should not happen */
344 		    MPIU_ERR_SETANDSTMT1(mpi_errno, MPI_ERR_INTERN,;,
345 				 "**badcase",
346 				 "**badcase %d", request_ptr->greq_fns->greq_lang);
347 		    break;
348 		    /* --END ERROR HANDLING-- */
349 		}
350 	    }
351 
352 	    break;
353 	}
354 
355 	default:
356 	{
357 	    /* --BEGIN ERROR HANDLING-- */
358 	    /* This should not happen */
359 	    MPIU_ERR_SETANDSTMT1(mpi_errno, MPI_ERR_INTERN,;, "**badcase",
360 				 "**badcase %d", request_ptr->kind);
361 	    break;
362 	    /* --END ERROR HANDLING-- */
363 	}
364     }
365 
366     return mpi_errno;
367 }
368 
369 #ifdef HAVE_FORTRAN_BINDING
370 /* Set the language type to Fortran for this (generalized) request */
MPIR_Grequest_set_lang_f77(MPI_Request greq)371 void MPIR_Grequest_set_lang_f77( MPI_Request greq )
372 {
373     MPID_Request *greq_ptr;
374 
375     MPID_Request_get_ptr( greq, greq_ptr );
376 
377     greq_ptr->greq_fns->greq_lang = MPID_LANG_FORTRAN;
378 }
379 #endif
380 
381 
382 #undef FUNCNAME
383 #define FUNCNAME MPIR_Grequest_cancel
384 #undef FCNAME
385 #define FCNAME MPIU_QUOTE(FUNCNAME)
MPIR_Grequest_cancel(MPID_Request * request_ptr,int complete)386 int MPIR_Grequest_cancel(MPID_Request * request_ptr, int complete)
387 {
388     int rc;
389     int mpi_errno = MPI_SUCCESS;
390 
391     switch (request_ptr->greq_fns->greq_lang)
392     {
393 	case MPID_LANG_C:
394 #ifdef HAVE_CXX_BINDING
395 	case MPID_LANG_CXX:
396 #endif
397 	    rc = (request_ptr->greq_fns->cancel_fn)(
398 		request_ptr->greq_fns->grequest_extra_state, complete);
399 	    MPIU_ERR_CHKANDSTMT1((rc != MPI_SUCCESS), mpi_errno,
400 		MPI_ERR_OTHER,;, "**user", "**usercancel %d", rc);
401 	    break;
402 #ifdef HAVE_FORTRAN_BINDING
403 	case MPID_LANG_FORTRAN:
404 	case MPID_LANG_FORTRAN90:
405 	{
406 	    MPI_Fint ierr;
407 	    MPI_Fint icomplete = complete;
408 
409 	    ((MPIR_Grequest_f77_cancel_function *)(request_ptr->greq_fns->cancel_fn))(
410 		request_ptr->greq_fns->grequest_extra_state, &icomplete, &ierr);
411 	    rc = (int) ierr;
412 	    MPIU_ERR_CHKANDSTMT1((rc != MPI_SUCCESS), mpi_errno, MPI_ERR_OTHER,
413 		{;}, "**user", "**usercancel %d", rc);
414 	    break;
415 	}
416 #endif
417 
418 	default:
419 	{
420 	    /* --BEGIN ERROR HANDLING-- */
421 	    /* This should not happen */
422 	    MPIU_ERR_SETANDSTMT1(mpi_errno, MPI_ERR_INTERN,;, "**badcase",
423 		"**badcase %d", request_ptr->greq_fns->greq_lang);
424 	    break;
425 	    /* --END ERROR HANDLING-- */
426 	}
427     }
428 
429     return mpi_errno;
430 }
431 
432 
433 #undef FUNCNAME
434 #define FUNCNAME MPIR_Grequest_query
435 #undef FCNAME
436 #define FCNAME MPIU_QUOTE(FUNCNAME)
MPIR_Grequest_query(MPID_Request * request_ptr)437 int MPIR_Grequest_query(MPID_Request * request_ptr)
438 {
439     int rc;
440     int mpi_errno = MPI_SUCCESS;
441 
442     switch (request_ptr->greq_fns->greq_lang)
443     {
444 	case MPID_LANG_C:
445 #ifdef HAVE_CXX_BINDING
446 	case MPID_LANG_CXX:
447 #endif
448 	    rc = (request_ptr->greq_fns->query_fn)(request_ptr->greq_fns->grequest_extra_state,
449 		&request_ptr->status);
450 	    MPIU_ERR_CHKANDSTMT1((rc != MPI_SUCCESS), mpi_errno, MPI_ERR_OTHER,
451 		{;}, "**user", "**userquery %d", rc);
452 	    break;
453 #ifdef HAVE_FORTRAN_BINDING
454 	case MPID_LANG_FORTRAN:
455 	case MPID_LANG_FORTRAN90:
456 	{
457 	    MPI_Fint ierr;
458 	    MPI_Fint is[sizeof(MPI_Status)/sizeof(int)];
459 	    ((MPIR_Grequest_f77_query_function *)(request_ptr->greq_fns->query_fn))(
460 		request_ptr->greq_fns->grequest_extra_state, is, &ierr );
461 	    rc = (int)ierr;
462 	    if (rc == MPI_SUCCESS)
463 		PMPI_Status_f2c( is, &request_ptr->status );
464 	    MPIU_ERR_CHKANDSTMT1((rc != MPI_SUCCESS), mpi_errno, MPI_ERR_OTHER,
465 		{;}, "**user", "**userquery %d", rc);
466 	}
467 	break;
468 #endif
469 	default:
470 	{
471 	    /* --BEGIN ERROR HANDLING-- */
472 	    /* This should not happen */
473 	    MPIU_ERR_SETANDSTMT1(mpi_errno, MPI_ERR_INTERN,;, "**badcase",
474 		"**badcase %d", request_ptr->greq_fns->greq_lang);
475 	    break;
476 	    /* --END ERROR HANDLING-- */
477 	}
478     }
479 
480     return mpi_errno;
481 }
482 
483 
484 #undef FUNCNAME
485 #define FUNCNAME MPIR_Grequest_free
486 #undef FCNAME
487 #define FCNAME MPIU_QUOTE(FUNCNAME)
MPIR_Grequest_free(MPID_Request * request_ptr)488 int MPIR_Grequest_free(MPID_Request * request_ptr)
489 {
490     int rc;
491     int mpi_errno = MPI_SUCCESS;
492 
493     switch (request_ptr->greq_fns->greq_lang)
494     {
495 	case MPID_LANG_C:
496 #ifdef HAVE_CXX_BINDING
497 	case MPID_LANG_CXX:
498 #endif
499 	    rc = (request_ptr->greq_fns->free_fn)(request_ptr->greq_fns->grequest_extra_state);
500 	    MPIU_ERR_CHKANDSTMT1((rc != MPI_SUCCESS), mpi_errno, MPI_ERR_OTHER,
501 		{;}, "**user", "**userfree %d", rc);
502 	    break;
503 #ifdef HAVE_FORTRAN_BINDING
504 	case MPID_LANG_FORTRAN:
505 	case MPID_LANG_FORTRAN90:
506 	{
507 	    MPI_Fint ierr;
508 
509 	    ((MPIR_Grequest_f77_free_function *)(request_ptr->greq_fns->free_fn))(
510 		request_ptr->greq_fns->grequest_extra_state, &ierr);
511 	    rc = (int) ierr;
512 	    MPIU_ERR_CHKANDSTMT1((rc != MPI_SUCCESS), mpi_errno, MPI_ERR_OTHER,
513 		{;}, "**user", "**userfree %d", rc);
514 	    break;
515 	}
516 #endif
517 
518 	default:
519 	{
520 	    /* --BEGIN ERROR HANDLING-- */
521 	    /* This should not happen */
522 	    MPIU_ERR_SETANDSTMT1(mpi_errno, MPI_ERR_INTERN, {;}, "**badcase",
523 		"**badcase %d", request_ptr->greq_fns->greq_lang);
524 	    break;
525 	    /* --END ERROR HANDLING-- */
526 	}
527     }
528 
529     return mpi_errno;
530 }
531 
532 /* MPIR_Grequest_progress_poke:  Drives progess on generalized requests.
533  * Invokes poll_fn for each request in request_ptrs.  Waits for completion of
534  * multiple requests if possible (all outstanding generalized requests are of
535  * same greq class) */
536 #undef FUNCNAME
537 #define FUNCNAME MPIR_Grequest_progress_poke
538 #undef FCNAME
539 #define FCNAME MPIU_QUOTE(FUNCNAME)
MPIR_Grequest_progress_poke(int count,MPID_Request ** request_ptrs,MPI_Status array_of_statuses[])540 int MPIR_Grequest_progress_poke(int count,
541 		MPID_Request **request_ptrs,
542 		MPI_Status array_of_statuses[] )
543 {
544     MPIX_Grequest_wait_function *wait_fn = NULL;
545     void ** state_ptrs;
546     int i, j, n_classes, n_native, n_greq;
547     int mpi_errno = MPI_SUCCESS;
548     MPIU_CHKLMEM_DECL(1);
549 
550     MPIU_CHKLMEM_MALLOC(state_ptrs, void **, sizeof(void*) * count, mpi_errno, "state_ptrs");
551 
552     /* This somewhat messy for-loop computes how many requests are native
553      * requests and how many are generalized requests, and how many generalized
554      * request classes those grequests are members of */
555     for (i=0, j=0, n_classes=1, n_native=0, n_greq=0; i< count; i++)
556     {
557 	if (request_ptrs[i] == NULL || MPID_Request_is_complete(request_ptrs[i])) continue;
558 	if (request_ptrs[i]->kind == MPID_UREQUEST)
559 	{
560 	    n_greq += 1;
561 	    wait_fn = request_ptrs[i]->greq_fns->wait_fn;
562 	    state_ptrs[j] = request_ptrs[i]->greq_fns->grequest_extra_state;
563 	    j++;
564 	    if (i+1 < count) {
565 	        if (request_ptrs[i+1] == NULL ||
566 			(request_ptrs[i]->greq_fns->greq_class !=
567 				request_ptrs[i+1]->greq_fns->greq_class) )
568 	            n_classes += 1;
569 	    }
570 	} else {
571 	    n_native += 1;
572 	}
573     }
574 
575     if (j > 0 && n_classes == 1 && wait_fn != NULL) {
576         mpi_errno = (wait_fn)(j, state_ptrs, 0, NULL);
577     } else {
578 	for (i = 0; i< count; i++ )
579 	{
580 	    if (request_ptrs[i] != NULL &&
581                 request_ptrs[i]->kind == MPID_UREQUEST &&
582                 !MPID_Request_is_complete(request_ptrs[i]) &&
583                 request_ptrs[i]->greq_fns->poll_fn != NULL)
584             {
585 		mpi_errno = (request_ptrs[i]->greq_fns->poll_fn)(request_ptrs[i]->greq_fns->grequest_extra_state, &(array_of_statuses[i]));
586                 if (mpi_errno) MPIU_ERR_POP(mpi_errno);
587 	    }
588 	}
589     }
590 fn_exit:
591     MPIU_CHKLMEM_FREEALL();
592     return mpi_errno;
593 fn_fail:
594     goto fn_exit;
595 }
596 
597 /* MPIR_Grequest_wait: Waits until all generalized requests have
598    completed.  This routine groups grequests by class and calls the
599    wait_fn on the whole class. */
600 #undef FUNCNAME
601 #define FUNCNAME MPIR_Grequest_waitall
602 #undef FCNAME
603 #define FCNAME MPIDI_QUOTE(FUNCNAME)
MPIR_Grequest_waitall(int count,MPID_Request * const * request_ptrs)604 int MPIR_Grequest_waitall(int count, MPID_Request * const * request_ptrs)
605 {
606     void ** state_ptrs;
607     int i;
608     int mpi_error = MPI_SUCCESS;
609     MPID_Progress_state progress_state;
610     MPIU_CHKLMEM_DECL(1);
611 
612     MPIU_CHKLMEM_MALLOC(state_ptrs, void *, sizeof(void*)*count, mpi_error, "state_ptrs");
613 
614         /* DISABLED CODE: The greq wait_fn function returns when ANY
615            of the requests completes, rather than all.  Also, once a
616            greq has completed, you can't call wait on it again.  So in
617            order to implement wait-all, we would need to rebuild the
618            state_ptrs array every time wait_fn completed.  This would
619            then be an O(n^2) algorithm.
620 
621            Until a waitall_fn is added for greqs, we'll call wait on
622            each greq individually. */
623 #if 0
624     MPIX_Grequest_wait_function *wait_fn = NULL;
625     int n_greq;
626     MPIX_Grequest_class curr_class;
627     /* loop over all requests, group greqs with the same class and
628        call wait_fn on the groups.  (Only consecutive greqs with the
629        same class are being grouped) */
630     n_greq = 0;
631     for (i = 0; i < count; ++i)
632     {
633         /* skip over requests we're not interested in */
634         if (request_ptrs[i] == NULL || *request_ptrs[i]->cc_ptr == 0 ||  request_ptrs[i]->kind != MPID_UREQUEST)
635             continue;
636 
637         if (n_greq == 0 || request_ptrs[i]->greq_fns->greq_class == curr_class)
638         {
639             /* if this is the first grequest of a group, or if it's the
640                same class as the last one, add its state to the list  */
641             curr_class = request_ptrs[i]->greq_fns->greq_class;
642             wait_fn = request_ptrs[i]->greq_fns->wait_fn;
643             state_ptrs[n_greq] = request_ptrs[i]->greq_fns->grequest_extra_state;
644             ++n_greq;
645         }
646         else
647         {
648             /* greq with a new class: wait on the list of greqs we've
649                created, then start a new list*/
650             mpi_error = (wait_fn)(n_greq, state_ptrs, 0, NULL);
651             if (mpi_error) MPIU_ERR_POP(mpi_error);
652 
653             curr_class = request_ptrs[i]->greq_fns->greq_class;
654             wait_fn = request_ptrs[i]->greq_fns->wait_fn;
655             state_ptrs[0] = request_ptrs[i]->greq_fns->grequest_extra_state;
656             n_greq = 1;
657         }
658     }
659 
660     if (n_greq)
661     {
662         /* wait on the last group of greqs */
663         mpi_error = (wait_fn)(n_greq, state_ptrs, 0, NULL);
664         if (mpi_error) MPIU_ERR_POP(mpi_error);
665 
666     }
667 #else
668     for (i = 0; i < count; ++i)
669     {
670         /* skip over requests we're not interested in */
671         if (request_ptrs[i] == NULL ||
672             MPID_Request_is_complete(request_ptrs[i]) ||
673             request_ptrs[i]->kind != MPID_UREQUEST ||
674             request_ptrs[i]->greq_fns->wait_fn == NULL)
675         {
676             continue;
677         }
678 
679         mpi_error = (request_ptrs[i]->greq_fns->wait_fn)(1, &request_ptrs[i]->greq_fns->grequest_extra_state, 0, NULL);
680         if (mpi_error) MPIU_ERR_POP(mpi_error);
681         MPIU_Assert(MPID_Request_is_complete(request_ptrs[i]));
682     }
683 
684     MPID_Progress_start(&progress_state);
685     for (i = 0; i < count; ++i)
686     {
687         if (request_ptrs[i] == NULL ||
688             MPID_Request_is_complete(request_ptrs[i]) ||
689             request_ptrs[i]->kind != MPID_UREQUEST)
690         {
691             continue;
692         }
693         /* We have a greq that doesn't have a wait function; some other
694            thread will cause completion via MPI_Grequest_complete().  Rather
695            than waste the time by simply yielding the processor to the
696            other thread, we'll make progress on regular requests too.  The
697            progress engine should permit the other thread to run at some
698            point. */
699         while (!MPID_Request_is_complete(request_ptrs[i]))
700         {
701             mpi_error = MPID_Progress_wait(&progress_state);
702             if (mpi_error != MPI_SUCCESS)
703             {
704                 /* --BEGIN ERROR HANDLING-- */
705                 MPID_Progress_end(&progress_state);
706                 goto fn_fail;
707                 /* --END ERROR HANDLING-- */
708             }
709         }
710     }
711     MPID_Progress_end(&progress_state);
712 #endif
713 
714  fn_exit:
715     MPIU_CHKLMEM_FREEALL();
716     return mpi_error;
717  fn_fail:
718     goto fn_exit;
719 }
720 
721