Blame src/include/mpir_objects.h

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
#ifndef MPIR_OBJECTS_H_INCLUDED
Packit Service c5cf8c
#define MPIR_OBJECTS_H_INCLUDED
Packit Service c5cf8c
Packit Service c5cf8c
#include "mpichconf.h"
Packit Service c5cf8c
Packit Service c5cf8c
/*TDSOverview.tex
Packit Service c5cf8c
Packit Service c5cf8c
  MPI has a number of data structures, most of which are represented by
Packit Service c5cf8c
  an opaque handle in an MPI program.  In the MPICH implementation of MPI,
Packit Service c5cf8c
  these handles are represented
Packit Service c5cf8c
  as integers; this makes implementation of the C/Fortran handle transfer
Packit Service c5cf8c
  calls (part of MPI-2) easy.
Packit Service c5cf8c
Packit Service c5cf8c
  MPIR objects
Packit Service c5cf8c
  are allocated by a common set of object allocation functions.
Packit Service c5cf8c
Packit Service c5cf8c
  where 'objmem' is a pointer to a memory allocation object that knows
Packit Service c5cf8c
  enough to allocate objects, including the
Packit Service c5cf8c
  size of the object and the location of preallocated memory, as well
Packit Service c5cf8c
  as the type of memory allocator.  By providing the routines to allocate and
Packit Service c5cf8c
  free the memory, we make it easy to use the same interface to allocate both
Packit Service c5cf8c
  local and shared memory for objects (always using the same kind for each
Packit Service c5cf8c
  type of object).
Packit Service c5cf8c
Packit Service c5cf8c
  The names create/destroy were chosen because they are different from
Packit Service c5cf8c
  new/delete (C++ operations) and malloc/free.
Packit Service c5cf8c
  Any name choice will have some conflicts with other uses, of course.
Packit Service c5cf8c
Packit Service c5cf8c
  Reference Counts:
Packit Service c5cf8c
  Many MPI objects have reference count semantics.
Packit Service c5cf8c
  The semantics of MPI require that many objects that have been freed by the
Packit Service c5cf8c
  user
Packit Service c5cf8c
  (e.g., with 'MPI_Type_free' or 'MPI_Comm_free') remain valid until all
Packit Service c5cf8c
  pending
Packit Service c5cf8c
  references to that object (e.g., by an 'MPI_Irecv') are complete.  There
Packit Service c5cf8c
  are several ways to implement this; MPICH uses `reference counts` in the
Packit Service c5cf8c
  objects.  To support the 'MPI_THREAD_MULTIPLE' level of thread-safety, these
Packit Service c5cf8c
  reference counts must be accessed and updated atomically.
Packit Service c5cf8c
  A reference count for
Packit Service c5cf8c
  `any` object can be incremented (atomically)
Packit Service c5cf8c
  with 'MPIR_Object_add_ref(objptr)'
Packit Service c5cf8c
  and decremented with 'MPIR_Object_release_ref(objptr,newval_ptr)'.
Packit Service c5cf8c
  These have been designed so that then can be implemented as inlined
Packit Service c5cf8c
  macros rather than function calls, even in the multithreaded case, and
Packit Service c5cf8c
  can use special processor instructions that guarantee atomicity to
Packit Service c5cf8c
  avoid thread locks.
Packit Service c5cf8c
  The decrement routine sets the value pointed at by 'inuse_ptr' to 0 if
Packit Service c5cf8c
  the postdecrement value of the reference counter is zero, and to a non-zero
Packit Service c5cf8c
  value otherwise.  If this value is zero, then the routine that decremented
Packit Service c5cf8c
  the
Packit Service c5cf8c
  reference count should free the object.  This may be as simple as
Packit Service c5cf8c
  calling 'destroy' (for simple objects with no other allocated
Packit Service c5cf8c
  storage) or may require calling a separate routine to destroy the object.
Packit Service c5cf8c
  Because MPI uses 'MPI_xxx_free' to both decrement the reference count and
Packit Service c5cf8c
  free the object if the reference count is zero, we avoid the use of 'free'
Packit Service c5cf8c
  in the MPIR destruction routines.
Packit Service c5cf8c
Packit Service c5cf8c
  The 'inuse_ptr' approach is used rather than requiring the post-decrement
Packit Service c5cf8c
  value because, for reference-count semantics, all that is necessary is
Packit Service c5cf8c
  to know when the reference count reaches zero, and this can sometimes
Packit Service c5cf8c
  be implemented more cheaply that requiring the post-decrement value (e.g.,
Packit Service c5cf8c
  on IA32, there is an instruction for this operation).
Packit Service c5cf8c
Packit Service c5cf8c
  Question:
Packit Service c5cf8c
  Should we state that this is a macro so that we can use a register for
Packit Service c5cf8c
  the output value?  That avoids a store.  Alternately, have the macro
Packit Service c5cf8c
  return the value as if it was a function?
Packit Service c5cf8c
Packit Service c5cf8c
  Structure Definitions:
Packit Service c5cf8c
  The structure definitions in this document define `only` that part of
Packit Service c5cf8c
  a structure that may be used by code that is making use of the ADI.
Packit Service c5cf8c
  Thus, some structures, such as 'MPIR_Comm', have many defined fields;
Packit Service c5cf8c
  these are used to support MPI routines such as 'MPI_Comm_size' and
Packit Service c5cf8c
  'MPI_Comm_remote_group'.  Other structures may have few or no defined
Packit Service c5cf8c
  members; these structures have no fields used outside of the ADI.
Packit Service c5cf8c
  In C++ terms,  all members of these structures are 'private'.
Packit Service c5cf8c
Packit Service c5cf8c
  For the initial implementation, we expect that the structure definitions
Packit Service c5cf8c
  will be designed for the multimethod device.  However, all items that are
Packit Service c5cf8c
  specific to a particular device (including the multi-method device)
Packit Service c5cf8c
  will be placed at the end of the structure;
Packit Service c5cf8c
  the document will clearly identify the members that all implementations
Packit Service c5cf8c
  will provide.  This simplifies much of the code in both the ADI and the
Packit Service c5cf8c
  implementation of the MPI routines because structure member can be directly
Packit Service c5cf8c
  accessed rather than using some macro or C++ style method interface.
Packit Service c5cf8c
Packit Service c5cf8c
 T*/
Packit Service c5cf8c
Packit Service c5cf8c
/*TOpaqOverview.tex
Packit Service c5cf8c
  MPI Opaque Objects:
Packit Service c5cf8c
Packit Service c5cf8c
  MPI Opaque objects such as 'MPI_Comm' or 'MPI_Datatype' are specified by
Packit Service c5cf8c
  integers (in the MPICH implementation); the MPI standard calls these
Packit Service c5cf8c
  handles.
Packit Service c5cf8c
  Out of range values are invalid; the value 0 is reserved.
Packit Service c5cf8c
  For most (with the possible exception of
Packit Service c5cf8c
  'MPI_Request' for performance reasons) MPI Opaque objects, the integer
Packit Service c5cf8c
  encodes both the kind of object (allowing runtime tests to detect a datatype
Packit Service c5cf8c
  passed where a communicator is expected) and important properties of the
Packit Service c5cf8c
  object.  Even the 'MPI_xxx_NULL' values should be encoded so that
Packit Service c5cf8c
  different null handles can be distinguished.  The details of the encoding
Packit Service c5cf8c
  of the handles is covered in more detail in the MPICH Design Document.
Packit Service c5cf8c
  For the most part, the ADI uses pointers to the underlying structures
Packit Service c5cf8c
  rather than the handles themselves.  However, each structure contains an
Packit Service c5cf8c
  'handle' field that is the corresponding integer handle for the MPI object.
Packit Service c5cf8c
Packit Service c5cf8c
  MPIR objects are not opaque.
Packit Service c5cf8c
Packit Service c5cf8c
  T*/
Packit Service c5cf8c
Packit Service c5cf8c
/* Known MPI object types.  These are used for both the error handlers
Packit Service c5cf8c
   and for the handles.  This is a 4 bit value.  0 is reserved for so
Packit Service c5cf8c
   that all-zero handles can be flagged as an error. */
Packit Service c5cf8c
/*E
Packit Service c5cf8c
  MPII_Object_kind - Object kind (communicator, window, or file)
Packit Service c5cf8c
Packit Service c5cf8c
  Notes:
Packit Service c5cf8c
  This enum is used by keyvals and errhandlers to indicate the type of
Packit Service c5cf8c
  object for which MPI opaque types the data is valid.  These are defined
Packit Service c5cf8c
  as bits to allow future expansion to the case where an object is value for
Packit Service c5cf8c
  multiple types (for example, we may want a universal error handler for
Packit Service c5cf8c
  errors return).  This is also used to indicate the type of MPI object a
Packit Service c5cf8c
  MPI handle represents.  It is an enum because only this applies only the
Packit Service c5cf8c
  the MPI and internal MPICH objects.
Packit Service c5cf8c
Packit Service c5cf8c
  The 'MPIR_PROCGROUP' kind is used to manage process groups (different
Packit Service c5cf8c
  from MPI Groups) that are used to keep track of collections of
Packit Service c5cf8c
  processes (each 'MPIR_PROCGROUP' corresponds to a group of processes
Packit Service c5cf8c
  that define an 'MPI_COMM_WORLD'.  This becomes important only
Packit Service c5cf8c
  when MPI-2 dynamic process features are supported.  'MPIR_VCONN' is
Packit Service c5cf8c
  a virtual connection; while this is not part of the overall ADI3
Packit Service c5cf8c
  design, an object that manages connections to other processes is
Packit Service c5cf8c
  a common need, and 'MPIR_VCONN' may be used for that.
Packit Service c5cf8c
Packit Service c5cf8c
  Module:
Packit Service c5cf8c
  Attribute-DS
Packit Service c5cf8c
  E*/
Packit Service c5cf8c
typedef enum MPII_Object_kind {
Packit Service c5cf8c
    MPIR_COMM = 0x1,
Packit Service c5cf8c
    MPIR_GROUP = 0x2,
Packit Service c5cf8c
    MPIR_DATATYPE = 0x3,
Packit Service c5cf8c
    MPIR_FILE = 0x4,    /* only used obliquely inside MPIR_Errhandler objs */
Packit Service c5cf8c
    MPIR_ERRHANDLER = 0x5,
Packit Service c5cf8c
    MPIR_OP = 0x6,
Packit Service c5cf8c
    MPIR_INFO = 0x7,
Packit Service c5cf8c
    MPIR_WIN = 0x8,
Packit Service c5cf8c
    MPIR_KEYVAL = 0x9,
Packit Service c5cf8c
    MPIR_ATTR = 0xa,
Packit Service c5cf8c
    MPIR_REQUEST = 0xb,
Packit Service c5cf8c
    MPIR_PROCGROUP = 0xc,       /* These are internal device objects */
Packit Service c5cf8c
    MPIR_VCONN = 0xd,
Packit Service c5cf8c
    MPIR_WORKQ_ELEM = 0xe,      /* Work queue element, currently only meaningful in CH4 */
Packit Service c5cf8c
    MPIR_GREQ_CLASS = 0xf
Packit Service c5cf8c
} MPII_Object_kind;
Packit Service c5cf8c
Packit Service c5cf8c
Packit Service c5cf8c
#define HANDLE_MPI_KIND_SHIFT 26
Packit Service c5cf8c
#define HANDLE_GET_MPI_KIND(a) (((a)&0x3c000000) >> HANDLE_MPI_KIND_SHIFT)
Packit Service c5cf8c
#define HANDLE_SET_MPI_KIND(a,kind) ((a) | ((kind) << HANDLE_MPI_KIND_SHIFT))
Packit Service c5cf8c
Packit Service c5cf8c
/* returns the name of the handle kind for debugging/logging purposes */
Packit Service c5cf8c
const char *MPIR_Handle_get_kind_str(int kind);
Packit Service c5cf8c
Packit Service c5cf8c
/* Handle types.  These are really 2 bits */
Packit Service c5cf8c
#define HANDLE_KIND_INVALID  0x0
Packit Service c5cf8c
#define HANDLE_KIND_BUILTIN  0x1
Packit Service c5cf8c
#define HANDLE_KIND_DIRECT   0x2
Packit Service c5cf8c
#define HANDLE_KIND_INDIRECT 0x3
Packit Service c5cf8c
/* Mask assumes that ints are at least 4 bytes */
Packit Service c5cf8c
#define HANDLE_KIND_MASK 0xc0000000
Packit Service c5cf8c
#define HANDLE_KIND_SHIFT 30
Packit Service c5cf8c
#define HANDLE_GET_KIND(a) (((unsigned)(a)&HANDLE_KIND_MASK)>>HANDLE_KIND_SHIFT)
Packit Service c5cf8c
#define HANDLE_SET_KIND(a,kind) ((a)|((kind)<
Packit Service c5cf8c
Packit Service c5cf8c
/* For indirect, the remainder of the handle has a block and index within that
Packit Service c5cf8c
 * block */
Packit Service c5cf8c
#define HANDLE_INDIRECT_SHIFT 12
Packit Service c5cf8c
#define HANDLE_BLOCK(a) (((a)& 0x03FFF000) >> HANDLE_INDIRECT_SHIFT)
Packit Service c5cf8c
#define HANDLE_BLOCK_INDEX(a) ((a) & 0x00000FFF)
Packit Service c5cf8c
Packit Service c5cf8c
/* Number of blocks is between 1 and 16384 */
Packit Service c5cf8c
#if defined MPID_HANDLE_NUM_BLOCKS
Packit Service c5cf8c
#define HANDLE_NUM_BLOCKS MPID_HANDLE_NUM_BLOCKS
Packit Service c5cf8c
#else
Packit Service c5cf8c
#define HANDLE_NUM_BLOCKS 8192
Packit Service c5cf8c
#endif /* MPID_HANDLE_NUM_BLOCKS */
Packit Service c5cf8c
Packit Service c5cf8c
/* Number of objects in a block is bewtween 1 and 4096 (each obj has an index
Packit Service c5cf8c
 * within its block) */
Packit Service c5cf8c
#if defined MPID_HANDLE_NUM_INDICES
Packit Service c5cf8c
#define HANDLE_NUM_INDICES MPID_HANDLE_NUM_INDICES
Packit Service c5cf8c
#else
Packit Service c5cf8c
#define HANDLE_NUM_INDICES 1024
Packit Service c5cf8c
#endif /* MPID_HANDLE_NUM_INDICES */
Packit Service c5cf8c
Packit Service c5cf8c
/* For direct, the remainder of the handle is the index into a predefined
Packit Service c5cf8c
   block */
Packit Service c5cf8c
#define HANDLE_MASK 0x03FFFFFF
Packit Service c5cf8c
#define HANDLE_INDEX(a) ((a)& HANDLE_MASK)
Packit Service c5cf8c
Packit Service c5cf8c
#if defined (MPL_USE_DBG_LOGGING)
Packit Service c5cf8c
extern MPL_dbg_class MPIR_DBG_HANDLE;
Packit Service c5cf8c
#endif /* MPL_USE_DBG_LOGGING */
Packit Service c5cf8c
Packit Service c5cf8c
/* ------------------------------------------------------------------------- */
Packit Service c5cf8c
/* reference counting macros */
Packit Service c5cf8c
Packit Service c5cf8c
/* If we're debugging the handles (including reference counts),
Packit Service c5cf8c
   add an additional test.  The check on a max refcount helps to
Packit Service c5cf8c
   detect objects whose refcounts are not decremented as many times
Packit Service c5cf8c
   as they are incremented */
Packit Service c5cf8c
#ifdef MPICH_DEBUG_HANDLES
Packit Service c5cf8c
#define MPICH_DEBUG_MAX_REFCOUNT 64
Packit Service c5cf8c
#define HANDLE_CHECK_REFCOUNT(objptr_,local_ref_count_,op_)             \
Packit Service c5cf8c
    do {                                                                \
Packit Service c5cf8c
        if (local_ref_count_ > MPICH_DEBUG_MAX_REFCOUNT || local_ref_count_ < 0) \
Packit Service c5cf8c
        {                                                               \
Packit Service c5cf8c
            MPL_DBG_MSG_FMT(MPIR_DBG_HANDLE,TYPICAL,(MPL_DBG_FDEST,     \
Packit Service c5cf8c
                                                     "Invalid refcount (%d) in %p (0x%08x) %s", \
Packit Service c5cf8c
                                                     local_ref_count_, (objptr_), (objptr_)->handle, op_)); \
Packit Service c5cf8c
        }                                                               \
Packit Service c5cf8c
        MPIR_Assert(local_ref_count_ >= 0);                             \
Packit Service c5cf8c
    } while (0)
Packit Service c5cf8c
#else
Packit Service c5cf8c
#define HANDLE_CHECK_REFCOUNT(objptr_,local_ref_count_,op_)     \
Packit Service c5cf8c
    MPIR_Assert(local_ref_count_ >= 0)
Packit Service c5cf8c
#endif
Packit Service c5cf8c
Packit Service c5cf8c
#define HANDLE_LOG_REFCOUNT_CHANGE(objptr_, new_refcount_, action_str_) \
Packit Service c5cf8c
    MPL_DBG_MSG_FMT(MPIR_DBG_HANDLE,TYPICAL,(MPL_DBG_FDEST,             \
Packit Service c5cf8c
                                             "%s %p (0x%08x kind=%s) refcount to %d", \
Packit Service c5cf8c
                                             (action_str_),             \
Packit Service c5cf8c
                                             (objptr_),                 \
Packit Service c5cf8c
                                             (objptr_)->handle,         \
Packit Service c5cf8c
                                             MPIR_Handle_get_kind_str(HANDLE_GET_MPI_KIND((objptr_)->handle)), \
Packit Service c5cf8c
                                             new_refcount_))
Packit Service c5cf8c
Packit Service c5cf8c
/* The "_always" versions of these macros unconditionally manipulate the
Packit Service c5cf8c
 * reference count of the given object.  They exist to permit an optimization
Packit Service c5cf8c
 * of not reference counting predefined objects. */
Packit Service c5cf8c
Packit Service c5cf8c
/* The MPL_DBG... statements are macros that vanish unless
Packit Service c5cf8c
   --enable-g=log is selected.  HANDLE_CHECK_REFCOUNT is
Packit Service c5cf8c
   defined above, and adds an additional sanity check for the refcounts
Packit Service c5cf8c
*/
Packit Service c5cf8c
#if MPICH_THREAD_REFCOUNT == MPICH_REFCOUNT__NONE
Packit Service c5cf8c
Packit Service c5cf8c
typedef int Handle_ref_count;
Packit Service c5cf8c
Packit Service c5cf8c
#define MPIR_Object_set_ref(objptr_,val)                        \
Packit Service c5cf8c
    do {                                                        \
Packit Service c5cf8c
        (objptr_)->ref_count = val;                             \
Packit Service c5cf8c
        HANDLE_LOG_REFCOUNT_CHANGE(objptr_, val, "set");        \
Packit Service c5cf8c
    } while (0)
Packit Service c5cf8c
Packit Service c5cf8c
/* must be used with care, since there is no synchronization for this read */
Packit Service c5cf8c
#define MPIR_Object_get_ref(objptr_)            \
Packit Service c5cf8c
    ((objptr_)->ref_count)
Packit Service c5cf8c
Packit Service c5cf8c
#define MPIR_Object_add_ref_always(objptr_)                             \
Packit Service c5cf8c
    do {                                                                \
Packit Service c5cf8c
        (objptr_)->ref_count++;                                         \
Packit Service c5cf8c
        HANDLE_LOG_REFCOUNT_CHANGE(objptr_, (objptr_)->ref_count, "incr"); \
Packit Service c5cf8c
        HANDLE_CHECK_REFCOUNT(objptr_,(objptr_)->ref_count,"incr");     \
Packit Service c5cf8c
    } while (0)
Packit Service c5cf8c
#define MPIR_Object_release_ref_always(objptr_,inuse_ptr)               \
Packit Service c5cf8c
    do {                                                                \
Packit Service c5cf8c
        *(inuse_ptr) = --((objptr_)->ref_count);                        \
Packit Service c5cf8c
        HANDLE_LOG_REFCOUNT_CHANGE(objptr_, (objptr_)->ref_count, "decr"); \
Packit Service c5cf8c
        HANDLE_CHECK_REFCOUNT(objptr_,(objptr_)->ref_count,"decr");     \
Packit Service c5cf8c
    } while (0)
Packit Service c5cf8c
Packit Service c5cf8c
#elif MPICH_THREAD_REFCOUNT == MPICH_REFCOUNT__LOCKFREE
Packit Service c5cf8c
Packit Service c5cf8c
#include "opa_primitives.h"
Packit Service c5cf8c
typedef OPA_int_t Handle_ref_count;
Packit Service c5cf8c
Packit Service c5cf8c
#define MPIR_Object_set_ref(objptr_,val)                        \
Packit Service c5cf8c
    do {                                                        \
Packit Service c5cf8c
        OPA_store_int(&(objptr_)->ref_count, val);              \
Packit Service c5cf8c
        HANDLE_LOG_REFCOUNT_CHANGE(objptr_, val, "set");        \
Packit Service c5cf8c
    } while (0)
Packit Service c5cf8c
Packit Service c5cf8c
/* must be used with care, since there is no synchronization for this read */
Packit Service c5cf8c
#define MPIR_Object_get_ref(objptr_) \
Packit Service c5cf8c
    (OPA_load_int(&(objptr_)->ref_count))
Packit Service c5cf8c
Packit Service c5cf8c
#ifdef MPICH_DEBUG_HANDLES
Packit Service c5cf8c
/*
Packit Service c5cf8c
  For non-debug builds, we use non-fetch atomics here, because they may be
Packit Service c5cf8c
  slightly faster than fetch versions, and we don't care about exact value
Packit Service c5cf8c
  of the refcount (other than whether it hit zero.)
Packit Service c5cf8c
  For debug builds (when MPICH_DEBUG_HANDLES is set), we need fetch atomics
Packit Service c5cf8c
  in order to know the correct refcount value when multiple threads present.
Packit Service c5cf8c
*/
Packit Service c5cf8c
Packit Service c5cf8c
/* MPICH_THREAD_REFCOUNT == MPICH_REFCOUNT__LOCKFREE && MPICH_DEBUG_HANDLES */
Packit Service c5cf8c
#define MPIR_Object_add_ref_always(objptr_)                             \
Packit Service c5cf8c
    do {                                                                \
Packit Service c5cf8c
        int new_ref_;                                                   \
Packit Service c5cf8c
        new_ref_ = OPA_fetch_and_incr_int(&((objptr_)->ref_count)) + 1; \
Packit Service c5cf8c
        HANDLE_LOG_REFCOUNT_CHANGE(objptr_, new_ref_, "incr");          \
Packit Service c5cf8c
        HANDLE_CHECK_REFCOUNT(objptr_,new_ref_,"incr");                 \
Packit Service c5cf8c
    } while (0)
Packit Service c5cf8c
#define MPIR_Object_release_ref_always(objptr_,inuse_ptr)               \
Packit Service c5cf8c
    do {                                                                \
Packit Service c5cf8c
        int new_ref_ = OPA_fetch_and_decr_int(&((objptr_)->ref_count)) - 1; \
Packit Service c5cf8c
        *(inuse_ptr) = new_ref_;                                        \
Packit Service c5cf8c
        HANDLE_LOG_REFCOUNT_CHANGE(objptr_, new_ref_, "decr");          \
Packit Service c5cf8c
        HANDLE_CHECK_REFCOUNT(objptr_,new_ref_,"decr");                 \
Packit Service c5cf8c
    } while (0)
Packit Service c5cf8c
#else /* MPICH_DEBUG_HANDLES */
Packit Service c5cf8c
/* MPICH_THREAD_REFCOUNT == MPICH_REFCOUNT__LOCKFREE && !MPICH_DEBUG_HANDLES */
Packit Service c5cf8c
#define MPIR_Object_add_ref_always(objptr_)     \
Packit Service c5cf8c
    do {                                        \
Packit Service c5cf8c
        OPA_incr_int(&((objptr_)->ref_count));  \
Packit Service c5cf8c
    } while (0)
Packit Service c5cf8c
#define MPIR_Object_release_ref_always(objptr_,inuse_ptr)               \
Packit Service c5cf8c
    do {                                                                \
Packit Service c5cf8c
        int got_zero_ = OPA_decr_and_test_int(&((objptr_)->ref_count)); \
Packit Service c5cf8c
        *(inuse_ptr) = got_zero_ ? 0 : 1;                               \
Packit Service c5cf8c
    } while (0)
Packit Service c5cf8c
#endif /* MPICH_DEBUG_HANDLES */
Packit Service c5cf8c
#else
Packit Service c5cf8c
#error invalid value for MPICH_THREAD_REFCOUNT
Packit Service c5cf8c
#endif
Packit Service c5cf8c
Packit Service c5cf8c
/* TODO someday we should probably always suppress predefined object refcounting,
Packit Service c5cf8c
 * but we don't have total confidence in it yet.  So until we gain sufficient
Packit Service c5cf8c
 * confidence, this is a configurable option. */
Packit Service c5cf8c
#if defined(MPICH_THREAD_SUPPRESS_PREDEFINED_REFCOUNTS)
Packit Service c5cf8c
Packit Service c5cf8c
/* The assumption here is that objects with handles of type HANDLE_KIND_BUILTIN
Packit Service c5cf8c
 * will be created/destroyed only at MPI_Init/MPI_Finalize time and don't need
Packit Service c5cf8c
 * to be reference counted.  This can be a big performance win on some
Packit Service c5cf8c
 * platforms, such as BG/P.
Packit Service c5cf8c
 *
Packit Service c5cf8c
 * It is also assumed that any object being reference counted via these macros
Packit Service c5cf8c
 * will have a valid value in the handle field, even if it is
Packit Service c5cf8c
 * HANDLE_SET_KIND(0, HANDLE_KIND_INVALID) */
Packit Service c5cf8c
/* TODO profile and examine the assembly that is generated for this if () on Blue
Packit Service c5cf8c
 * Gene (and elsewhere).  We may need to mark it unlikely(). */
Packit Service c5cf8c
#define MPIR_Object_add_ref(objptr_)                                    \
Packit Service c5cf8c
    do {                                                                \
Packit Service c5cf8c
        int handle_kind_ = HANDLE_GET_KIND((objptr_)->handle);          \
Packit Service c5cf8c
        if (unlikely(handle_kind_ != HANDLE_KIND_BUILTIN)) {            \
Packit Service c5cf8c
            MPIR_Object_add_ref_always((objptr_));                      \
Packit Service c5cf8c
        }                                                               \
Packit Service c5cf8c
        else {                                                          \
Packit Service c5cf8c
            MPL_DBG_MSG_FMT(MPIR_DBG_HANDLE,TYPICAL,(MPL_DBG_FDEST,     \
Packit Service c5cf8c
                                                     "skipping add_ref on %p (0x%08x kind=%s) refcount=%d", \
Packit Service c5cf8c
                                                     (objptr_),         \
Packit Service c5cf8c
                                                     (objptr_)->handle, \
Packit Service c5cf8c
                                                     MPIR_Handle_get_kind_str(HANDLE_GET_MPI_KIND((objptr_)->handle)), \
Packit Service c5cf8c
                                                     MPIR_Object_get_ref(objptr_))) \
Packit Service c5cf8c
                }                                                       \
Packit Service c5cf8c
    } while (0)
Packit Service c5cf8c
#define MPIR_Object_release_ref(objptr_,inuse_ptr_)                     \
Packit Service c5cf8c
    do {                                                                \
Packit Service c5cf8c
        int handle_kind_ = HANDLE_GET_KIND((objptr_)->handle);          \
Packit Service c5cf8c
        if (unlikely(handle_kind_ != HANDLE_KIND_BUILTIN)) {            \
Packit Service c5cf8c
            MPIR_Object_release_ref_always((objptr_), (inuse_ptr_));    \
Packit Service c5cf8c
        }                                                               \
Packit Service c5cf8c
        else {                                                          \
Packit Service c5cf8c
            *(inuse_ptr_) = 1;                                          \
Packit Service c5cf8c
            MPL_DBG_MSG_FMT(MPIR_DBG_HANDLE,TYPICAL,(MPL_DBG_FDEST,     \
Packit Service c5cf8c
                                                     "skipping release_ref on %p (0x%08x kind=%s) refcount=%d", \
Packit Service c5cf8c
                                                     (objptr_),         \
Packit Service c5cf8c
                                                     (objptr_)->handle, \
Packit Service c5cf8c
                                                     MPIR_Handle_get_kind_str(HANDLE_GET_MPI_KIND((objptr_)->handle)), \
Packit Service c5cf8c
                                                     MPIR_Object_get_ref(objptr_))) \
Packit Service c5cf8c
                }                                                       \
Packit Service c5cf8c
    } while (0)
Packit Service c5cf8c
Packit Service c5cf8c
#else /* !defined(MPICH_THREAD_SUPPRESS_PREDEFINED_REFCOUNTS) */
Packit Service c5cf8c
Packit Service c5cf8c
/* the base case, where we just always manipulate the reference counts */
Packit Service c5cf8c
#define MPIR_Object_add_ref(objptr_)            \
Packit Service c5cf8c
    MPIR_Object_add_ref_always((objptr_))
Packit Service c5cf8c
#define MPIR_Object_release_ref(objptr_,inuse_ptr_)             \
Packit Service c5cf8c
    MPIR_Object_release_ref_always((objptr_),(inuse_ptr_))
Packit Service c5cf8c
Packit Service c5cf8c
#endif
Packit Service c5cf8c
Packit Service c5cf8c
Packit Service c5cf8c
/* end reference counting macros */
Packit Service c5cf8c
/* ------------------------------------------------------------------------- */
Packit Service c5cf8c
Packit Service c5cf8c
/* This macro defines structure fields that are needed in order to use the
Packit Service c5cf8c
 * reference counting and object allocation macros/functions in MPICH.  This
Packit Service c5cf8c
 * allows us to avoid casting and violating C's strict aliasing rules in most
Packit Service c5cf8c
 * cases.
Packit Service c5cf8c
 *
Packit Service c5cf8c
 * All *active* (in use) objects have the handle as the first value; objects
Packit Service c5cf8c
 * with referene counts have the reference count as the second value.  See
Packit Service c5cf8c
 * MPIR_Object_add_ref and MPIR_Object_release_ref.
Packit Service c5cf8c
 *
Packit Service c5cf8c
 * NOTE: This macro *must* be invoked as the very first element of the structure! */
Packit Service c5cf8c
#define MPIR_OBJECT_HEADER                                              \
Packit Service c5cf8c
    int handle;                                                         \
Packit Service c5cf8c
    Handle_ref_count ref_count  /*semicolon intentionally omitted */
Packit Service c5cf8c
Packit Service c5cf8c
/* ALL objects have the handle as the first value. */
Packit Service c5cf8c
/* Inactive (unused and stored on the appropriate avail list) objects
Packit Service c5cf8c
   have MPIR_Handle_common as the head */
Packit Service c5cf8c
typedef struct MPIR_Handle_common {
Packit Service c5cf8c
    MPIR_OBJECT_HEADER;
Packit Service c5cf8c
    void *next;                 /* Free handles use this field to point to the next
Packit Service c5cf8c
                                 * free object */
Packit Service c5cf8c
} MPIR_Handle_common;
Packit Service c5cf8c
Packit Service c5cf8c
/* This type contains all of the data, except for the direct array,
Packit Service c5cf8c
   used by the object allocators. */
Packit Service c5cf8c
typedef struct MPIR_Object_alloc_t {
Packit Service c5cf8c
    MPIR_Handle_common *avail;  /* Next available object */
Packit Service c5cf8c
    int initialized;            /* */
Packit Service c5cf8c
    void *(*indirect)[];        /* Pointer to indirect object blocks */
Packit Service c5cf8c
    int indirect_size;          /* Number of allocated indirect blocks */
Packit Service c5cf8c
    MPII_Object_kind kind;      /* Kind of object this is for */
Packit Service c5cf8c
    int size;                   /* Size of an individual object */
Packit Service c5cf8c
    void *direct;               /* Pointer to direct block, used
Packit Service c5cf8c
                                 * for allocation */
Packit Service c5cf8c
    int direct_size;            /* Size of direct block */
Packit Service c5cf8c
} MPIR_Object_alloc_t;
Packit Service c5cf8c
static inline void *MPIR_Handle_obj_alloc(MPIR_Object_alloc_t *);
Packit Service c5cf8c
static inline void *MPIR_Handle_obj_alloc_unsafe(MPIR_Object_alloc_t *);
Packit Service c5cf8c
static inline void MPIR_Handle_obj_free(MPIR_Object_alloc_t *, void *);
Packit Service c5cf8c
static inline void *MPIR_Handle_get_ptr_indirect(int, MPIR_Object_alloc_t *);
Packit Service c5cf8c
Packit Service c5cf8c
Packit Service c5cf8c
/* Convert Handles to objects for MPI types that have predefined objects */
Packit Service c5cf8c
/* TODO examine generated assembly for this construct, it's probably suboptimal
Packit Service c5cf8c
 * on Blue Gene.  An if/else if/else might help the compiler out.  It also lets
Packit Service c5cf8c
 * us hint that one case is likely(), usually the BUILTIN case. */
Packit Service c5cf8c
#define MPIR_Getb_ptr(kind,KIND,a,bmsk,ptr)                             \
Packit Service c5cf8c
    {                                                                   \
Packit Service c5cf8c
        switch (HANDLE_GET_KIND(a)) {                                   \
Packit Service c5cf8c
        case HANDLE_KIND_BUILTIN:                                       \
Packit Service c5cf8c
            MPIR_Assert(((a)&(bmsk)) < MPIR_##KIND##_N_BUILTIN);        \
Packit Service c5cf8c
            ptr=MPIR_##kind##_builtin+((a)&(bmsk));                     \
Packit Service c5cf8c
            break;                                                      \
Packit Service c5cf8c
        case HANDLE_KIND_DIRECT:                                        \
Packit Service c5cf8c
            ptr=MPIR_##kind##_direct+HANDLE_INDEX(a);                   \
Packit Service c5cf8c
            break;                                                      \
Packit Service c5cf8c
        case HANDLE_KIND_INDIRECT:                                      \
Packit Service c5cf8c
            ptr=((MPIR_##kind*)                                         \
Packit Service c5cf8c
                 MPIR_Handle_get_ptr_indirect(a,&MPIR_##kind##_mem));   \
Packit Service c5cf8c
            break;                                                      \
Packit Service c5cf8c
        case HANDLE_KIND_INVALID:                                       \
Packit Service c5cf8c
        default:                                                        \
Packit Service c5cf8c
            ptr=0;                                                      \
Packit Service c5cf8c
            break;                                                      \
Packit Service c5cf8c
        }                                                               \
Packit Service c5cf8c
    }
Packit Service c5cf8c
Packit Service c5cf8c
/* Convert handles to objects for MPI types that do _not_ have any predefined
Packit Service c5cf8c
   objects */
Packit Service c5cf8c
#define MPIR_Get_ptr(kind,a,ptr)                                        \
Packit Service c5cf8c
    {                                                                   \
Packit Service c5cf8c
        switch (HANDLE_GET_KIND(a)) {                                   \
Packit Service c5cf8c
        case HANDLE_KIND_DIRECT:                                        \
Packit Service c5cf8c
            ptr=MPIR_##kind##_direct+HANDLE_INDEX(a);                   \
Packit Service c5cf8c
            break;                                                      \
Packit Service c5cf8c
        case HANDLE_KIND_INDIRECT:                                      \
Packit Service c5cf8c
            ptr=((MPIR_##kind*)                                         \
Packit Service c5cf8c
                 MPIR_Handle_get_ptr_indirect(a,&MPIR_##kind##_mem));   \
Packit Service c5cf8c
            break;                                                      \
Packit Service c5cf8c
        case HANDLE_KIND_INVALID:                                       \
Packit Service c5cf8c
        case HANDLE_KIND_BUILTIN:                                       \
Packit Service c5cf8c
        default:                                                        \
Packit Service c5cf8c
            ptr=0;                                                      \
Packit Service c5cf8c
            break;                                                      \
Packit Service c5cf8c
        }                                                               \
Packit Service c5cf8c
    }
Packit Service c5cf8c
Packit Service c5cf8c
/* FIXME: the masks should be defined with the handle definitions instead
Packit Service c5cf8c
   of inserted here as literals */
Packit Service c5cf8c
#define MPIR_Comm_get_ptr(a,ptr)       MPIR_Getb_ptr(Comm,COMM,a,0x03ffffff,ptr)
Packit Service c5cf8c
#define MPIR_Group_get_ptr(a,ptr)      MPIR_Getb_ptr(Group,GROUP,a,0x03ffffff,ptr)
Packit Service c5cf8c
#define MPIR_Errhandler_get_ptr(a,ptr) MPIR_Getb_ptr(Errhandler,ERRHANDLER,a,0x3,ptr)
Packit Service c5cf8c
#define MPIR_Op_get_ptr(a,ptr)         MPIR_Getb_ptr(Op,OP,a,0x000000ff,ptr)
Packit Service c5cf8c
#define MPIR_Info_get_ptr(a,ptr)       MPIR_Getb_ptr(Info,INFO,a,0x03ffffff,ptr)
Packit Service c5cf8c
#define MPIR_Win_get_ptr(a,ptr)        MPIR_Get_ptr(Win,a,ptr)
Packit Service c5cf8c
#define MPIR_Request_get_ptr(a,ptr)    MPIR_Get_ptr(Request,a,ptr)
Packit Service c5cf8c
#define MPIR_Grequest_class_get_ptr(a,ptr) MPIR_Get_ptr(Grequest_class,a,ptr)
Packit Service c5cf8c
/* Keyvals have a special format. This is roughly MPIR_Get_ptrb, but
Packit Service c5cf8c
   the handle index is in a smaller bit field.  In addition,
Packit Service c5cf8c
   there is no storage for the builtin keyvals.
Packit Service c5cf8c
   For the indirect case, we mask off the part of the keyval that is
Packit Service c5cf8c
   in the bits normally used for the indirect block index.
Packit Service c5cf8c
*/
Packit Service c5cf8c
#define MPII_Keyval_get_ptr(a,ptr)                                      \
Packit Service c5cf8c
    {                                                                   \
Packit Service c5cf8c
        switch (HANDLE_GET_KIND(a)) {                                   \
Packit Service c5cf8c
        case HANDLE_KIND_BUILTIN:                                       \
Packit Service c5cf8c
            ptr=0;                                                      \
Packit Service c5cf8c
            break;                                                      \
Packit Service c5cf8c
        case HANDLE_KIND_DIRECT:                                        \
Packit Service c5cf8c
            ptr=MPII_Keyval_direct+((a)&0x3fffff);                      \
Packit Service c5cf8c
            break;                                                      \
Packit Service c5cf8c
        case HANDLE_KIND_INDIRECT:                                      \
Packit Service c5cf8c
            ptr=((MPII_Keyval*)                                         \
Packit Service c5cf8c
                 MPIR_Handle_get_ptr_indirect((a)&0xfc3fffff,&MPII_Keyval_mem)); \
Packit Service c5cf8c
            break;                                                      \
Packit Service c5cf8c
        case HANDLE_KIND_INVALID:                                       \
Packit Service c5cf8c
        default:                                                        \
Packit Service c5cf8c
            ptr=0;                                                      \
Packit Service c5cf8c
            break;                                                      \
Packit Service c5cf8c
        }                                                               \
Packit Service c5cf8c
    }
Packit Service c5cf8c
Packit Service c5cf8c
#endif /* MPIR_OBJECTS_H_INCLUDED */