/*
 * Copyright (C) by Argonne National Laboratory
 *     See COPYRIGHT in top-level directory
 */

#include "mpidimpl.h"

int (*MPIDI_Anysource_improbe_fn)(int tag, MPIR_Comm * comm, int context_offset,
                                  int *flag, MPIR_Request **message,
                                  MPI_Status * status) = NULL;

int MPID_Improbe(int source, int tag, MPIR_Comm *comm, int attr,
                 int *flag, MPIR_Request **message, MPI_Status *status)
{
    int mpi_errno = MPI_SUCCESS;
    int context_offset = MPIR_PT2PT_ATTR_CONTEXT_OFFSET(attr);
    int context_id = comm->recvcontext_id + context_offset;

    *message = NULL;

    /* Check to make sure the communicator hasn't already been revoked */
    if (comm->revoked) {
        MPIR_ERR_SETANDJUMP(mpi_errno,MPIX_ERR_REVOKED,"**revoked");
    }

#ifdef ENABLE_COMM_OVERRIDES
    if (MPIDI_Anysource_improbe_fn) {
        if (source == MPI_ANY_SOURCE) {
            /* if it's anysource, check shm, then check the network.
               If still not found, call progress, and check again. */

            /* check shm*/
            *message = MPIDI_CH3U_Recvq_FDU_matchonly(source, tag, context_id, comm, flag);
            if (!*flag) {
                /* not found, check network */
                mpi_errno = MPIDI_Anysource_improbe_fn(tag, comm, context_offset, flag, message, status);
                MPIR_ERR_CHECK(mpi_errno);
                if (!*flag) {
                    /* still not found, make some progress*/
                    mpi_errno = MPIDI_CH3_Progress_poke();
                    MPIR_ERR_CHECK(mpi_errno);
                    /* check shm again */
                    *message = MPIDI_CH3U_Recvq_FDU_matchonly(source, tag, context_id, comm, flag);
                    if (!*flag) {
                        /* check network again */
                        mpi_errno = MPIDI_Anysource_improbe_fn(tag, comm, context_offset, flag, message, status);
                        MPIR_ERR_CHECK(mpi_errno);
                    }
                }
            }
            goto fn_exit;
        }
        else {
            /* it's not anysource, check if the netmod has overridden it */
            MPIDI_VC_t * vc;
            MPIDI_Comm_get_vc_set_active(comm, source, &vc);
            if (vc->comm_ops && vc->comm_ops->improbe) {
                mpi_errno = vc->comm_ops->improbe(vc, source, tag, comm, context_offset, flag, message, status);
                MPIR_ERR_CHECK(mpi_errno);
                goto fn_exit;
            }
            /* fall-through to shm case */
        }
    }
#endif

    *message = MPIDI_CH3U_Recvq_FDU_matchonly(source, tag, context_id, comm, flag);

    if (!*flag) {
        /* Always try to advance progress before returning failure
           from the improbe test. */
        /* FIXME: It would be helpful to know if the Progress_poke
           operation causes any change in state; we could then avoid
           a second test of the receive queue if we knew that nothing
           had changed */
        mpi_errno = MPID_Progress_poke();
        MPIR_ERR_CHECK(mpi_errno);
        *message = MPIDI_CH3U_Recvq_FDU_matchonly(source, tag, context_id, comm, flag);
    }

    if (*flag && *message) {
        (*message)->kind = MPIR_REQUEST_KIND__MPROBE;
        MPIR_Request_extract_status((*message), status);
    }

fn_exit:
    return mpi_errno;
fn_fail:
    goto fn_exit;
}

