root/ompi/request/grequest.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. ompi_grequest_free
  2. ompi_grequest_cancel
  3. ompi_grequest_construct
  4. ompi_grequest_destruct
  5. ompi_grequest_start
  6. ompi_grequest_complete
  7. ompi_grequest_invoke_query

   1 /*
   2  * Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana
   3  *                         University Research and Technology
   4  *                         Corporation.  All rights reserved.
   5  * Copyright (c) 2004-2016 The University of Tennessee and The University
   6  *                         of Tennessee Research Foundation.  All rights
   7  *                         reserved.
   8  * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart,
   9  *                         University of Stuttgart.  All rights reserved.
  10  * Copyright (c) 2004-2005 The Regents of the University of California.
  11  *                         All rights reserved.
  12  * Copyright (c) 2006-2012 Cisco Systems, Inc.  All rights reserved.
  13  * Copyright (c) 2009      Sun Microsystems, Inc.  All rights reserved.
  14  * $COPYRIGHT$
  15  *
  16  * Additional copyrights may follow
  17  *
  18  * $HEADER$
  19  */
  20 
  21 #include "ompi_config.h"
  22 #include "ompi/communicator/communicator.h"
  23 #include "ompi/request/grequest.h"
  24 #include "ompi/mpi/fortran/base/fint_2_int.h"
  25 
  26 
  27 /*
  28  * See the comment in the grequest destructor for the weird semantics
  29  * here.  If the request has been marked complete via a call to
  30  * MPI_GREQUEST_COMPLETE, actually release the object.  OTherwise,
  31  * just mark this object as "freed" so that a later call to
  32  * MPI_GREQUEST_COMPLETE will release it (!).
  33  *
  34  * Note that TEST* and WAIT* will call this function when a request
  35  * has been completed.
  36  */
  37 static int ompi_grequest_free(ompi_request_t** req)
  38 {
  39     OBJ_RELEASE(*req);
  40     *req = MPI_REQUEST_NULL;
  41     return OMPI_SUCCESS;
  42 }
  43 
  44 static int ompi_grequest_cancel(ompi_request_t* req, int flag)
  45 {
  46     int rc = OMPI_SUCCESS;
  47     MPI_Fint ierr;
  48     ompi_fortran_logical_t fflag;
  49     ompi_grequest_t* greq = (ompi_grequest_t*)req;
  50 
  51     if (greq->greq_cancel.c_cancel != NULL) {
  52         if (greq->greq_funcs_are_c) {
  53             rc = greq->greq_cancel.c_cancel(greq->greq_state,
  54                                             REQUEST_COMPLETE(&greq->greq_base));
  55         } else {
  56             fflag = (ompi_fortran_logical_t) REQUEST_COMPLETE(&greq->greq_base);
  57             greq->greq_cancel.f_cancel((MPI_Aint*)greq->greq_state, &fflag, &ierr);
  58             rc = OMPI_FINT_2_INT(ierr);
  59         }
  60     }
  61     return rc;
  62 }
  63 
  64 static void ompi_grequest_construct(ompi_grequest_t* greq)
  65 {
  66     greq->greq_base.req_free     = ompi_grequest_free;
  67     greq->greq_base.req_cancel   = ompi_grequest_cancel;
  68     greq->greq_base.req_type = OMPI_REQUEST_GEN;
  69     greq->greq_base.req_mpi_object.comm = &(ompi_mpi_comm_world.comm);
  70     /* Set the function pointers to C here; the F77 MPI API will
  71        override this value if the gen request was created from
  72        Fortran */
  73     greq->greq_funcs_are_c = true;
  74 }
  75 
  76 /*
  77  * MPI has some weird semantics with respect to generalized requests
  78  * -- different than all other MPI object types.  So we move some
  79  * cleanup stuff here to the destructor rather than in
  80  * greqeust_request_free -- mainly because the cleanup may be required
  81  * in two different places.
  82  *
  83  * Specifically, generalized requests can be completed (and therefore
  84  * released) the following ways:
  85  *
  86  * 1. Call to MPI_GREQUEST_COMPLETE and then a corresponding call to
  87  * some flavor of MPI_TEST* or MPI_WAIT*.  This will both complete the
  88  * requests and destroy the coresponding MPI generalized request
  89  * object.
  90  *
  91  * 2. Call MPI_REQUEST_FREE and then (!) -- with some other
  92  * still-valid copy of the handler -- call MPI_GREQUEST_COMPLETE.
  93  *
  94  * 3. Reverse the order of #2 -- call MPI_GREQUEST_COMPLETE and then
  95  * MPI_REQUEST_FREE.
  96  *
  97  * So any one of these functions may actually be the one that
  98  * de-allocates the back-end request object.  Hence, this is perfect
  99  * for our reference counting system -- so the call to the gen request
 100  * free_fn() is back here in the destructor, whenever the object is
 101  * actually freed.
 102  *
 103  * Hence, the following must occur before a grequest is freed:
 104  *
 105  * - ompi_grequest_complete() (i.e., GREQUEST_COMPLETE) is invoked
 106  * - ompi_grequest_free() is invoked
 107  *
 108  * Remember that ompi_grequest_free() is invoked by MPI_TEST* and
 109  * MPI_WAIT* when the request was previously marked as complete and
 110  * TEST* / WAIT* notified the user as such, and this function is also
 111  * invoked by REQUEST_FREE).  Hence, these two functions will *always*
 112  * be invoked, but the order in which they are invoked is up to the
 113  * user.  So this is a perfect opprotunity for the OBJ_* reference
 114  * count system.  When we create an ompi_grequest_t in
 115  * ompi_grequest_start(), we both OBJ_NEW and OBJ_RETAIN it so that
 116  * its reference count goes to 0.  Then in ompi_grequest_complete()
 117  * and ompi_grequest_free(), we OBJ_RELEASE it.  Hence, when both of
 118  * them have RELEASEd -- regardless of the order in which the
 119  * functions were invoked, then the destructor is invoked and
 120  * everything is cleaned up (and we invoked the grequest free_fn).
 121  */
 122 static void ompi_grequest_destruct(ompi_grequest_t* greq)
 123 {
 124     MPI_Fint ierr;
 125 
 126     if (greq->greq_free.c_free != NULL) {
 127         if (greq->greq_funcs_are_c) {
 128             greq->greq_free.c_free(greq->greq_state);
 129         } else {
 130             greq->greq_free.f_free((MPI_Aint*)greq->greq_state, &ierr);
 131         }
 132     }
 133 
 134     OMPI_REQUEST_FINI(&greq->greq_base);
 135 }
 136 
 137 
 138 OBJ_CLASS_INSTANCE(
 139     ompi_grequest_t,
 140     ompi_request_t,
 141     ompi_grequest_construct,
 142     ompi_grequest_destruct);
 143 
 144 
 145 int ompi_grequest_start(
 146     MPI_Grequest_query_function *gquery_fn,
 147     MPI_Grequest_free_function *gfree_fn,
 148     MPI_Grequest_cancel_function *gcancel_fn,
 149     void* gstate,
 150     ompi_request_t** request)
 151 {
 152     ompi_grequest_t *greq = OBJ_NEW(ompi_grequest_t);
 153     if(greq == NULL) {
 154         return OMPI_ERR_OUT_OF_RESOURCE;
 155     }
 156     /* We call RETAIN here specifically to increase the refcount to 2.
 157        See comment before the destructor for an explanation. */
 158     OBJ_RETAIN(greq);
 159 
 160     greq->greq_base.req_state = OMPI_REQUEST_ACTIVE;
 161     greq->greq_state = gstate;
 162     greq->greq_query.c_query = gquery_fn;
 163     greq->greq_free.c_free = gfree_fn;
 164     greq->greq_cancel.c_cancel = gcancel_fn;
 165     greq->greq_base.req_status = ompi_status_empty;
 166 
 167     *request = &greq->greq_base;
 168     return OMPI_SUCCESS;
 169 }
 170 
 171 
 172 /*
 173  * Beware the odd semantics listed in MPI-2:8.2...  See the comment in
 174  * the grequest destructor.
 175  *
 176  * First do the normal stuff to complete the request (i.e., call
 177  * ompi_request_complete()).  Then, if this request object was
 178  * previously freed via MPI_REQUEST_FREE, release it.
 179  */
 180 int ompi_grequest_complete(ompi_request_t *req)
 181 {
 182     int rc;
 183 
 184     rc = ompi_request_complete(req, true);
 185     OBJ_RELEASE(req);
 186     return rc;
 187 }
 188 
 189 
 190 /*
 191  * Grequest queries are invoked in two places:
 192  *
 193  * 1. MPI_TEST* / MPI_WAIT*, when requests have completed.
 194  *
 195  * 2. MPI_REQUEST_GET_STATUS, when requests may or may not have
 196  * completed.
 197  *
 198  */
 199 int ompi_grequest_invoke_query(ompi_request_t *request,
 200                                ompi_status_public_t *status)
 201 {
 202     int rc = OMPI_SUCCESS;
 203     ompi_grequest_t *g = (ompi_grequest_t*) request;
 204 
 205     /* MPI-2:8.2 does not say what to do with the return value from
 206        the query function (i.e., the int return value from the C
 207        function or the ierr argument from the Fortran function).
 208        Making the command decision here to ignore it.  If the handler
 209        wants to pass an error back, it should set it in the MPI_ERROR
 210        field in the status (which is always kept, regardless if the
 211        top-level function was invoked with MPI_STATUS[ES]_IGNORE or
 212        not).  */
 213     if (NULL != g->greq_query.c_query) {
 214         if (g->greq_funcs_are_c) {
 215             rc = g->greq_query.c_query(g->greq_state, status);
 216         } else {
 217             MPI_Fint ierr;
 218             MPI_Fint fstatus[sizeof(MPI_Status) / sizeof(int)];
 219             g->greq_query.f_query((MPI_Aint*)g->greq_state, fstatus, &ierr);
 220             MPI_Status_f2c(fstatus, status);
 221             rc = OMPI_FINT_2_INT(ierr);
 222         }
 223     }
 224 
 225     return rc;
 226 }
 227 

/* [<][>][^][v][top][bottom][index][help] */