|
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 */
|