# vim: set ft=c:

MPI_Comm_compare:
    .desc: Compares two communicators
    .extra: ignore_revoked_comm

MPI_Comm_create:
    .desc: Creates a new communicator
    .seealso: MPI_Comm_free

MPI_Comm_create_group:
    .desc: Creates a new communicator
    .seealso: MPI_Comm_free
    .extra: errtest_comm_intra

MPI_Comm_dup:
    .desc: Duplicates an existing communicator
    .seealso: MPI_Comm_free, MPI_Keyval_create, MPI_Attr_put, MPI_Attr_delete, MPI_Comm_create_keyval, MPI_Comm_set_attr, MPI_Comm_delete_attr
    .extra: threadcomm

MPI_Comm_dup_with_info:
    .desc: Duplicates an existing communicator using the supplied info hints
    .seealso: MPI_Comm_dup, MPI_Comm_free, MPI_Keyval_create, MPI_Attr_put, MPI_Attr_delete, MPI_Comm_create_keyval, MPI_Comm_set_attr, MPI_Comm_delete_attr

MPI_Comm_free:
    .desc: Marks the communicator object for deallocation
    .extra: ignore_revoked_comm, threadcomm
{ -- error_check --
    if (HANDLE_IS_BUILTIN(*comm)) {
        mpi_errno = MPIR_Err_create_code(MPI_SUCCESS, MPIR_ERR_RECOVERABLE, __func__, __LINE__,
                                         MPI_ERR_COMM, "**commperm", "**commperm %s",
                                         comm_ptr->name);
        goto fn_fail;
    }
}

MPI_Comm_get_info:
    .desc: Returns a new info object containing the hints
    .extra: ignore_revoked_comm

MPI_Comm_get_name:
    .desc: Return the print name from the communicator
    .docnotes: COMMNULL
    .extra: ignore_revoked_comm

MPI_Comm_group:
    .desc: Accesses the group associated with given communicator
    .docnotes: COMMNULL
    .extra: ignore_revoked_comm

MPI_Comm_idup:
    .desc: nonblocking communicator duplication

MPI_Comm_idup_with_info:
    .desc: nonblocking communicator duplication

MPI_Comm_rank:
    .desc: Determines the rank of the calling process in the communicator
    .skip: global_cs
    .extra: ignore_revoked_comm, threadcomm

MPI_Comm_remote_group:
    .desc: Accesses the remote group associated with
    .seealso: MPI_Group_free
    .extra: ignore_revoked_comm

MPI_Comm_remote_size:
    .desc: Determines the size of the remote group
    .skip: global_cs
    .extra: ignore_revoked_comm

MPI_Comm_set_info:
    .desc: Set new values for the hints of the communicator associated with comm

MPI_Comm_set_name:
    .desc: Sets the print name for a communicator

MPI_Comm_size:
    .desc: Determines the size of the group associated with a communicator
    .skip: global_cs
    .docnotes: NULL
    .extra: ignore_revoked_comm, threadcomm

MPI_Comm_split:
    .desc: Creates new communicators based on colors and keys
    .skip: validate-COLOR, validate-KEY
    .seealso: MPI_Comm_free

MPI_Comm_split_type:
    .desc: Creates new communicators based on split types and keys
    .skip: validate-SPLIT_TYPE, validate-KEY
    .seealso: MPI_Comm_free
{ -- error_check --
    CHECKENUM: split_type, splittype, MPI_UNDEFINED MPI_COMM_TYPE_SHARED MPI_COMM_TYPE_HW_GUIDED MPI_COMM_TYPE_HW_UNGUIDED MPI_COMM_TYPE_RESOURCE_GUIDED MPIX_COMM_TYPE_NEIGHBORHOOD
}

MPI_Comm_test_inter:
    .desc: Tests to see if a comm is an inter-communicator
    .skip: global_cs

MPIX_Comm_test_threadcomm:
    comm: COMMUNICATOR, [communicator]
    flag: LOGICAL, direction=out, [true if comm is an inter-communicator]
    .desc: Tests to see if a comm is a threadcomm
    .skip: global_cs

MPI_Intercomm_create_from_groups:
    .desc: Create an intercommuncator from local and remote groups
{ -- early_return --
    if (local_group == MPI_GROUP_EMPTY || remote_group == MPI_GROUP_EMPTY) {
        *newintercomm = MPI_COMM_NULL;
        goto fn_exit;
    }
}

MPI_Intercomm_create:
    .desc: Creates an intercommuncator from two intracommunicators
    .skip: validate-RANK
    .extra: errtest_comm_intra
    .seealso: MPI_Intercomm_merge, MPI_Comm_free, MPI_Comm_remote_group, MPI_Comm_remote_size
{ -- error_check --
    /* Validate local_comm_ptr */
    MPIR_Comm_valid_ptr(local_comm_ptr, mpi_errno, FALSE);
    if (local_comm_ptr) {
        /*  Only check if local_comm_ptr valid */
        MPIR_ERRTEST_COMM_INTRA(local_comm_ptr, mpi_errno);
        if ((local_leader < 0 || local_leader >= local_comm_ptr->local_size)) {
            MPIR_ERR_SET2(mpi_errno, MPI_ERR_RANK,
                            "**ranklocal", "**ranklocal %d %d",
                            local_leader, local_comm_ptr->local_size - 1);
            /* If local_comm_ptr is not valid, it will be reset to null */
            if (mpi_errno)
                goto fn_fail;
        }
        if (local_comm_ptr->rank == local_leader) {
            MPIR_ERRTEST_COMM(peer_comm, mpi_errno);
            MPIR_Comm_valid_ptr(peer_comm_ptr, mpi_errno, FALSE);
            /* Note: In MPI 1.0, peer_comm was restricted to
                * intracommunicators.  In 1.1, it may be any communicator */

            /* In checking the rank of the remote leader,
                * allow the peer_comm to be in intercommunicator
                * by checking against the remote size */
            if (!mpi_errno && peer_comm_ptr &&
                (remote_leader < 0 || remote_leader >= peer_comm_ptr->remote_size)) {
                MPIR_ERR_SET2(mpi_errno, MPI_ERR_RANK,
                                "**rankremote", "**rankremote %d %d",
                                remote_leader, peer_comm_ptr->remote_size - 1);
            }
            /* Check that the local leader and the remote leader are
                * different processes.  This test requires looking at
                * the lpid for the two ranks in their respective
                * communicators.  However, an easy test is for
                * the same ranks in an intracommunicator; we only
                * need the lpid comparison for intercommunicators */
            /* Here is the test.  We restrict this test to the
                * process that is the local leader (local_comm_ptr->rank ==
                * local_leader because we can then use peer_comm_ptr->rank
                * to get the rank in peer_comm of the local leader. */
            if (peer_comm_ptr->comm_kind == MPIR_COMM_KIND__INTRACOMM &&
                local_comm_ptr->rank == local_leader && peer_comm_ptr->rank == remote_leader) {
                MPIR_ERR_SET(mpi_errno, MPI_ERR_RANK, "**ranksdistinct");
            }
            if (mpi_errno)
                goto fn_fail;
        }
    }
}

MPI_Intercomm_merge:
    .desc: Creates an intracommuncator from an intercommunicator
    .skip: validate-LOGICAL
    .extra: setup_intercomm_localcomm
    .seealso: MPI_Intercomm_create, MPI_Comm_free
{ -- handle_ptr --
    /* Make sure that we have a local intercommunicator */
    if (!intercomm_ptr->local_comm) {
        /* Manufacture the local communicator */
        MPII_Setup_intercomm_localcomm(intercomm_ptr);
    }
}
{ -- error_check --
    int acthigh;
    /* Check for consistent values of high in each local group.
     * The Intel test suite checks for this; it is also an easy
     * error to make */
    acthigh = high ? 1 : 0;     /* Clamp high into 1 or 0 */
    mpi_errno = MPIR_Allreduce_fallback(MPI_IN_PLACE, &acthigh, 1, MPIR_INT_INTERNAL,
                                        MPI_SUM, intercomm_ptr->local_comm, MPIR_COLL_ATTR_SYNC);
    MPIR_ERR_CHECK(mpi_errno);
    /* acthigh must either == 0 or the size of the local comm */
    if (acthigh != 0 && acthigh != intercomm_ptr->local_size) {
        mpi_errno = MPIR_Err_create_code(MPI_SUCCESS,
                                         MPIR_ERR_RECOVERABLE, __func__, __LINE__,
                                         MPI_ERR_ARG, "**notsame", "**notsame %s %s",
                                         "high", "MPI_Intercomm_merge");
        goto fn_fail;
    }
}

MPIX_Comm_revoke:
    comm: COMMUNICATOR, [communicator to revoke]
    .desc: Prevent a communicator from being used in the future
    .extra: ignore_revoked_comm
{
    mpi_errno = MPID_Comm_revoke(comm_ptr, 0);
    if (mpi_errno) {
        goto fn_fail;
    }
}

MPIX_Comm_shrink:
    comm: COMMUNICATOR, [communicator]
    newcomm: COMMUNICATOR, direction=out, [new communicator]
    .desc: Creates a new communitor from an existing communicator while excluding failed processes
    .extra: ignore_revoked_comm

MPIX_Comm_failure_ack:
    comm: COMMUNICATOR, [communicator]
    .desc: Acknowledge the current group of failed processes
    .extra: ignore_revoked_comm
    .impl: mpid

MPIX_Comm_failure_get_acked:
    comm: COMMUNICATOR, [communicator]
    failedgrp: GROUP, direction=out, [group of failed processes]
    .desc: Get the group of acknowledged failures.
    .extra: ignore_revoked_comm
    .impl: mpid

MPIX_Comm_agree:
    comm: COMMUNICATOR, [communicator]
    flag: LOGICAL, direction=out, [new communicator]
    .desc: Performs agreement operation on comm
    .extra: ignore_revoked_comm

MPIX_Comm_get_failed:
    comm: COMMUNICATOR, [communicator]
    failedgrp: GROUP, direction=out, [group of failed processes]
    .desc: This local operation returns the group of processes that are locally known to have failed.
