Blame src/mpi/comm/commutil.c

Packit Service c5cf8c
/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil ; -*- */
Packit Service c5cf8c
/*
Packit Service c5cf8c
 *  (C) 2001 by Argonne National Laboratory.
Packit Service c5cf8c
 *      See COPYRIGHT in top-level directory.
Packit Service c5cf8c
 */
Packit Service c5cf8c
Packit Service c5cf8c
#include "mpiimpl.h"
Packit Service c5cf8c
#include "mpicomm.h"
Packit Service c5cf8c
#include "mpir_info.h"  /* MPIR_Info_free */
Packit Service c5cf8c
Packit Service c5cf8c
#include "utlist.h"
Packit Service c5cf8c
#include "uthash.h"
Packit Service c5cf8c
Packit Service c5cf8c
/* This is the utility file for comm that contains the basic comm items
Packit Service c5cf8c
   and storage management */
Packit Service c5cf8c
#ifndef MPID_COMM_PREALLOC
Packit Service c5cf8c
#define MPID_COMM_PREALLOC 8
Packit Service c5cf8c
#endif
Packit Service c5cf8c
Packit Service c5cf8c
/* Preallocated comm objects */
Packit Service c5cf8c
/* initialized in initthread.c */
Packit Service c5cf8c
MPIR_Comm MPIR_Comm_builtin[MPIR_COMM_N_BUILTIN] = { {0}
Packit Service c5cf8c
};
Packit Service c5cf8c
MPIR_Comm MPIR_Comm_direct[MPID_COMM_PREALLOC] = { {0}
Packit Service c5cf8c
};
Packit Service c5cf8c
Packit Service c5cf8c
MPIR_Object_alloc_t MPIR_Comm_mem = {
Packit Service c5cf8c
    0,
Packit Service c5cf8c
    0,
Packit Service c5cf8c
    0,
Packit Service c5cf8c
    0,
Packit Service c5cf8c
    MPIR_COMM,
Packit Service c5cf8c
    sizeof(MPIR_Comm),
Packit Service c5cf8c
    MPIR_Comm_direct,
Packit Service c5cf8c
    MPID_COMM_PREALLOC
Packit Service c5cf8c
};
Packit Service c5cf8c
Packit Service c5cf8c
/* Communicator creation functions */
Packit Service c5cf8c
struct MPIR_Commops *MPIR_Comm_fns = NULL;
Packit Service c5cf8c
struct MPIR_Comm_hint_fn_elt {
Packit Service c5cf8c
    char name[MPI_MAX_INFO_KEY];
Packit Service c5cf8c
    MPIR_Comm_hint_fn_t fn;
Packit Service c5cf8c
    void *state;
Packit Service c5cf8c
    UT_hash_handle hh;
Packit Service c5cf8c
};
Packit Service c5cf8c
static struct MPIR_Comm_hint_fn_elt *MPID_hint_fns = NULL;
Packit Service c5cf8c
Packit Service c5cf8c
/* FIXME :
Packit Service c5cf8c
   Reusing context ids can lead to a race condition if (as is desirable)
Packit Service c5cf8c
   MPI_Comm_free does not include a barrier.  Consider the following:
Packit Service c5cf8c
   Process A frees the communicator.
Packit Service c5cf8c
   Process A creates a new communicator, reusing the just released id
Packit Service c5cf8c
   Process B sends a message to A on the old communicator.
Packit Service c5cf8c
   Process A receives the message, and believes that it belongs to the
Packit Service c5cf8c
   new communicator.
Packit Service c5cf8c
   Process B then cancels the message, and frees the communicator.
Packit Service c5cf8c
Packit Service c5cf8c
   The likelihood of this happening can be reduced by introducing a gap
Packit Service c5cf8c
   between when a context id is released and when it is reused.  An alternative
Packit Service c5cf8c
   is to use an explicit message (in the implementation of MPI_Comm_free)
Packit Service c5cf8c
   to indicate that a communicator is being freed; this will often require
Packit Service c5cf8c
   less communication than a barrier in MPI_Comm_free, and will ensure that
Packit Service c5cf8c
   no messages are later sent to the same communicator (we may also want to
Packit Service c5cf8c
   have a similar check when building fault-tolerant versions of MPI).
Packit Service c5cf8c
 */
Packit Service c5cf8c
Packit Service c5cf8c
/* Zeroes most non-handle fields in a communicator, as well as initializing any
Packit Service c5cf8c
 * other special fields, such as a per-object mutex.  Also defaults the
Packit Service c5cf8c
 * reference count to 1, under the assumption that the caller holds a reference
Packit Service c5cf8c
 * to it.
Packit Service c5cf8c
 *
Packit Service c5cf8c
 * !!! The resulting struct is _not_ ready for communication !!! */
Packit Service c5cf8c
int MPII_Comm_init(MPIR_Comm * comm_p)
Packit Service c5cf8c
{
Packit Service c5cf8c
    int mpi_errno = MPI_SUCCESS;
Packit Service c5cf8c
Packit Service c5cf8c
    MPIR_Object_set_ref(comm_p, 1);
Packit Service c5cf8c
Packit Service c5cf8c
    /* initialize local and remote sizes to -1 to allow other parts of
Packit Service c5cf8c
     * the stack to detect errors more easily */
Packit Service c5cf8c
    comm_p->local_size = -1;
Packit Service c5cf8c
    comm_p->remote_size = -1;
Packit Service c5cf8c
Packit Service c5cf8c
    /* Clear many items (empty means to use the default; some of these
Packit Service c5cf8c
     * may be overridden within the upper-level communicator initialization) */
Packit Service c5cf8c
    comm_p->errhandler = NULL;
Packit Service c5cf8c
    comm_p->attributes = NULL;
Packit Service c5cf8c
    comm_p->remote_group = NULL;
Packit Service c5cf8c
    comm_p->local_group = NULL;
Packit Service c5cf8c
    comm_p->topo_fns = NULL;
Packit Service c5cf8c
    comm_p->name[0] = '\0';
Packit Service c5cf8c
    comm_p->info = NULL;
Packit Service c5cf8c
Packit Service c5cf8c
    comm_p->hierarchy_kind = MPIR_COMM_HIERARCHY_KIND__FLAT;
Packit Service c5cf8c
    comm_p->node_comm = NULL;
Packit Service c5cf8c
    comm_p->node_roots_comm = NULL;
Packit Service c5cf8c
    comm_p->intranode_table = NULL;
Packit Service c5cf8c
    comm_p->internode_table = NULL;
Packit Service c5cf8c
Packit Service c5cf8c
    /* abstractions bleed a bit here... :(*/
Packit Service c5cf8c
    comm_p->next_sched_tag = MPIR_FIRST_NBC_TAG;
Packit Service c5cf8c
Packit Service c5cf8c
    /* Initialize the revoked flag as false */
Packit Service c5cf8c
    comm_p->revoked = 0;
Packit Service c5cf8c
    comm_p->mapper_head = NULL;
Packit Service c5cf8c
    comm_p->mapper_tail = NULL;
Packit Service c5cf8c
Packit Service c5cf8c
#if MPICH_THREAD_GRANULARITY == MPICH_THREAD_GRANULARITY__POBJ
Packit Service c5cf8c
    {
Packit Service c5cf8c
        int thr_err;
Packit Service c5cf8c
        MPID_Thread_mutex_create(&MPIR_THREAD_POBJ_COMM_MUTEX(comm_p), &thr_err);
Packit Service c5cf8c
        MPIR_Assert(thr_err == 0);
Packit Service c5cf8c
    }
Packit Service c5cf8c
#endif
Packit Service c5cf8c
    /* Fields not set include context_id, remote and local size, and
Packit Service c5cf8c
     * kind, since different communicator construction routines need
Packit Service c5cf8c
     * different values */
Packit Service c5cf8c
    return mpi_errno;
Packit Service c5cf8c
}
Packit Service c5cf8c
Packit Service c5cf8c
Packit Service c5cf8c
/*
Packit Service c5cf8c
    Create a communicator structure and perform basic initialization
Packit Service c5cf8c
    (mostly clearing fields and updating the reference count).
Packit Service c5cf8c
 */
Packit Service c5cf8c
#undef FUNCNAME
Packit Service c5cf8c
#define FUNCNAME MPIR_Comm_create
Packit Service c5cf8c
#undef FCNAME
Packit Service c5cf8c
#define FCNAME "MPIR_Comm_create"
Packit Service c5cf8c
int MPIR_Comm_create(MPIR_Comm ** newcomm_ptr)
Packit Service c5cf8c
{
Packit Service c5cf8c
    int mpi_errno = MPI_SUCCESS;
Packit Service c5cf8c
    MPIR_Comm *newptr;
Packit Service c5cf8c
    MPIR_FUNC_TERSE_STATE_DECL(MPID_STATE_MPIR_COMM_CREATE);
Packit Service c5cf8c
Packit Service c5cf8c
    MPIR_FUNC_TERSE_ENTER(MPID_STATE_MPIR_COMM_CREATE);
Packit Service c5cf8c
Packit Service c5cf8c
    newptr = (MPIR_Comm *) MPIR_Handle_obj_alloc(&MPIR_Comm_mem);
Packit Service c5cf8c
    MPIR_ERR_CHKANDJUMP(!newptr, mpi_errno, MPI_ERR_OTHER, "**nomem");
Packit Service c5cf8c
Packit Service c5cf8c
    *newcomm_ptr = newptr;
Packit Service c5cf8c
Packit Service c5cf8c
    mpi_errno = MPII_Comm_init(newptr);
Packit Service c5cf8c
    if (mpi_errno)
Packit Service c5cf8c
        MPIR_ERR_POP(mpi_errno);
Packit Service c5cf8c
Packit Service c5cf8c
    /* Insert this new communicator into the list of known communicators.
Packit Service c5cf8c
     * Make this conditional on debugger support to match the test in
Packit Service c5cf8c
     * MPIR_Comm_release . */
Packit Service c5cf8c
    MPII_COMML_REMEMBER(newptr);
Packit Service c5cf8c
Packit Service c5cf8c
  fn_fail:
Packit Service c5cf8c
    MPIR_FUNC_TERSE_EXIT(MPID_STATE_MPIR_COMM_CREATE);
Packit Service c5cf8c
Packit Service c5cf8c
    return mpi_errno;
Packit Service c5cf8c
}
Packit Service c5cf8c
Packit Service c5cf8c
/* Create a local intra communicator from the local group of the
Packit Service c5cf8c
   specified intercomm. */
Packit Service c5cf8c
/* FIXME this is an alternative constructor that doesn't use MPIR_Comm_create! */
Packit Service c5cf8c
#undef FUNCNAME
Packit Service c5cf8c
#define FUNCNAME MPII_Setup_intercomm_localcomm
Packit Service c5cf8c
#undef FCNAME
Packit Service c5cf8c
#define FCNAME "MPII_Setup_intercomm_localcomm"
Packit Service c5cf8c
int MPII_Setup_intercomm_localcomm(MPIR_Comm * intercomm_ptr)
Packit Service c5cf8c
{
Packit Service c5cf8c
    MPIR_Comm *localcomm_ptr;
Packit Service c5cf8c
    int mpi_errno = MPI_SUCCESS;
Packit Service c5cf8c
    MPIR_FUNC_TERSE_STATE_DECL(MPID_STATE_MPIR_SETUP_INTERCOMM_LOCALCOMM);
Packit Service c5cf8c
Packit Service c5cf8c
    MPIR_FUNC_TERSE_ENTER(MPID_STATE_MPIR_SETUP_INTERCOMM_LOCALCOMM);
Packit Service c5cf8c
Packit Service c5cf8c
    localcomm_ptr = (MPIR_Comm *) MPIR_Handle_obj_alloc(&MPIR_Comm_mem);
Packit Service c5cf8c
    MPIR_ERR_CHKANDJUMP(!localcomm_ptr, mpi_errno, MPI_ERR_OTHER, "**nomem");
Packit Service c5cf8c
Packit Service c5cf8c
    /* get sensible default values for most fields (usually zeros) */
Packit Service c5cf8c
    mpi_errno = MPII_Comm_init(localcomm_ptr);
Packit Service c5cf8c
    if (mpi_errno)
Packit Service c5cf8c
        MPIR_ERR_POP(mpi_errno);
Packit Service c5cf8c
Packit Service c5cf8c
    /* use the parent intercomm's recv ctx as the basis for our ctx */
Packit Service c5cf8c
    localcomm_ptr->recvcontext_id =
Packit Service c5cf8c
        MPIR_CONTEXT_SET_FIELD(IS_LOCALCOMM, intercomm_ptr->recvcontext_id, 1);
Packit Service c5cf8c
    localcomm_ptr->context_id = localcomm_ptr->recvcontext_id;
Packit Service c5cf8c
Packit Service c5cf8c
    MPL_DBG_MSG_FMT(MPIR_DBG_COMM, TYPICAL,
Packit Service c5cf8c
                    (MPL_DBG_FDEST,
Packit Service c5cf8c
                     "setup_intercomm_localcomm ic=%p ic->context_id=%d ic->recvcontext_id=%d lc->recvcontext_id=%d",
Packit Service c5cf8c
                     intercomm_ptr, intercomm_ptr->context_id, intercomm_ptr->recvcontext_id,
Packit Service c5cf8c
                     localcomm_ptr->recvcontext_id));
Packit Service c5cf8c
Packit Service c5cf8c
    /* Save the kind of the communicator */
Packit Service c5cf8c
    localcomm_ptr->comm_kind = MPIR_COMM_KIND__INTRACOMM;
Packit Service c5cf8c
Packit Service c5cf8c
    /* Set the sizes and ranks */
Packit Service c5cf8c
    localcomm_ptr->remote_size = intercomm_ptr->local_size;
Packit Service c5cf8c
    localcomm_ptr->local_size = intercomm_ptr->local_size;
Packit Service c5cf8c
    localcomm_ptr->pof2 = intercomm_ptr->pof2;
Packit Service c5cf8c
    localcomm_ptr->rank = intercomm_ptr->rank;
Packit Service c5cf8c
Packit Service c5cf8c
    MPIR_Comm_map_dup(localcomm_ptr, intercomm_ptr, MPIR_COMM_MAP_DIR__L2L);
Packit Service c5cf8c
Packit Service c5cf8c
    /* TODO More advanced version: if the group is available, dup it by
Packit Service c5cf8c
     * increasing the reference count instead of recreating it later */
Packit Service c5cf8c
    /* FIXME  : No local functions for the topology routines */
Packit Service c5cf8c
Packit Service c5cf8c
    intercomm_ptr->local_comm = localcomm_ptr;
Packit Service c5cf8c
Packit Service c5cf8c
    /* sets up the SMP-aware sub-communicators and tables */
Packit Service c5cf8c
    mpi_errno = MPIR_Comm_commit(localcomm_ptr);
Packit Service c5cf8c
    if (mpi_errno)
Packit Service c5cf8c
        MPIR_ERR_POP(mpi_errno);
Packit Service c5cf8c
Packit Service c5cf8c
  fn_fail:
Packit Service c5cf8c
    MPIR_FUNC_TERSE_EXIT(MPID_STATE_MPIR_SETUP_INTERCOMM_LOCALCOMM);
Packit Service c5cf8c
Packit Service c5cf8c
    return mpi_errno;
Packit Service c5cf8c
}
Packit Service c5cf8c
Packit Service c5cf8c
#undef FUNCNAME
Packit Service c5cf8c
#define FUNCNAME MPIR_Comm_map_irregular
Packit Service c5cf8c
#undef FCNAME
Packit Service c5cf8c
#define FCNAME MPL_QUOTE(FUNCNAME)
Packit Service c5cf8c
int MPIR_Comm_map_irregular(MPIR_Comm * newcomm, MPIR_Comm * src_comm,
Packit Service c5cf8c
                            int *src_mapping, int src_mapping_size,
Packit Service c5cf8c
                            MPIR_Comm_map_dir_t dir, MPIR_Comm_map_t ** map)
Packit Service c5cf8c
{
Packit Service c5cf8c
    int mpi_errno = MPI_SUCCESS;
Packit Service c5cf8c
    MPIR_Comm_map_t *mapper;
Packit Service c5cf8c
    MPIR_CHKPMEM_DECL(3);
Packit Service c5cf8c
    MPIR_FUNC_TERSE_STATE_DECL(MPID_STATE_MPIR_COMM_MAP_TYPE__IRREGULAR);
Packit Service c5cf8c
Packit Service c5cf8c
    MPIR_FUNC_TERSE_ENTER(MPID_STATE_MPIR_COMM_MAP_TYPE__IRREGULAR);
Packit Service c5cf8c
Packit Service c5cf8c
    MPIR_CHKPMEM_MALLOC(mapper, MPIR_Comm_map_t *, sizeof(MPIR_Comm_map_t), mpi_errno, "mapper",
Packit Service c5cf8c
                        MPL_MEM_COMM);
Packit Service c5cf8c
Packit Service c5cf8c
    mapper->type = MPIR_COMM_MAP_TYPE__IRREGULAR;
Packit Service c5cf8c
    mapper->src_comm = src_comm;
Packit Service c5cf8c
    mapper->dir = dir;
Packit Service c5cf8c
    mapper->src_mapping_size = src_mapping_size;
Packit Service c5cf8c
Packit Service c5cf8c
    if (src_mapping) {
Packit Service c5cf8c
        mapper->src_mapping = src_mapping;
Packit Service c5cf8c
        mapper->free_mapping = 0;
Packit Service c5cf8c
    } else {
Packit Service c5cf8c
        MPIR_CHKPMEM_MALLOC(mapper->src_mapping, int *,
Packit Service c5cf8c
                            src_mapping_size * sizeof(int), mpi_errno, "mapper mapping",
Packit Service c5cf8c
                            MPL_MEM_COMM);
Packit Service c5cf8c
        mapper->free_mapping = 1;
Packit Service c5cf8c
    }
Packit Service c5cf8c
Packit Service c5cf8c
    mapper->next = NULL;
Packit Service c5cf8c
Packit Service c5cf8c
    LL_APPEND(newcomm->mapper_head, newcomm->mapper_tail, mapper);
Packit Service c5cf8c
Packit Service c5cf8c
    if (map)
Packit Service c5cf8c
        *map = mapper;
Packit Service c5cf8c
Packit Service c5cf8c
  fn_exit:
Packit Service c5cf8c
    MPIR_CHKPMEM_COMMIT();
Packit Service c5cf8c
    MPIR_FUNC_TERSE_EXIT(MPID_STATE_MPIR_COMM_MAP_TYPE__IRREGULAR);
Packit Service c5cf8c
    return mpi_errno;
Packit Service c5cf8c
  fn_fail:
Packit Service c5cf8c
    MPIR_CHKPMEM_REAP();
Packit Service c5cf8c
    goto fn_exit;
Packit Service c5cf8c
}
Packit Service c5cf8c
Packit Service c5cf8c
#undef FUNCNAME
Packit Service c5cf8c
#define FUNCNAME MPIR_Comm_map_dup
Packit Service c5cf8c
#undef FCNAME
Packit Service c5cf8c
#define FCNAME MPL_QUOTE(FUNCNAME)
Packit Service c5cf8c
int MPIR_Comm_map_dup(MPIR_Comm * newcomm, MPIR_Comm * src_comm, MPIR_Comm_map_dir_t dir)
Packit Service c5cf8c
{
Packit Service c5cf8c
    int mpi_errno = MPI_SUCCESS;
Packit Service c5cf8c
    MPIR_Comm_map_t *mapper;
Packit Service c5cf8c
    MPIR_CHKPMEM_DECL(1);
Packit Service c5cf8c
    MPIR_FUNC_TERSE_STATE_DECL(MPID_STATE_MPIR_COMM_MAP_TYPE__DUP);
Packit Service c5cf8c
Packit Service c5cf8c
    MPIR_FUNC_TERSE_ENTER(MPID_STATE_MPIR_COMM_MAP_TYPE__DUP);
Packit Service c5cf8c
Packit Service c5cf8c
    MPIR_CHKPMEM_MALLOC(mapper, MPIR_Comm_map_t *, sizeof(MPIR_Comm_map_t), mpi_errno, "mapper",
Packit Service c5cf8c
                        MPL_MEM_COMM);
Packit Service c5cf8c
Packit Service c5cf8c
    mapper->type = MPIR_COMM_MAP_TYPE__DUP;
Packit Service c5cf8c
    mapper->src_comm = src_comm;
Packit Service c5cf8c
    mapper->dir = dir;
Packit Service c5cf8c
Packit Service c5cf8c
    mapper->next = NULL;
Packit Service c5cf8c
Packit Service c5cf8c
    LL_APPEND(newcomm->mapper_head, newcomm->mapper_tail, mapper);
Packit Service c5cf8c
Packit Service c5cf8c
  fn_exit:
Packit Service c5cf8c
    MPIR_CHKPMEM_COMMIT();
Packit Service c5cf8c
    MPIR_FUNC_TERSE_EXIT(MPID_STATE_MPIR_COMM_MAP_TYPE__DUP);
Packit Service c5cf8c
    return mpi_errno;
Packit Service c5cf8c
  fn_fail:
Packit Service c5cf8c
    MPIR_CHKPMEM_REAP();
Packit Service c5cf8c
    goto fn_exit;
Packit Service c5cf8c
}
Packit Service c5cf8c
Packit Service c5cf8c
Packit Service c5cf8c
#undef FUNCNAME
Packit Service c5cf8c
#define FUNCNAME MPIR_Comm_map_free
Packit Service c5cf8c
#undef FCNAME
Packit Service c5cf8c
#define FCNAME MPL_QUOTE(FUNCNAME)
Packit Service c5cf8c
int MPIR_Comm_map_free(MPIR_Comm * comm)
Packit Service c5cf8c
{
Packit Service c5cf8c
    int mpi_errno = MPI_SUCCESS;
Packit Service c5cf8c
    MPIR_Comm_map_t *mapper, *tmp;
Packit Service c5cf8c
    MPIR_FUNC_TERSE_STATE_DECL(MPID_STATE_MPIR_COMM_MAP_FREE);
Packit Service c5cf8c
Packit Service c5cf8c
    MPIR_FUNC_TERSE_ENTER(MPID_STATE_MPIR_COMM_MAP_FREE);
Packit Service c5cf8c
Packit Service c5cf8c
    for (mapper = comm->mapper_head; mapper;) {
Packit Service c5cf8c
        tmp = mapper->next;
Packit Service c5cf8c
        if (mapper->type == MPIR_COMM_MAP_TYPE__IRREGULAR && mapper->free_mapping)
Packit Service c5cf8c
            MPL_free(mapper->src_mapping);
Packit Service c5cf8c
        MPL_free(mapper);
Packit Service c5cf8c
        mapper = tmp;
Packit Service c5cf8c
    }
Packit Service c5cf8c
    comm->mapper_head = NULL;
Packit Service c5cf8c
Packit Service c5cf8c
    MPIR_FUNC_TERSE_EXIT(MPID_STATE_MPIR_COMM_MAP_FREE);
Packit Service c5cf8c
    return mpi_errno;
Packit Service c5cf8c
}
Packit Service c5cf8c
Packit Service c5cf8c
/* Provides a hook for the top level functions to perform some manipulation on a
Packit Service c5cf8c
   communicator just before it is given to the application level.
Packit Service c5cf8c
Packit Service c5cf8c
   For example, we create sub-communicators for SMP-aware collectives at this
Packit Service c5cf8c
   step. */
Packit Service c5cf8c
#undef FUNCNAME
Packit Service c5cf8c
#define FUNCNAME MPIR_Comm_commit
Packit Service c5cf8c
#undef FCNAME
Packit Service c5cf8c
#define FCNAME MPL_QUOTE(FUNCNAME)
Packit Service c5cf8c
int MPIR_Comm_commit(MPIR_Comm * comm)
Packit Service c5cf8c
{
Packit Service c5cf8c
    int mpi_errno = MPI_SUCCESS;
Packit Service c5cf8c
    int num_local = -1, num_external = -1;
Packit Service c5cf8c
    int local_rank = -1, external_rank = -1;
Packit Service c5cf8c
    int *local_procs = NULL, *external_procs = NULL;
Packit Service c5cf8c
    MPIR_FUNC_TERSE_STATE_DECL(MPID_STATE_MPIR_COMM_COMMIT);
Packit Service c5cf8c
Packit Service c5cf8c
    MPIR_FUNC_TERSE_ENTER(MPID_STATE_MPIR_COMM_COMMIT);
Packit Service c5cf8c
Packit Service c5cf8c
    /* It's OK to relax these assertions, but we should do so very
Packit Service c5cf8c
     * intentionally.  For now this function is the only place that we create
Packit Service c5cf8c
     * our hierarchy of communicators */
Packit Service c5cf8c
    MPIR_Assert(comm->node_comm == NULL);
Packit Service c5cf8c
    MPIR_Assert(comm->node_roots_comm == NULL);
Packit Service c5cf8c
Packit Service c5cf8c
    /* Notify device of communicator creation */
Packit Service c5cf8c
    if (comm != MPIR_Process.comm_world) {
Packit Service c5cf8c
        mpi_errno = MPID_Comm_create_hook(comm);
Packit Service c5cf8c
        if (mpi_errno)
Packit Service c5cf8c
            MPIR_ERR_POP(mpi_errno);
Packit Service c5cf8c
Packit Service c5cf8c
        MPIR_Comm_map_free(comm);
Packit Service c5cf8c
    }
Packit Service c5cf8c
Packit Service c5cf8c
    /* Create collectives-specific infrastructure */
Packit Service c5cf8c
    mpi_errno = MPIR_Coll_comm_init(comm);
Packit Service c5cf8c
    if (mpi_errno)
Packit Service c5cf8c
        MPIR_ERR_POP(mpi_errno);
Packit Service c5cf8c
Packit Service c5cf8c
    MPIR_Comm_map_free(comm);
Packit Service c5cf8c
Packit Service c5cf8c
    comm->pof2 = MPL_pof2(comm->local_size);
Packit Service c5cf8c
Packit Service c5cf8c
    if (comm->comm_kind == MPIR_COMM_KIND__INTRACOMM && !MPIR_CONTEXT_READ_FIELD(SUBCOMM, comm->context_id)) {  /*make sure this is not a subcomm */
Packit Service c5cf8c
Packit Service c5cf8c
        mpi_errno = MPIR_Find_local_and_external(comm,
Packit Service c5cf8c
                                                 &num_local, &local_rank, &local_procs,
Packit Service c5cf8c
                                                 &num_external, &external_rank, &external_procs,
Packit Service c5cf8c
                                                 &comm->intranode_table, &comm->internode_table);
Packit Service c5cf8c
        /* --BEGIN ERROR HANDLING-- */
Packit Service c5cf8c
        if (mpi_errno) {
Packit Service c5cf8c
            if (MPIR_Err_is_fatal(mpi_errno))
Packit Service c5cf8c
                MPIR_ERR_POP(mpi_errno);
Packit Service c5cf8c
Packit Service c5cf8c
            /* Non-fatal errors simply mean that this communicator will not have
Packit Service c5cf8c
             * any node awareness.  Node-aware collectives are an optimization. */
Packit Service c5cf8c
            MPL_DBG_MSG_P(MPIR_DBG_COMM, VERBOSE,
Packit Service c5cf8c
                          "MPIR_Find_local_and_external failed for comm_ptr=%p", comm);
Packit Service c5cf8c
            if (comm->intranode_table)
Packit Service c5cf8c
                MPL_free(comm->intranode_table);
Packit Service c5cf8c
            if (comm->internode_table)
Packit Service c5cf8c
                MPL_free(comm->internode_table);
Packit Service c5cf8c
Packit Service c5cf8c
            mpi_errno = MPI_SUCCESS;
Packit Service c5cf8c
            goto fn_exit;
Packit Service c5cf8c
        }
Packit Service c5cf8c
        /* --END ERROR HANDLING-- */
Packit Service c5cf8c
Packit Service c5cf8c
        /* defensive checks */
Packit Service c5cf8c
        MPIR_Assert(num_local > 0);
Packit Service c5cf8c
        MPIR_Assert(num_local > 1 || external_rank >= 0);
Packit Service c5cf8c
        MPIR_Assert(external_rank < 0 || external_procs != NULL);
Packit Service c5cf8c
Packit Service c5cf8c
        /* if the node_roots_comm and comm would be the same size, then creating
Packit Service c5cf8c
         * the second communicator is useless and wasteful. */
Packit Service c5cf8c
        if (num_external == comm->remote_size) {
Packit Service c5cf8c
            MPIR_Assert(num_local == 1);
Packit Service c5cf8c
            goto fn_exit;
Packit Service c5cf8c
        }
Packit Service c5cf8c
Packit Service c5cf8c
        /* we don't need a local comm if this process is the only one on this node */
Packit Service c5cf8c
        if (num_local > 1) {
Packit Service c5cf8c
            mpi_errno = MPIR_Comm_create(&comm->node_comm);
Packit Service c5cf8c
            if (mpi_errno)
Packit Service c5cf8c
                MPIR_ERR_POP(mpi_errno);
Packit Service c5cf8c
Packit Service c5cf8c
            comm->node_comm->context_id = comm->context_id + MPIR_CONTEXT_INTRANODE_OFFSET;
Packit Service c5cf8c
            comm->node_comm->recvcontext_id = comm->node_comm->context_id;
Packit Service c5cf8c
            comm->node_comm->rank = local_rank;
Packit Service c5cf8c
            comm->node_comm->comm_kind = MPIR_COMM_KIND__INTRACOMM;
Packit Service c5cf8c
            comm->node_comm->hierarchy_kind = MPIR_COMM_HIERARCHY_KIND__NODE;
Packit Service c5cf8c
            comm->node_comm->local_comm = NULL;
Packit Service c5cf8c
            MPL_DBG_MSG_D(MPIR_DBG_COMM, VERBOSE, "Create node_comm=%p\n", comm->node_comm);
Packit Service c5cf8c
Packit Service c5cf8c
            comm->node_comm->local_size = num_local;
Packit Service c5cf8c
            comm->node_comm->pof2 = MPL_pof2(comm->node_comm->local_size);
Packit Service c5cf8c
            comm->node_comm->remote_size = num_local;
Packit Service c5cf8c
Packit Service c5cf8c
            MPIR_Comm_map_irregular(comm->node_comm, comm, local_procs,
Packit Service c5cf8c
                                    num_local, MPIR_COMM_MAP_DIR__L2L, NULL);
Packit Service c5cf8c
Packit Service c5cf8c
            /* Notify device of communicator creation */
Packit Service c5cf8c
            mpi_errno = MPID_Comm_create_hook(comm->node_comm);
Packit Service c5cf8c
            if (mpi_errno)
Packit Service c5cf8c
                MPIR_ERR_POP(mpi_errno);
Packit Service c5cf8c
            /* don't call MPIR_Comm_commit here */
Packit Service c5cf8c
Packit Service c5cf8c
            /* Create collectives-specific infrastructure */
Packit Service c5cf8c
            mpi_errno = MPIR_Coll_comm_init(comm->node_comm);
Packit Service c5cf8c
            if (mpi_errno)
Packit Service c5cf8c
                MPIR_ERR_POP(mpi_errno);
Packit Service c5cf8c
Packit Service c5cf8c
            MPIR_Comm_map_free(comm->node_comm);
Packit Service c5cf8c
        }
Packit Service c5cf8c
Packit Service c5cf8c
Packit Service c5cf8c
        /* this process may not be a member of the node_roots_comm */
Packit Service c5cf8c
        if (local_rank == 0) {
Packit Service c5cf8c
            mpi_errno = MPIR_Comm_create(&comm->node_roots_comm);
Packit Service c5cf8c
            if (mpi_errno)
Packit Service c5cf8c
                MPIR_ERR_POP(mpi_errno);
Packit Service c5cf8c
Packit Service c5cf8c
            comm->node_roots_comm->context_id = comm->context_id + MPIR_CONTEXT_INTERNODE_OFFSET;
Packit Service c5cf8c
            comm->node_roots_comm->recvcontext_id = comm->node_roots_comm->context_id;
Packit Service c5cf8c
            comm->node_roots_comm->rank = external_rank;
Packit Service c5cf8c
            comm->node_roots_comm->comm_kind = MPIR_COMM_KIND__INTRACOMM;
Packit Service c5cf8c
            comm->node_roots_comm->hierarchy_kind = MPIR_COMM_HIERARCHY_KIND__NODE_ROOTS;
Packit Service c5cf8c
            comm->node_roots_comm->local_comm = NULL;
Packit Service c5cf8c
            MPL_DBG_MSG_D(MPIR_DBG_COMM, VERBOSE, "Create node_roots_comm=%p\n",
Packit Service c5cf8c
                          comm->node_roots_comm);
Packit Service c5cf8c
Packit Service c5cf8c
            comm->node_roots_comm->local_size = num_external;
Packit Service c5cf8c
            comm->node_roots_comm->pof2 = MPL_pof2(comm->node_roots_comm->local_size);
Packit Service c5cf8c
            comm->node_roots_comm->remote_size = num_external;
Packit Service c5cf8c
Packit Service c5cf8c
            MPIR_Comm_map_irregular(comm->node_roots_comm, comm,
Packit Service c5cf8c
                                    external_procs, num_external, MPIR_COMM_MAP_DIR__L2L, NULL);
Packit Service c5cf8c
Packit Service c5cf8c
            /* Notify device of communicator creation */
Packit Service c5cf8c
            mpi_errno = MPID_Comm_create_hook(comm->node_roots_comm);
Packit Service c5cf8c
            if (mpi_errno)
Packit Service c5cf8c
                MPIR_ERR_POP(mpi_errno);
Packit Service c5cf8c
            /* don't call MPIR_Comm_commit here */
Packit Service c5cf8c
Packit Service c5cf8c
            /* Create collectives-specific infrastructure */
Packit Service c5cf8c
            mpi_errno = MPIR_Coll_comm_init(comm->node_roots_comm);
Packit Service c5cf8c
            if (mpi_errno)
Packit Service c5cf8c
                MPIR_ERR_POP(mpi_errno);
Packit Service c5cf8c
Packit Service c5cf8c
            MPIR_Comm_map_free(comm->node_roots_comm);
Packit Service c5cf8c
        }
Packit Service c5cf8c
Packit Service c5cf8c
        comm->hierarchy_kind = MPIR_COMM_HIERARCHY_KIND__PARENT;
Packit Service c5cf8c
    }
Packit Service c5cf8c
Packit Service c5cf8c
  fn_exit:
Packit Service c5cf8c
    if (comm == MPIR_Process.comm_world) {
Packit Service c5cf8c
        mpi_errno = MPID_Comm_create_hook(comm);
Packit Service c5cf8c
        if (mpi_errno)
Packit Service c5cf8c
            MPIR_ERR_POP(mpi_errno);
Packit Service c5cf8c
Packit Service c5cf8c
        MPIR_Comm_map_free(comm);
Packit Service c5cf8c
    }
Packit Service c5cf8c
Packit Service c5cf8c
    if (external_procs != NULL)
Packit Service c5cf8c
        MPL_free(external_procs);
Packit Service c5cf8c
    if (local_procs != NULL)
Packit Service c5cf8c
        MPL_free(local_procs);
Packit Service c5cf8c
Packit Service c5cf8c
    MPIR_FUNC_TERSE_EXIT(MPID_STATE_MPIR_COMM_COMMIT);
Packit Service c5cf8c
    return mpi_errno;
Packit Service c5cf8c
  fn_fail:
Packit Service c5cf8c
    goto fn_exit;
Packit Service c5cf8c
}
Packit Service c5cf8c
Packit Service c5cf8c
/* Returns true if the given communicator is aware of node topology information,
Packit Service c5cf8c
   false otherwise.  Such information could be used to implement more efficient
Packit Service c5cf8c
   collective communication, for example. */
Packit Service c5cf8c
int MPIR_Comm_is_node_aware(MPIR_Comm * comm)
Packit Service c5cf8c
{
Packit Service c5cf8c
    return (comm->hierarchy_kind == MPIR_COMM_HIERARCHY_KIND__PARENT);
Packit Service c5cf8c
}
Packit Service c5cf8c
Packit Service c5cf8c
/* Returns true if the communicator is node-aware and processes in all the nodes
Packit Service c5cf8c
   are consecutive. For example, if node 0 contains "0, 1, 2, 3", node 1
Packit Service c5cf8c
   contains "4, 5, 6", and node 2 contains "7", we shall return true. */
Packit Service c5cf8c
int MPII_Comm_is_node_consecutive(MPIR_Comm * comm)
Packit Service c5cf8c
{
Packit Service c5cf8c
    int i = 0, curr_nodeidx = 0;
Packit Service c5cf8c
    int *internode_table = comm->internode_table;
Packit Service c5cf8c
Packit Service c5cf8c
    if (!MPIR_Comm_is_node_aware(comm))
Packit Service c5cf8c
        return 0;
Packit Service c5cf8c
Packit Service c5cf8c
    for (; i < comm->local_size; i++) {
Packit Service c5cf8c
        if (internode_table[i] == curr_nodeidx + 1)
Packit Service c5cf8c
            curr_nodeidx++;
Packit Service c5cf8c
        else if (internode_table[i] != curr_nodeidx)
Packit Service c5cf8c
            return 0;
Packit Service c5cf8c
    }
Packit Service c5cf8c
Packit Service c5cf8c
    return 1;
Packit Service c5cf8c
}
Packit Service c5cf8c
Packit Service c5cf8c
/*
Packit Service c5cf8c
 * Copy a communicator, including creating a new context and copying the
Packit Service c5cf8c
 * virtual connection tables and clearing the various fields.
Packit Service c5cf8c
 * Does *not* copy attributes.  If size is < the size of the local group
Packit Service c5cf8c
 * in the input communicator, copy only the first size elements.
Packit Service c5cf8c
 * If this process is not a member, return a null pointer in outcomm_ptr.
Packit Service c5cf8c
 * This is only supported in the case where the communicator is in
Packit Service c5cf8c
 * Intracomm (not an Intercomm).  Note that this is all that is required
Packit Service c5cf8c
 * for cart_create and graph_create.
Packit Service c5cf8c
 *
Packit Service c5cf8c
 * Used by cart_create, graph_create, and dup_create
Packit Service c5cf8c
 */
Packit Service c5cf8c
#undef FUNCNAME
Packit Service c5cf8c
#define FUNCNAME MPII_Comm_copy
Packit Service c5cf8c
#undef FCNAME
Packit Service c5cf8c
#define FCNAME "MPII_Comm_copy"
Packit Service c5cf8c
int MPII_Comm_copy(MPIR_Comm * comm_ptr, int size, MPIR_Comm ** outcomm_ptr)
Packit Service c5cf8c
{
Packit Service c5cf8c
    int mpi_errno = MPI_SUCCESS;
Packit Service c5cf8c
    MPIR_Context_id_t new_context_id, new_recvcontext_id;
Packit Service c5cf8c
    MPIR_Comm *newcomm_ptr = NULL;
Packit Service c5cf8c
    MPIR_Comm_map_t *map = NULL;
Packit Service c5cf8c
    MPIR_FUNC_TERSE_STATE_DECL(MPID_STATE_MPIR_COMM_COPY);
Packit Service c5cf8c
Packit Service c5cf8c
    MPIR_FUNC_TERSE_ENTER(MPID_STATE_MPIR_COMM_COPY);
Packit Service c5cf8c
Packit Service c5cf8c
    /* Get a new context first.  We need this to be collective over the
Packit Service c5cf8c
     * input communicator */
Packit Service c5cf8c
    /* If there is a context id cache in oldcomm, use it here.  Otherwise,
Packit Service c5cf8c
     * use the appropriate algorithm to get a new context id.  Be careful
Packit Service c5cf8c
     * of intercomms here */
Packit Service c5cf8c
    if (comm_ptr->comm_kind == MPIR_COMM_KIND__INTERCOMM) {
Packit Service c5cf8c
        mpi_errno = MPIR_Get_intercomm_contextid(comm_ptr, &new_context_id, &new_recvcontext_id);
Packit Service c5cf8c
        if (mpi_errno)
Packit Service c5cf8c
            MPIR_ERR_POP(mpi_errno);
Packit Service c5cf8c
    } else {
Packit Service c5cf8c
        mpi_errno = MPIR_Get_contextid_sparse(comm_ptr, &new_context_id, FALSE);
Packit Service c5cf8c
        new_recvcontext_id = new_context_id;
Packit Service c5cf8c
        if (mpi_errno)
Packit Service c5cf8c
            MPIR_ERR_POP(mpi_errno);
Packit Service c5cf8c
        MPIR_Assert(new_context_id != 0);
Packit Service c5cf8c
    }
Packit Service c5cf8c
Packit Service c5cf8c
    /* This is the local size, not the remote size, in the case of
Packit Service c5cf8c
     * an intercomm */
Packit Service c5cf8c
    if (comm_ptr->rank >= size) {
Packit Service c5cf8c
        *outcomm_ptr = 0;
Packit Service c5cf8c
        /* always free the recvcontext ID, never the "send" ID */
Packit Service c5cf8c
        MPIR_Free_contextid(new_recvcontext_id);
Packit Service c5cf8c
        goto fn_exit;
Packit Service c5cf8c
    }
Packit Service c5cf8c
Packit Service c5cf8c
    /* We're left with the processes that will have a non-null communicator.
Packit Service c5cf8c
     * Create the object, initialize the data, and return the result */
Packit Service c5cf8c
Packit Service c5cf8c
    mpi_errno = MPIR_Comm_create(&newcomm_ptr);
Packit Service c5cf8c
    if (mpi_errno)
Packit Service c5cf8c
        goto fn_fail;
Packit Service c5cf8c
Packit Service c5cf8c
    newcomm_ptr->context_id = new_context_id;
Packit Service c5cf8c
    newcomm_ptr->recvcontext_id = new_recvcontext_id;
Packit Service c5cf8c
Packit Service c5cf8c
    /* Save the kind of the communicator */
Packit Service c5cf8c
    newcomm_ptr->comm_kind = comm_ptr->comm_kind;
Packit Service c5cf8c
    newcomm_ptr->local_comm = 0;
Packit Service c5cf8c
Packit Service c5cf8c
    /* There are two cases here - size is the same as the old communicator,
Packit Service c5cf8c
     * or it is smaller.  If the size is the same, we can just add a reference.
Packit Service c5cf8c
     * Otherwise, we need to create a new network address mapping.  Note that this is the
Packit Service c5cf8c
     * test that matches the test on rank above. */
Packit Service c5cf8c
    if (size == comm_ptr->local_size) {
Packit Service c5cf8c
        /* Duplicate the network address mapping */
Packit Service c5cf8c
        if (comm_ptr->comm_kind == MPIR_COMM_KIND__INTRACOMM)
Packit Service c5cf8c
            MPIR_Comm_map_dup(newcomm_ptr, comm_ptr, MPIR_COMM_MAP_DIR__L2L);
Packit Service c5cf8c
        else
Packit Service c5cf8c
            MPIR_Comm_map_dup(newcomm_ptr, comm_ptr, MPIR_COMM_MAP_DIR__R2R);
Packit Service c5cf8c
    } else {
Packit Service c5cf8c
        int i;
Packit Service c5cf8c
Packit Service c5cf8c
        if (comm_ptr->comm_kind == MPIR_COMM_KIND__INTRACOMM)
Packit Service c5cf8c
            MPIR_Comm_map_irregular(newcomm_ptr, comm_ptr, NULL, size, MPIR_COMM_MAP_DIR__L2L,
Packit Service c5cf8c
                                    &map);
Packit Service c5cf8c
        else
Packit Service c5cf8c
            MPIR_Comm_map_irregular(newcomm_ptr, comm_ptr, NULL, size, MPIR_COMM_MAP_DIR__R2R,
Packit Service c5cf8c
                                    &map);
Packit Service c5cf8c
        for (i = 0; i < size; i++) {
Packit Service c5cf8c
            /* For rank i in the new communicator, find the corresponding
Packit Service c5cf8c
             * rank in the input communicator */
Packit Service c5cf8c
            map->src_mapping[i] = i;
Packit Service c5cf8c
        }
Packit Service c5cf8c
    }
Packit Service c5cf8c
Packit Service c5cf8c
    /* If it is an intercomm, duplicate the local network address references */
Packit Service c5cf8c
    if (comm_ptr->comm_kind == MPIR_COMM_KIND__INTERCOMM) {
Packit Service c5cf8c
        MPIR_Comm_map_dup(newcomm_ptr, comm_ptr, MPIR_COMM_MAP_DIR__L2L);
Packit Service c5cf8c
    }
Packit Service c5cf8c
Packit Service c5cf8c
    /* Set the sizes and ranks */
Packit Service c5cf8c
    newcomm_ptr->rank = comm_ptr->rank;
Packit Service c5cf8c
    if (comm_ptr->comm_kind == MPIR_COMM_KIND__INTERCOMM) {
Packit Service c5cf8c
        newcomm_ptr->local_size = comm_ptr->local_size;
Packit Service c5cf8c
        newcomm_ptr->remote_size = comm_ptr->remote_size;
Packit Service c5cf8c
        newcomm_ptr->is_low_group = comm_ptr->is_low_group;
Packit Service c5cf8c
    } else {
Packit Service c5cf8c
        newcomm_ptr->local_size = size;
Packit Service c5cf8c
        newcomm_ptr->remote_size = size;
Packit Service c5cf8c
    }
Packit Service c5cf8c
    newcomm_ptr->pof2 = MPL_pof2(newcomm_ptr->local_size);
Packit Service c5cf8c
Packit Service c5cf8c
    /* Inherit the error handler (if any) */
Packit Service c5cf8c
    MPID_THREAD_CS_ENTER(POBJ, MPIR_THREAD_POBJ_COMM_MUTEX(comm_ptr));
Packit Service c5cf8c
    newcomm_ptr->errhandler = comm_ptr->errhandler;
Packit Service c5cf8c
    if (comm_ptr->errhandler) {
Packit Service c5cf8c
        MPIR_Errhandler_add_ref(comm_ptr->errhandler);
Packit Service c5cf8c
    }
Packit Service c5cf8c
    MPID_THREAD_CS_EXIT(POBJ, MPIR_THREAD_POBJ_COMM_MUTEX(comm_ptr));
Packit Service c5cf8c
Packit Service c5cf8c
    mpi_errno = MPIR_Comm_commit(newcomm_ptr);
Packit Service c5cf8c
    if (mpi_errno)
Packit Service c5cf8c
        MPIR_ERR_POP(mpi_errno);
Packit Service c5cf8c
Packit Service c5cf8c
    /* Start with no attributes on this communicator */
Packit Service c5cf8c
    newcomm_ptr->attributes = 0;
Packit Service c5cf8c
Packit Service c5cf8c
    /* Copy over the info hints from the original communicator. */
Packit Service c5cf8c
    mpi_errno = MPIR_Info_dup_impl(comm_ptr->info, &(newcomm_ptr->info));
Packit Service c5cf8c
    if (mpi_errno)
Packit Service c5cf8c
        MPIR_ERR_POP(mpi_errno);
Packit Service c5cf8c
    mpi_errno = MPII_Comm_apply_hints(newcomm_ptr, newcomm_ptr->info);
Packit Service c5cf8c
    if (mpi_errno)
Packit Service c5cf8c
        MPIR_ERR_POP(mpi_errno);
Packit Service c5cf8c
Packit Service c5cf8c
    *outcomm_ptr = newcomm_ptr;
Packit Service c5cf8c
Packit Service c5cf8c
  fn_fail:
Packit Service c5cf8c
  fn_exit:
Packit Service c5cf8c
Packit Service c5cf8c
    MPIR_FUNC_TERSE_EXIT(MPID_STATE_MPIR_COMM_COPY);
Packit Service c5cf8c
Packit Service c5cf8c
    return mpi_errno;
Packit Service c5cf8c
}
Packit Service c5cf8c
Packit Service c5cf8c
/* Copy a communicator, including copying the virtual connection tables and
Packit Service c5cf8c
 * clearing the various fields.  Does *not* allocate a context ID or commit the
Packit Service c5cf8c
 * communicator.  Does *not* copy attributes.
Packit Service c5cf8c
 *
Packit Service c5cf8c
 * Used by comm_idup.
Packit Service c5cf8c
 */
Packit Service c5cf8c
#undef FUNCNAME
Packit Service c5cf8c
#define FUNCNAME MPII_Comm_copy_data
Packit Service c5cf8c
#undef FCNAME
Packit Service c5cf8c
#define FCNAME MPL_QUOTE(FUNCNAME)
Packit Service c5cf8c
int MPII_Comm_copy_data(MPIR_Comm * comm_ptr, MPIR_Comm ** outcomm_ptr)
Packit Service c5cf8c
{
Packit Service c5cf8c
    int mpi_errno = MPI_SUCCESS;
Packit Service c5cf8c
    MPIR_Comm *newcomm_ptr = NULL;
Packit Service c5cf8c
    MPIR_FUNC_TERSE_STATE_DECL(MPID_STATE_MPIR_COMM_COPY_DATA);
Packit Service c5cf8c
Packit Service c5cf8c
    MPIR_FUNC_TERSE_ENTER(MPID_STATE_MPIR_COMM_COPY_DATA);
Packit Service c5cf8c
Packit Service c5cf8c
    mpi_errno = MPIR_Comm_create(&newcomm_ptr);
Packit Service c5cf8c
    if (mpi_errno)
Packit Service c5cf8c
        goto fn_fail;
Packit Service c5cf8c
Packit Service c5cf8c
    /* use a large garbage value to ensure errors are caught more easily */
Packit Service c5cf8c
    newcomm_ptr->context_id = 32767;
Packit Service c5cf8c
    newcomm_ptr->recvcontext_id = 32767;
Packit Service c5cf8c
Packit Service c5cf8c
    /* Save the kind of the communicator */
Packit Service c5cf8c
    newcomm_ptr->comm_kind = comm_ptr->comm_kind;
Packit Service c5cf8c
    newcomm_ptr->local_comm = 0;
Packit Service c5cf8c
Packit Service c5cf8c
    if (comm_ptr->comm_kind == MPIR_COMM_KIND__INTRACOMM)
Packit Service c5cf8c
        MPIR_Comm_map_dup(newcomm_ptr, comm_ptr, MPIR_COMM_MAP_DIR__L2L);
Packit Service c5cf8c
    else
Packit Service c5cf8c
        MPIR_Comm_map_dup(newcomm_ptr, comm_ptr, MPIR_COMM_MAP_DIR__R2R);
Packit Service c5cf8c
Packit Service c5cf8c
    /* If it is an intercomm, duplicate the network address mapping */
Packit Service c5cf8c
    if (comm_ptr->comm_kind == MPIR_COMM_KIND__INTERCOMM) {
Packit Service c5cf8c
        MPIR_Comm_map_dup(newcomm_ptr, comm_ptr, MPIR_COMM_MAP_DIR__L2L);
Packit Service c5cf8c
    }
Packit Service c5cf8c
Packit Service c5cf8c
    /* Set the sizes and ranks */
Packit Service c5cf8c
    newcomm_ptr->rank = comm_ptr->rank;
Packit Service c5cf8c
    newcomm_ptr->local_size = comm_ptr->local_size;
Packit Service c5cf8c
    newcomm_ptr->pof2 = comm_ptr->pof2;
Packit Service c5cf8c
    newcomm_ptr->remote_size = comm_ptr->remote_size;
Packit Service c5cf8c
    newcomm_ptr->is_low_group = comm_ptr->is_low_group; /* only relevant for intercomms */
Packit Service c5cf8c
Packit Service c5cf8c
    /* Inherit the error handler (if any) */
Packit Service c5cf8c
    MPID_THREAD_CS_ENTER(POBJ, MPIR_THREAD_POBJ_COMM_MUTEX(comm_ptr));
Packit Service c5cf8c
    newcomm_ptr->errhandler = comm_ptr->errhandler;
Packit Service c5cf8c
    if (comm_ptr->errhandler) {
Packit Service c5cf8c
        MPIR_Errhandler_add_ref(comm_ptr->errhandler);
Packit Service c5cf8c
    }
Packit Service c5cf8c
    MPID_THREAD_CS_EXIT(POBJ, MPIR_THREAD_POBJ_COMM_MUTEX(comm_ptr));
Packit Service c5cf8c
Packit Service c5cf8c
    /* Start with no attributes on this communicator */
Packit Service c5cf8c
    newcomm_ptr->attributes = 0;
Packit Service c5cf8c
    *outcomm_ptr = newcomm_ptr;
Packit Service c5cf8c
Packit Service c5cf8c
  fn_fail:
Packit Service c5cf8c
    MPIR_FUNC_TERSE_EXIT(MPID_STATE_MPIR_COMM_COPY_DATA);
Packit Service c5cf8c
    return mpi_errno;
Packit Service c5cf8c
}
Packit Service c5cf8c
Packit Service c5cf8c
/* Common body between MPIR_Comm_release and MPIR_comm_release_always.  This
Packit Service c5cf8c
 * helper function frees the actual MPIR_Comm structure and any associated
Packit Service c5cf8c
 * storage.  It also releases any references to other objects.
Packit Service c5cf8c
 * This function should only be called when the communicator's reference count
Packit Service c5cf8c
 * has dropped to 0.
Packit Service c5cf8c
 *
Packit Service c5cf8c
 * !!! This routine should *never* be called outside of MPIR_Comm_release{,_always} !!!
Packit Service c5cf8c
 */
Packit Service c5cf8c
#undef FUNCNAME
Packit Service c5cf8c
#define FUNCNAME MPIR_Comm_delete_internal
Packit Service c5cf8c
#undef FCNAME
Packit Service c5cf8c
#define FCNAME MPL_QUOTE(FUNCNAME)
Packit Service c5cf8c
int MPIR_Comm_delete_internal(MPIR_Comm * comm_ptr)
Packit Service c5cf8c
{
Packit Service c5cf8c
    int in_use;
Packit Service c5cf8c
    int mpi_errno = MPI_SUCCESS;
Packit Service c5cf8c
    MPIR_FUNC_TERSE_STATE_DECL(MPID_STATE_COMM_DELETE_INTERNAL);
Packit Service c5cf8c
Packit Service c5cf8c
    MPIR_FUNC_TERSE_ENTER(MPID_STATE_COMM_DELETE_INTERNAL);
Packit Service c5cf8c
Packit Service c5cf8c
    MPIR_Assert(MPIR_Object_get_ref(comm_ptr) == 0);    /* sanity check */
Packit Service c5cf8c
Packit Service c5cf8c
    /* Remove the attributes, executing the attribute delete routine.
Packit Service c5cf8c
     * Do this only if the attribute functions are defined.
Packit Service c5cf8c
     * This must be done first, because if freeing the attributes
Packit Service c5cf8c
     * returns an error, the communicator is not freed */
Packit Service c5cf8c
    if (MPIR_Process.attr_free && comm_ptr->attributes) {
Packit Service c5cf8c
        /* Temporarily add a reference to this communicator because
Packit Service c5cf8c
         * the attr_free code requires a valid communicator */
Packit Service c5cf8c
        MPIR_Object_add_ref(comm_ptr);
Packit Service c5cf8c
        mpi_errno = MPIR_Process.attr_free(comm_ptr->handle, &comm_ptr->attributes);
Packit Service c5cf8c
        /* Release the temporary reference added before the call to
Packit Service c5cf8c
         * attr_free */
Packit Service c5cf8c
        MPIR_Object_release_ref(comm_ptr, &in_use);
Packit Service c5cf8c
    }
Packit Service c5cf8c
Packit Service c5cf8c
    /* If the attribute delete functions return failure, the
Packit Service c5cf8c
     * communicator must not be freed.  That is the reason for the
Packit Service c5cf8c
     * test on mpi_errno here. */
Packit Service c5cf8c
    if (mpi_errno == MPI_SUCCESS) {
Packit Service c5cf8c
        /* If this communicator is our parent, and we're disconnecting
Packit Service c5cf8c
         * from the parent, mark that fact */
Packit Service c5cf8c
        if (MPIR_Process.comm_parent == comm_ptr)
Packit Service c5cf8c
            MPIR_Process.comm_parent = NULL;
Packit Service c5cf8c
Packit Service c5cf8c
        /* Cleanup collectives-specific infrastructure */
Packit Service c5cf8c
        mpi_errno = MPII_Coll_comm_cleanup(comm_ptr);
Packit Service c5cf8c
        if (mpi_errno)
Packit Service c5cf8c
            MPIR_ERR_POP(mpi_errno);
Packit Service c5cf8c
Packit Service c5cf8c
        /* Notify the device that the communicator is about to be
Packit Service c5cf8c
         * destroyed */
Packit Service c5cf8c
        mpi_errno = MPID_Comm_free_hook(comm_ptr);
Packit Service c5cf8c
        if (mpi_errno)
Packit Service c5cf8c
            MPIR_ERR_POP(mpi_errno);
Packit Service c5cf8c
Packit Service c5cf8c
        /* Free info hints */
Packit Service c5cf8c
        if (comm_ptr->info != NULL) {
Packit Service c5cf8c
            MPIR_Info_free(comm_ptr->info);
Packit Service c5cf8c
        }
Packit Service c5cf8c
Packit Service c5cf8c
        if (comm_ptr->comm_kind == MPIR_COMM_KIND__INTERCOMM && comm_ptr->local_comm)
Packit Service c5cf8c
            MPIR_Comm_release(comm_ptr->local_comm);
Packit Service c5cf8c
Packit Service c5cf8c
        /* Free the local and remote groups, if they exist */
Packit Service c5cf8c
        if (comm_ptr->local_group)
Packit Service c5cf8c
            MPIR_Group_release(comm_ptr->local_group);
Packit Service c5cf8c
        if (comm_ptr->remote_group)
Packit Service c5cf8c
            MPIR_Group_release(comm_ptr->remote_group);
Packit Service c5cf8c
Packit Service c5cf8c
        /* free the intra/inter-node communicators, if they exist */
Packit Service c5cf8c
        if (comm_ptr->node_comm)
Packit Service c5cf8c
            MPIR_Comm_release(comm_ptr->node_comm);
Packit Service c5cf8c
        if (comm_ptr->node_roots_comm)
Packit Service c5cf8c
            MPIR_Comm_release(comm_ptr->node_roots_comm);
Packit Service c5cf8c
        if (comm_ptr->intranode_table != NULL)
Packit Service c5cf8c
            MPL_free(comm_ptr->intranode_table);
Packit Service c5cf8c
        if (comm_ptr->internode_table != NULL)
Packit Service c5cf8c
            MPL_free(comm_ptr->internode_table);
Packit Service c5cf8c
Packit Service c5cf8c
        /* Free the context value.  This should come after freeing the
Packit Service c5cf8c
         * intra/inter-node communicators since those free calls won't
Packit Service c5cf8c
         * release this context ID and releasing this before then could lead
Packit Service c5cf8c
         * to races once we make threading finer grained. */
Packit Service c5cf8c
        /* This must be the recvcontext_id (i.e. not the (send)context_id)
Packit Service c5cf8c
         * because in the case of intercommunicators the send context ID is
Packit Service c5cf8c
         * allocated out of the remote group's bit vector, not ours. */
Packit Service c5cf8c
        MPIR_Free_contextid(comm_ptr->recvcontext_id);
Packit Service c5cf8c
Packit Service c5cf8c
#if MPICH_THREAD_GRANULARITY == MPICH_THREAD_GRANULARITY__POBJ
Packit Service c5cf8c
        {
Packit Service c5cf8c
            int thr_err;
Packit Service c5cf8c
            MPID_Thread_mutex_destroy(&MPIR_THREAD_POBJ_COMM_MUTEX(comm_ptr), &thr_err);
Packit Service c5cf8c
            MPIR_Assert(thr_err == 0);
Packit Service c5cf8c
        }
Packit Service c5cf8c
#endif
Packit Service c5cf8c
        /* We need to release the error handler */
Packit Service c5cf8c
        if (comm_ptr->errhandler &&
Packit Service c5cf8c
            !(HANDLE_GET_KIND(comm_ptr->errhandler->handle) == HANDLE_KIND_BUILTIN)) {
Packit Service c5cf8c
            int errhInuse;
Packit Service c5cf8c
            MPIR_Errhandler_release_ref(comm_ptr->errhandler, &errhInuse);
Packit Service c5cf8c
            if (!errhInuse) {
Packit Service c5cf8c
                MPIR_Handle_obj_free(&MPIR_Errhandler_mem, comm_ptr->errhandler);
Packit Service c5cf8c
            }
Packit Service c5cf8c
        }
Packit Service c5cf8c
Packit Service c5cf8c
        /* Remove from the list of active communicators if
Packit Service c5cf8c
         * we are supporting message-queue debugging.  We make this
Packit Service c5cf8c
         * conditional on having debugger support since the
Packit Service c5cf8c
         * operation is not constant-time */
Packit Service c5cf8c
        MPII_COMML_FORGET(comm_ptr);
Packit Service c5cf8c
Packit Service c5cf8c
        /* Check for predefined communicators - these should not
Packit Service c5cf8c
         * be freed */
Packit Service c5cf8c
        if (!(HANDLE_GET_KIND(comm_ptr->handle) == HANDLE_KIND_BUILTIN))
Packit Service c5cf8c
            MPIR_Handle_obj_free(&MPIR_Comm_mem, comm_ptr);
Packit Service c5cf8c
    } else {
Packit Service c5cf8c
        /* If the user attribute free function returns an error,
Packit Service c5cf8c
         * then do not free the communicator */
Packit Service c5cf8c
        MPIR_Comm_add_ref(comm_ptr);
Packit Service c5cf8c
    }
Packit Service c5cf8c
Packit Service c5cf8c
  fn_exit:
Packit Service c5cf8c
    MPIR_FUNC_TERSE_EXIT(MPID_STATE_COMM_DELETE_INTERNAL);
Packit Service c5cf8c
    return mpi_errno;
Packit Service c5cf8c
  fn_fail:
Packit Service c5cf8c
    goto fn_exit;
Packit Service c5cf8c
}
Packit Service c5cf8c
Packit Service c5cf8c
/* Release a reference to a communicator.  If there are no pending
Packit Service c5cf8c
   references, delete the communicator and recover all storage and
Packit Service c5cf8c
   context ids.  This version of the function always manipulates the reference
Packit Service c5cf8c
   counts, even for predefined objects. */
Packit Service c5cf8c
#undef FUNCNAME
Packit Service c5cf8c
#define FUNCNAME MPIR_Comm_release_always
Packit Service c5cf8c
#undef FCNAME
Packit Service c5cf8c
#define FCNAME MPL_QUOTE(FUNCNAME)
Packit Service c5cf8c
int MPIR_Comm_release_always(MPIR_Comm * comm_ptr)
Packit Service c5cf8c
{
Packit Service c5cf8c
    int mpi_errno = MPI_SUCCESS;
Packit Service c5cf8c
    int in_use;
Packit Service c5cf8c
    MPIR_FUNC_TERSE_STATE_DECL(MPID_STATE_MPIR_COMM_RELEASE_ALWAYS);
Packit Service c5cf8c
Packit Service c5cf8c
    MPIR_FUNC_TERSE_ENTER(MPID_STATE_MPIR_COMM_RELEASE_ALWAYS);
Packit Service c5cf8c
Packit Service c5cf8c
    /* we want to short-circuit any optimization that avoids reference counting
Packit Service c5cf8c
     * predefined communicators, such as MPI_COMM_WORLD or MPI_COMM_SELF. */
Packit Service c5cf8c
    MPIR_Object_release_ref_always(comm_ptr, &in_use);
Packit Service c5cf8c
    if (!in_use) {
Packit Service c5cf8c
        mpi_errno = MPIR_Comm_delete_internal(comm_ptr);
Packit Service c5cf8c
        if (mpi_errno)
Packit Service c5cf8c
            MPIR_ERR_POP(mpi_errno);
Packit Service c5cf8c
    }
Packit Service c5cf8c
Packit Service c5cf8c
  fn_exit:
Packit Service c5cf8c
    MPIR_FUNC_TERSE_EXIT(MPID_STATE_MPIR_COMM_RELEASE_ALWAYS);
Packit Service c5cf8c
    return mpi_errno;
Packit Service c5cf8c
  fn_fail:
Packit Service c5cf8c
    goto fn_exit;
Packit Service c5cf8c
}
Packit Service c5cf8c
Packit Service c5cf8c
/* Apply all known info hints in the specified info chain to the given
Packit Service c5cf8c
 * communicator. */
Packit Service c5cf8c
#undef FUNCNAME
Packit Service c5cf8c
#define FUNCNAME MPII_Comm_apply_hints
Packit Service c5cf8c
#undef FCNAME
Packit Service c5cf8c
#define FCNAME MPL_QUOTE(FUNCNAME)
Packit Service c5cf8c
int MPII_Comm_apply_hints(MPIR_Comm * comm_ptr, MPIR_Info * info_ptr)
Packit Service c5cf8c
{
Packit Service c5cf8c
    int mpi_errno = MPI_SUCCESS;
Packit Service c5cf8c
    MPIR_Info *hint = NULL;
Packit Service c5cf8c
    char hint_name[MPI_MAX_INFO_KEY] = { 0 };
Packit Service c5cf8c
    struct MPIR_Comm_hint_fn_elt *hint_fn = NULL;
Packit Service c5cf8c
    MPIR_FUNC_TERSE_STATE_DECL(MPID_STATE_MPIR_COMM_APPLY_HINTS);
Packit Service c5cf8c
Packit Service c5cf8c
    MPIR_FUNC_TERSE_ENTER(MPID_STATE_MPIR_COMM_APPLY_HINTS);
Packit Service c5cf8c
Packit Service c5cf8c
    LL_FOREACH(info_ptr, hint) {
Packit Service c5cf8c
        /* Have we hit the default, empty info hint? */
Packit Service c5cf8c
        if (hint->key == NULL)
Packit Service c5cf8c
            continue;
Packit Service c5cf8c
Packit Service c5cf8c
        MPL_strncpy(hint_name, hint->key, MPI_MAX_INFO_KEY);
Packit Service c5cf8c
Packit Service c5cf8c
        HASH_FIND_STR(MPID_hint_fns, hint_name, hint_fn);
Packit Service c5cf8c
Packit Service c5cf8c
        /* Skip hints that MPICH doesn't recognize. */
Packit Service c5cf8c
        if (hint_fn) {
Packit Service c5cf8c
            mpi_errno = hint_fn->fn(comm_ptr, hint, hint_fn->state);
Packit Service c5cf8c
            if (mpi_errno)
Packit Service c5cf8c
                MPIR_ERR_POP(mpi_errno);
Packit Service c5cf8c
        }
Packit Service c5cf8c
    }
Packit Service c5cf8c
Packit Service c5cf8c
  fn_exit:
Packit Service c5cf8c
    MPIR_FUNC_TERSE_EXIT(MPID_STATE_MPIR_COMM_APPLY_HINTS);
Packit Service c5cf8c
    return mpi_errno;
Packit Service c5cf8c
  fn_fail:
Packit Service c5cf8c
    goto fn_exit;
Packit Service c5cf8c
}
Packit Service c5cf8c
Packit Service c5cf8c
#undef FUNCNAME
Packit Service c5cf8c
#define FUNCNAME free_hint_handles
Packit Service c5cf8c
#undef FCNAME
Packit Service c5cf8c
#define FCNAME MPL_QUOTE(FUNCNAME)
Packit Service c5cf8c
static int free_hint_handles(void *ignore)
Packit Service c5cf8c
{
Packit Service c5cf8c
    int mpi_errno = MPI_SUCCESS;
Packit Service c5cf8c
    struct MPIR_Comm_hint_fn_elt *curr_hint = NULL, *tmp = NULL;
Packit Service c5cf8c
    MPIR_FUNC_TERSE_STATE_DECL(MPID_STATE_MPIR_COMM_FREE_HINT_HANDLES);
Packit Service c5cf8c
Packit Service c5cf8c
    MPIR_FUNC_TERSE_ENTER(MPID_STATE_MPIR_COMM_FREE_HINT_HANDLES);
Packit Service c5cf8c
Packit Service c5cf8c
    if (MPID_hint_fns) {
Packit Service c5cf8c
        HASH_ITER(hh, MPID_hint_fns, curr_hint, tmp) {
Packit Service c5cf8c
            HASH_DEL(MPID_hint_fns, curr_hint);
Packit Service c5cf8c
            MPL_free(curr_hint);
Packit Service c5cf8c
        }
Packit Service c5cf8c
    }
Packit Service c5cf8c
Packit Service c5cf8c
    MPIR_FUNC_TERSE_EXIT(MPID_STATE_MPIR_COMM_FREE_HINT_HANDLES);
Packit Service c5cf8c
    return mpi_errno;
Packit Service c5cf8c
}
Packit Service c5cf8c
Packit Service c5cf8c
/* The hint logic is stored in a uthash, with hint name as key and
Packit Service c5cf8c
 * the function responsible for applying the hint as the value. */
Packit Service c5cf8c
#undef FUNCNAME
Packit Service c5cf8c
#define FUNCNAME MPIR_Comm_register_hint
Packit Service c5cf8c
#undef FCNAME
Packit Service c5cf8c
#define FCNAME MPL_QUOTE(FUNCNAME)
Packit Service c5cf8c
int MPIR_Comm_register_hint(const char *hint_key, MPIR_Comm_hint_fn_t fn, void *state)
Packit Service c5cf8c
{
Packit Service c5cf8c
    int mpi_errno = MPI_SUCCESS;
Packit Service c5cf8c
    struct MPIR_Comm_hint_fn_elt *hint_elt = NULL;
Packit Service c5cf8c
    MPIR_FUNC_TERSE_STATE_DECL(MPID_STATE_MPIR_COMM_REGISTER_HINT);
Packit Service c5cf8c
Packit Service c5cf8c
    MPIR_FUNC_TERSE_ENTER(MPID_STATE_MPIR_COMM_REGISTER_HINT);
Packit Service c5cf8c
Packit Service c5cf8c
    if (MPID_hint_fns == NULL) {
Packit Service c5cf8c
        MPIR_Add_finalize(free_hint_handles, NULL, MPIR_FINALIZE_CALLBACK_PRIO - 1);
Packit Service c5cf8c
    }
Packit Service c5cf8c
Packit Service c5cf8c
    hint_elt = MPL_malloc(sizeof(struct MPIR_Comm_hint_fn_elt), MPL_MEM_COMM);
Packit Service c5cf8c
    MPL_strncpy(hint_elt->name, hint_key, MPI_MAX_INFO_KEY);
Packit Service c5cf8c
    hint_elt->state = state;
Packit Service c5cf8c
    hint_elt->fn = fn;
Packit Service c5cf8c
Packit Service c5cf8c
    HASH_ADD_STR(MPID_hint_fns, name, hint_elt, MPL_MEM_COMM);
Packit Service c5cf8c
Packit Service c5cf8c
    MPIR_FUNC_TERSE_EXIT(MPID_STATE_MPIR_COMM_REGISTER_HINT);
Packit Service c5cf8c
    return mpi_errno;
Packit Service c5cf8c
}