# vim: set ft=c:

MPI_Bsend:
    .desc: Basic send with user-provided buffering
    .seealso: MPI_Buffer_attach, MPI_Ibsend, MPI_Bsend_init
    .earlyreturn: pt2pt_proc_null
{
    mpi_errno = MPIR_Bsend_isend(buf, count, datatype, dest, tag, comm_ptr, NULL);
    if (mpi_errno != MPI_SUCCESS)
        goto fn_fail;
}

MPI_Bsend_init:
    .desc: Builds a handle for a buffered send
    .seealso: MPI_Buffer_attach
{
    MPIR_Request *request_ptr = NULL;

    mpi_errno = MPID_Bsend_init(buf, count, datatype, dest, tag, comm_ptr,
                                0, &request_ptr);
    if (mpi_errno != MPI_SUCCESS)
        goto fn_fail;

    /* return the handle of the request to the user */
    MPIR_OBJ_PUBLISH_HANDLE(*request, request_ptr->handle);
}

MPI_Buffer_attach:
    .desc: Attaches a user-provided buffer for sending
    .skip: ThreadSafe
    .seealso: MPI_Buffer_detach, MPI_Bsend

MPI_Buffer_detach:
    .desc: Removes an existing buffer (for use in MPI_Bsend etc)
    .skip: ThreadSafe
    .seealso: MPI_Buffer_attach

MPI_Buffer_flush:
    .desc: block until all messages currently in the globally shared buffer of the calling process have been transmitted
    .seealso: MPI_Comm_flush_buffer, MPI_Session_flush_buffer

MPI_Buffer_iflush:
    .desc: start a nonblocking flush in the globally shared buffer
    .seealso: MPI_Buffer_flush

MPI_Comm_attach_buffer:
    .desc: Attaches a user-provided buffer for buffered send in the communicator
    .skip: ThreadSafe
    .seealso: MPI_Buffer_attach, MPI_Bsend

MPI_Comm_detach_buffer:
    .desc: Removes an existing buffer (for use in MPI_Bsend etc) in the communicator
    .skip: ThreadSafe
    .seealso: MPI_Comm_attach_buffer, MPI_Bsend

MPI_Comm_flush_buffer:
    .desc: block until all messages currently in the communicator-specific buffer of the calling process have been transmitted
    .seealso: MPI_Buffer_flush, MPI_Session_flush_buffer

MPI_Comm_iflush_buffer:
    .desc: start a nonblocking flush in the communicator-specific buffer
    .seealso: MPI_Comm_flush_buffer

MPI_Ibsend:
    .desc: Starts a nonblocking buffered send
    .earlyreturn: pt2pt_proc_null
{
    mpi_errno = MPIR_Bsend_isend(buf, count, datatype, dest, tag, comm_ptr, NULL);
    if (mpi_errno)
        goto fn_fail;

    /* Ibsend is local-complete */
    MPIR_Request *request_ptr = MPIR_Request_create_complete(MPIR_REQUEST_KIND__SEND);
    *request = request_ptr->handle;
}

MPI_Improbe:
    .desc: Nonblocking matched probe.
    .earlyreturn: pt2pt_proc_null
{
    MPIR_Request *msgp = NULL;

    *message = MPI_MESSAGE_NULL;
    mpi_errno = MPID_Improbe(source, tag, comm_ptr, 0, flag, &msgp, status);
    MPIR_ERR_CHECK(mpi_errno);

    if (*flag) {
        MPIR_Assert(msgp != NULL);
        *message = msgp->handle;
    }
}

MPI_Imrecv:
    .desc: Nonblocking receive of message matched by MPI_Mprobe or MPI_Improbe.
{ -- early_return --
    if (message_ptr == NULL || message_ptr->handle == MPIR_REQUEST_NULL_RECV) {
        MPIR_Request *rreq;
        rreq = MPIR_Request_create_null_recv();
        *request = rreq->handle;
        *message = MPI_MESSAGE_NULL;
        goto fn_exit;
    }
}
{
    MPIR_Request *rreq = NULL;

    mpi_errno = MPID_Imrecv(buf, count, datatype, message_ptr, &rreq);
    MPIR_ERR_CHECK(mpi_errno);

    MPIR_Assert(rreq != NULL);
    *request = rreq->handle;
    *message = MPI_MESSAGE_NULL;
}

MPI_Iprobe:
    .desc: Nonblocking test for a message
    .earlyreturn: pt2pt_proc_null
{
    /* FIXME: Is this correct for intercomms? */
    mpi_errno = MPID_Iprobe(source, tag, comm_ptr, 0, flag, status);
    if (mpi_errno != MPI_SUCCESS)
        goto fn_fail;
}

MPI_Irecv:
    .desc: Begins a nonblocking receive
    .earlyreturn: pt2pt_proc_null
    .extra: threadcomm
{
    MPIR_Request *request_ptr = NULL;

    mpi_errno = MPID_Irecv(buf, count, datatype, source, tag, comm_ptr, 0, &request_ptr);
    /* return the handle of the request to the user */
    /* MPIU_OBJ_HANDLE_PUBLISH is unnecessary for irecv, lower-level access is
     * responsible for its own consistency, while upper-level field access is
     * controlled by the completion counter */
    *request = request_ptr->handle;

    /* Put this part after setting the request so that if the request is
     * pending (which is still considered an error), it will still be set
     * correctly here. For real error cases, the user might get garbage as
     * their request value, but that's fine since the definition is
     * undefined anyway. */
    if (mpi_errno != MPI_SUCCESS)
        goto fn_fail;
}

MPI_Irsend:
    .desc: Starts a nonblocking ready send
    .earlyreturn: pt2pt_proc_null
{
    MPIR_Request *request_ptr = NULL;

    mpi_errno = MPID_Irsend(buf, count, datatype, dest, tag, comm_ptr, 0, &request_ptr);
    if (mpi_errno != MPI_SUCCESS)
        goto fn_fail;

    /* return the handle of the request to the user */
    /* MPIU_OBJ_HANDLE_PUBLISH is unnecessary for irsend, lower-level access is
     * responsible for its own consistency, while upper-level field access is
     * controlled by the completion counter */
    *request = request_ptr->handle;
}

MPI_Isend:
    .desc: Begins a nonblocking send
    .earlyreturn: pt2pt_proc_null
    .extra: threadcomm
{
    MPIR_Request *request_ptr = NULL;

    mpi_errno = MPID_Isend(buf, count, datatype, dest, tag, comm_ptr, 0, &request_ptr);
    if (mpi_errno != MPI_SUCCESS)
        goto fn_fail;

    /* return the handle of the request to the user */
    /* MPIU_OBJ_HANDLE_PUBLISH is unnecessary for isend, lower-level access is
     * responsible for its own consistency, while upper-level field access is
     * controlled by the completion counter */
    *request = request_ptr->handle;
}

MPI_Issend:
    .desc: Starts a nonblocking synchronous send
    .earlyreturn: pt2pt_proc_null
{
    MPIR_Request *request_ptr = NULL;

    mpi_errno = MPID_Issend(buf, count, datatype, dest, tag, comm_ptr, 0, &request_ptr);
    if (mpi_errno != MPI_SUCCESS)
        goto fn_fail;

    /* return the handle of the request to the user */
    /* MPIU_OBJ_HANDLE_PUBLISH is unnecessary for issend, lower-level access is
     * responsible for its own consistency, while upper-level field access is
     * controlled by the completion counter */
    *request = request_ptr->handle;
}

MPI_Mprobe:
    .desc: Blocking matched probe.
    .earlyreturn: pt2pt_proc_null
{
    MPIR_Request *msgp = NULL;

    *message = MPI_MESSAGE_NULL;
    mpi_errno = MPID_Mprobe(source, tag, comm_ptr, 0, &msgp, status);
    MPIR_ERR_CHECK(mpi_errno);

    MPIR_Assert(msgp != NULL);
    *message = msgp->handle;
}

MPI_Mrecv:
    .desc: Blocking receive of message matched by MPI_Mprobe or MPI_Improbe.
{ -- early_return --
    if (message_ptr == NULL || message_ptr->handle == MPIR_REQUEST_NULL_RECV) {
        /* treat as though MPI_MESSAGE_NO_PROC was passed */
        MPIR_Status_set_procnull(status);
        *message = MPI_MESSAGE_NULL;
        goto fn_exit;
    }
}
{
    MPIR_Request *rreq = NULL;
    mpi_errno = MPID_Mrecv(buf, count, datatype, message_ptr, status, &rreq);
    MPIR_ERR_CHECK(mpi_errno);
    /* rreq == NULL implies message = MPI_MESSAGE_NO_PROC.
     * I.e, status was set and no need to wait on rreq */
    if (rreq != NULL) {
        mpi_errno = MPIR_Wait(rreq, status);
        MPIR_Request_free(rreq);
        MPIR_ERR_CHECK(mpi_errno);
    }

    *message = MPI_MESSAGE_NULL;
}

MPI_Probe:
    .desc: Blocking test for a message
    .earlyreturn: pt2pt_proc_null
{
    mpi_errno = MPID_Probe(source, tag, comm_ptr, 0, status);
    if (mpi_errno != MPI_SUCCESS)
        goto fn_fail;
}

MPI_Recv:
    .desc: Blocking receive for a message
    .earlyreturn: pt2pt_proc_null
    .extra: threadcomm
{
    MPIR_Request *request_ptr = NULL;

    /* MT: Note that MPID_Recv may release the SINGLE_CS if it
     * decides to block internally.  MPID_Recv in that case will
     * re-aquire the SINGLE_CS before returning */
    mpi_errno = MPID_Recv(buf, count, datatype, source, tag, comm_ptr, 0, status, &request_ptr);
    if (mpi_errno != MPI_SUCCESS)
        goto fn_fail;

    if (request_ptr == NULL) {
        goto fn_exit;
    }

    mpi_errno = MPIR_Wait(request_ptr, status);
    MPIR_Request_free(request_ptr);
    if (mpi_errno != MPI_SUCCESS)
        goto fn_fail;
}

MPI_Recv_init:
    .desc: Create a persistent request for a receive
    .seealso: MPI_Start, MPI_Startall, MPI_Request_free
{
    MPIR_Request *request_ptr = NULL;

    mpi_errno = MPID_Recv_init(buf, count, datatype, source, tag, comm_ptr, 0, &request_ptr);
    if (mpi_errno != MPI_SUCCESS)
        goto fn_fail;

    /* return the handle of the request to the user */
    MPIR_OBJ_PUBLISH_HANDLE(*request, request_ptr->handle);
}

MPI_Rsend:
    .desc: Blocking ready send
    .earlyreturn: pt2pt_proc_null
{
    MPIR_Request *request_ptr = NULL;

    mpi_errno = MPID_Rsend(buf, count, datatype, dest, tag, comm_ptr, 0, &request_ptr);
    if (mpi_errno != MPI_SUCCESS)
        goto fn_fail;

    if (request_ptr == NULL) {
        goto fn_exit;
    }

    /* If a request was returned, then we need to block until the request
     * is complete */
    mpi_errno = MPIR_Wait(request_ptr, MPI_STATUS_IGNORE);
    MPIR_Request_free(request_ptr);
    MPIR_ERR_CHECK(mpi_errno);
}

MPI_Rsend_init:
    .desc: Creates a persistent request for a ready send
    .seealso: MPI_Start, MPI_Request_free, MPI_Send_init
{
    MPIR_Request *request_ptr = NULL;

    mpi_errno = MPID_Rsend_init(buf, count, datatype, dest, tag, comm_ptr, 0, &request_ptr);
    if (mpi_errno != MPI_SUCCESS)
        goto fn_fail;

    /* return the handle of the request to the user */
    MPIR_OBJ_PUBLISH_HANDLE(*request, request_ptr->handle);
}

MPI_Send:
    .desc: Performs a blocking send
    .seealso: MPI_Isend, MPI_Bsend
    .earlyreturn: pt2pt_proc_null
    .extra: threadcomm
{
    MPIR_Request *request_ptr = NULL;

    mpi_errno = MPID_Send(buf, count, datatype, dest, tag, comm_ptr, 0, &request_ptr);
    if (mpi_errno != MPI_SUCCESS)
        goto fn_fail;

    if (request_ptr == NULL) {
        goto fn_exit;
    }

    mpi_errno = MPIR_Wait(request_ptr, MPI_STATUS_IGNORE);
    MPIR_Request_free(request_ptr);
    MPIR_ERR_CHECK(mpi_errno);
}

MPI_Send_init:
    .desc: Create a persistent request for a standard send
    .seealso: MPI_Start, MPI_Startall, MPI_Request_free
{
    MPIR_Request *request_ptr = NULL;

    mpi_errno = MPID_Send_init(buf, count, datatype, dest, tag, comm_ptr, 0, &request_ptr);
    if (mpi_errno != MPI_SUCCESS)
        goto fn_fail;

    /* return the handle of the request to the user */
    MPIR_OBJ_PUBLISH_HANDLE(*request, request_ptr->handle);
}

MPI_Sendrecv:
    .desc: Sends and receives a message

MPI_Sendrecv_replace:
    .desc: Sends and receives using a single buffer
    .decl: MPIR_Sendrecv_replace_impl
{
#if defined(MPID_Sendrecv_replace)
    mpi_errno = MPID_Sendrecv_replace(buf, count, datatype, dest,
                                      sendtag, source, recvtag, comm_ptr, status);
#else
    mpi_errno = MPIR_Sendrecv_replace_impl(buf, count, datatype, dest,
                                           sendtag, source, recvtag, comm_ptr, status);
#endif

    if (mpi_errno != MPI_SUCCESS)
        goto fn_fail;
}

MPI_Session_attach_buffer:
    .desc: Attaches a user-provided buffer for buffered send in the session
    .skip: ThreadSafe
    .seealso: MPI_Buffer_attach, MPI_Bsend

MPI_Session_detach_buffer:
    .desc: Removes an existing buffer (for use in MPI_Bsend etc) in the session
    .skip: ThreadSafe
    .seealso: MPI_Session_attach_buffer, MPI_Bsend

MPI_Session_flush_buffer:
    .desc: block until all messages currently in the session-specific buffer of the calling process have been transmitted
    .seealso: MPI_Buffer_flush, MPI_Comm_flush_buffer

MPI_Session_iflush_buffer:
    .desc: start a nonblocking flush in the session-specific buffer
    .seealso: MPI_Session_flush_buffer

MPI_Ssend:
    .desc: Blocking synchronous send
    .earlyreturn: pt2pt_proc_null
{
    MPIR_Request *request_ptr = NULL;

    mpi_errno = MPID_Ssend(buf, count, datatype, dest, tag, comm_ptr, 0, &request_ptr);
    if (mpi_errno != MPI_SUCCESS)
        goto fn_fail;

    if (request_ptr == NULL) {
        goto fn_exit;
    }

    /* If a request was returned, then we need to block until the request
     * is complete */
    mpi_errno = MPIR_Wait(request_ptr, MPI_STATUS_IGNORE);
    MPIR_Request_free(request_ptr);
    MPIR_ERR_CHECK(mpi_errno);
}

MPI_Ssend_init:
    .desc: Creates a persistent request for a synchronous send
{
    MPIR_Request *request_ptr = NULL;

    mpi_errno = MPID_Ssend_init(buf, count, datatype, dest, tag, comm_ptr, 0, &request_ptr);
    if (mpi_errno != MPI_SUCCESS)
        goto fn_fail;

    /* return the handle of the request to the user */
    MPIR_OBJ_PUBLISH_HANDLE(*request, request_ptr->handle);
}

MPI_Isendrecv:
    .desc: Starts a nonblocking send and receive

MPI_Isendrecv_replace:
    .desc: Starts a nonblocking send and receive with a single buffer
