static int handler_recv_dequeue_complete(const ptl_event_t *e) { int mpi_errno = MPI_SUCCESS; MPID_Request *const rreq = e->user_ptr; int is_contig; MPI_Aint last; MPI_Aint dt_true_lb; MPIDI_msg_sz_t data_sz; MPID_Datatype *dt_ptr ATTRIBUTE((unused)); MPIDI_STATE_DECL(MPID_STATE_HANDLER_RECV_DEQUEUE_COMPLETE); MPIDI_FUNC_ENTER(MPID_STATE_HANDLER_RECV_DEQUEUE_COMPLETE); MPIU_Assert(e->type == PTL_EVENT_PUT || e->type == PTL_EVENT_PUT_OVERFLOW); MPIDI_Datatype_get_info(rreq->dev.user_count, rreq->dev.datatype, is_contig, data_sz, dt_ptr, dt_true_lb); dequeue_req(e); if (e->type == PTL_EVENT_PUT_OVERFLOW) { /* unpack the data from unexpected buffer */ MPIU_DBG_MSG_D(CH3_CHANNEL, VERBOSE, "is_contig = %d", is_contig); if (is_contig) { MPIU_Memcpy((char *)rreq->dev.user_buf + dt_true_lb, e->start, e->mlength); } else { last = e->mlength; MPID_Segment_unpack(rreq->dev.segment_ptr, rreq->dev.segment_first, &last, e->start); if (last != e->mlength) MPIR_ERR_SET(rreq->status.MPI_ERROR, MPI_ERR_TYPE, "**dtypemismatch"); } } else { /* Data was placed directly into the user buffer, so datatype mismatch is harder to detect. We use a simple check ensuring the received bytes are a multiple of a single basic element. Currently, we do not detect mismatches with datatypes constructed of more than one basic type */ MPI_Datatype dt_basic_type; MPID_Datatype_get_basic_type(rreq->dev.datatype, dt_basic_type); if (dt_basic_type != MPI_DATATYPE_NULL && (e->mlength % MPID_Datatype_get_basic_size(dt_basic_type)) != 0) MPIR_ERR_SET(rreq->status.MPI_ERROR, MPI_ERR_TYPE, "**dtypemismatch"); } mpi_errno = handler_recv_complete(e); fn_exit: MPIDI_FUNC_EXIT(MPID_STATE_HANDLER_RECV_DEQUEUE_COMPLETE); return mpi_errno; fn_fail: goto fn_exit; }
int MPIR_Get_elements_x_impl(const MPI_Status *status, MPI_Datatype datatype, MPI_Count *elements) { int mpi_errno = MPI_SUCCESS; MPIR_Datatype *datatype_ptr = NULL; MPI_Count byte_count; if (HANDLE_GET_KIND(datatype) != HANDLE_KIND_BUILTIN) { MPID_Datatype_get_ptr(datatype, datatype_ptr); } /* three cases: * - nice, simple, single element type * - derived type with a zero size * - type with multiple element types (nastiest) */ if (HANDLE_GET_KIND(datatype) == HANDLE_KIND_BUILTIN || (datatype_ptr->builtin_element_size != -1 && datatype_ptr->size > 0)) { byte_count = MPIR_STATUS_GET_COUNT(*status); /* QUESTION: WHAT IF SOMEONE GAVE US AN MPI_UB OR MPI_LB??? */ /* in both cases we do not limit the number of types that might * be in bytes */ if (HANDLE_GET_KIND(datatype) != HANDLE_KIND_BUILTIN) { MPI_Datatype basic_type = MPI_DATATYPE_NULL; MPID_Datatype_get_basic_type(datatype_ptr->basic_type, basic_type); *elements = MPIR_Type_get_basic_type_elements(&byte_count, -1, basic_type); } else { /* Behaves just like MPI_Get_Count in the predefined case */ MPI_Count size; MPID_Datatype_get_size_macro(datatype, size); if ((byte_count % size) != 0) *elements = MPI_UNDEFINED; else *elements = MPIR_Type_get_basic_type_elements(&byte_count, -1, datatype); } MPIR_Assert(byte_count >= 0); } else if (datatype_ptr->size == 0) { if (MPIR_STATUS_GET_COUNT(*status) > 0) { /* --BEGIN ERROR HANDLING-- */ /* datatype size of zero and count > 0 should never happen. */ (*elements) = MPI_UNDEFINED; /* --END ERROR HANDLING-- */ } else { /* This is ambiguous. However, discussions on MPI Forum * reached a consensus that this is the correct return * value */ (*elements) = 0; } } else /* derived type with weird element type or weird size */ { MPIR_Assert(datatype_ptr->builtin_element_size == -1); byte_count = MPIR_STATUS_GET_COUNT(*status); *elements = MPIR_Type_get_elements(&byte_count, -1, datatype); } return mpi_errno; }
/* MPIR_Type_get_elements * * Arguments: * - bytes_p - input/output byte count * - count - maximum number of this type to subtract from the bytes; a count * of <0 indicates use as many as we like * - datatype - input datatype * * Returns number of elements available given the two constraints of number of * bytes and count of types. Also reduces the byte count by the amount taken * up by the types. * * This is called from MPI_Get_elements() when it sees a type with multiple * element types (datatype_ptr->element_sz = -1). This function calls itself too. */ PMPI_LOCAL MPI_Count MPIR_Type_get_elements(MPI_Count *bytes_p, MPI_Count count, MPI_Datatype datatype) { MPIR_Datatype *datatype_ptr = NULL; MPID_Datatype_get_ptr(datatype, datatype_ptr); /* invalid if builtin */ /* if we have gotten down to a type with only one element type, * call MPIR_Type_get_basic_type_elements() and return. */ if (HANDLE_GET_KIND(datatype) == HANDLE_KIND_BUILTIN || datatype == MPI_FLOAT_INT || datatype == MPI_DOUBLE_INT || datatype == MPI_LONG_INT || datatype == MPI_SHORT_INT || datatype == MPI_LONG_DOUBLE_INT) { return MPIR_Type_get_basic_type_elements(bytes_p, count, datatype); } else if (datatype_ptr->builtin_element_size >= 0) { MPI_Datatype basic_type = MPI_DATATYPE_NULL; MPID_Datatype_get_basic_type(datatype_ptr->basic_type, basic_type); return MPIR_Type_get_basic_type_elements(bytes_p, count * datatype_ptr->n_builtin_elements, basic_type); } else { /* we have bytes left and still don't have a single element size; must * recurse. */ int i, j, *ints; MPI_Count typecount = 0, nr_elements = 0, last_nr_elements; MPI_Aint *aints; MPI_Datatype *types; /* Establish locations of arrays */ MPID_Type_access_contents(datatype_ptr->handle, &ints, &aints, &types); if (!ints || !aints || !types) return MPI_ERR_TYPE; switch (datatype_ptr->contents->combiner) { case MPI_COMBINER_NAMED: case MPI_COMBINER_DUP: case MPI_COMBINER_RESIZED: return MPIR_Type_get_elements(bytes_p, count, *types); break; case MPI_COMBINER_CONTIGUOUS: case MPI_COMBINER_VECTOR: case MPI_COMBINER_HVECTOR_INTEGER: case MPI_COMBINER_HVECTOR: /* count is first in ints array */ return MPIR_Type_get_elements(bytes_p, count * (*ints), *types); break; case MPI_COMBINER_INDEXED_BLOCK: case MPI_COMBINER_HINDEXED_BLOCK: /* count is first in ints array, blocklength is second */ return MPIR_Type_get_elements(bytes_p, count * ints[0] * ints[1], *types); break; case MPI_COMBINER_INDEXED: case MPI_COMBINER_HINDEXED_INTEGER: case MPI_COMBINER_HINDEXED: for (i=0; i < (*ints); i++) { /* add up the blocklengths to get a max. # of the next type */ typecount += ints[i+1]; } return MPIR_Type_get_elements(bytes_p, count * typecount, *types); break; case MPI_COMBINER_STRUCT_INTEGER: case MPI_COMBINER_STRUCT: /* In this case we can't simply multiply the count of the next * type by the count of the current type, because we need to * cycle through the types just as the struct would. thus the * nested loops. * * We need to keep going until we get less elements than expected * or we run out of bytes. */ last_nr_elements = 1; /* seed value */ for (j=0; (count < 0 || j < count) && *bytes_p > 0 && last_nr_elements > 0; j++) { /* recurse on each type; bytes are reduced in calls */ for (i=0; i < (*ints); i++) { /* skip zero-count elements of the struct */ if (ints[i+1] == 0) continue; last_nr_elements = MPIR_Type_get_elements(bytes_p, ints[i+1], types[i]); nr_elements += last_nr_elements; MPIR_Assert(last_nr_elements >= 0); if (last_nr_elements < ints[i+1]) break; } } return nr_elements; break; case MPI_COMBINER_SUBARRAY: case MPI_COMBINER_DARRAY: case MPI_COMBINER_F90_REAL: case MPI_COMBINER_F90_COMPLEX: case MPI_COMBINER_F90_INTEGER: default: /* --BEGIN ERROR HANDLING-- */ MPIR_Assert(0); return -1; break; /* --END ERROR HANDLING-- */ } } }