Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-02-22 10:47:20

0001 /* -*- Mode: C; c-basic-offset:4 ; -*- */
0002 /*
0003  * Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana
0004  *                         University Research and Technology
0005  *                         Corporation.  All rights reserved.
0006  * Copyright (c) 2004-2007 The University of Tennessee and The University
0007  *                         of Tennessee Research Foundation.  All rights
0008  *                         reserved.
0009  * Copyright (c) 2004-2006 High Performance Computing Center Stuttgart,
0010  *                         University of Stuttgart.  All rights reserved.
0011  * Copyright (c) 2004-2005 The Regents of the University of California.
0012  *                         All rights reserved.
0013  * Copyright (c) 2007      Cisco Systems, Inc.  All rights reserved.
0014  * Copyright (c) 2013-2020 Intel, Inc.  All rights reserved.
0015  * Copyright (c) 2016      Research Organization for Information Science
0016  *                         and Technology (RIST). All rights reserved.
0017  * Copyright (c) 2021-2022 Nanook Consulting  All rights reserved.
0018  * Copyright (c) 2021-2023 Triad National Security, LLC. All rights reserved.
0019  * $COPYRIGHT$
0020  *
0021  * Additional copyrights may follow
0022  *
0023  * $HEADER$
0024  */
0025 
0026 /**
0027  * @file:
0028  *
0029  * A simple C-language object-oriented system with single inheritance
0030  * and ownership-based memory management using a retain/release model.
0031  *
0032  * A class consists of a struct and singly-instantiated class
0033  * descriptor.  The first element of the struct must be the parent
0034  * class's struct.  The class descriptor must be given a well-known
0035  * name based upon the class struct name (if the struct is sally_t,
0036  * the class descriptor should be sally_t_class) and must be
0037  * statically initialized as discussed below.
0038  *
0039  * (a) To define a class
0040  *
0041  * In a interface (.h) file, define the class.  The first element
0042  * should always be the parent class, for example
0043  * @code
0044  *   struct sally_t
0045  *   {
0046  *     parent_t parent;
0047  *     void *first_member;
0048  *     ...
0049  *   };
0050  *   typedef struct sally_t sally_t;
0051  *
0052  *   PMIX_CLASS_DECLARATION(sally_t);
0053  * @endcode
0054  * All classes must have a parent which is also class.
0055  *
0056  * In an implementation (.c) file, instantiate a class descriptor for
0057  * the class like this:
0058  * @code
0059  *   PMIX_CLASS_INSTANCE(sally_t, parent_t, sally_construct, sally_destruct);
0060  * @endcode
0061  * This macro actually expands to
0062  * @code
0063  *   pmix_class_t sally_t_class = {
0064  *     "sally_t",
0065  *     PMIX_CLASS(parent_t),  // pointer to parent_t_class
0066  *     sally_construct,
0067  *     sally_destruct,
0068  *     0, 0, NULL, NULL,
0069  *     sizeof ("sally_t")
0070  *   };
0071  * @endcode
0072  * This variable should be declared in the interface (.h) file using
0073  * the PMIX_CLASS_DECLARATION macro as shown above.
0074  *
0075  * sally_construct, and sally_destruct are function pointers to the
0076  * constructor and destructor for the class and are best defined as
0077  * static functions in the implementation file.  NULL pointers maybe
0078  * supplied instead.
0079  *
0080  * Other class methods may be added to the struct.
0081  *
0082  * (b) Class instantiation: dynamic
0083  *
0084  * To create a instance of a class (an object) use PMIX_NEW:
0085  * @code
0086  *   sally_t *sally = PMIX_NEW(sally_t);
0087  * @endcode
0088  * which allocates memory of sizeof(sally_t) and runs the class's
0089  * constructors.
0090  *
0091  * Use PMIX_RETAIN, PMIX_RELEASE to do reference-count-based
0092  * memory management:
0093  * @code
0094  *   PMIX_RETAIN(sally);
0095  *   PMIX_RELEASE(sally);
0096  *   PMIX_RELEASE(sally);
0097  * @endcode
0098  * When the reference count reaches zero, the class's destructor, and
0099  * those of its parents, are run and the memory is freed.
0100  *
0101  * N.B. There is no explicit free/delete method for dynamic objects in
0102  * this model.
0103  *
0104  * (c) Class instantiation: static
0105  *
0106  * For an object with static (or stack) allocation, it is only
0107  * necessary to initialize the memory, which is done using
0108  * PMIX_CONSTRUCT:
0109  * @code
0110  *   sally_t sally;
0111  *
0112  *   PMIX_CONSTRUCT(&sally, sally_t);
0113  * @endcode
0114  * The retain/release model is not necessary here, but before the
0115  * object goes out of scope, PMIX_DESTRUCT should be run to release
0116  * initialized resources:
0117  * @code
0118  *   PMIX_DESTRUCT(&sally);
0119  * @endcode
0120  */
0121 
0122 #ifndef PMIX_OBJECT_H
0123 #define PMIX_OBJECT_H
0124 
0125 #include "src/include/pmix_config.h"
0126 #include "pmix_common.h"
0127 
0128 #include <assert.h>
0129 #ifdef HAVE_STDLIB_H
0130 #    include <stdlib.h>
0131 #endif /* HAVE_STDLIB_H */
0132 #include <pthread.h>
0133 #include <stdio.h>
0134 #include <errno.h>
0135 
0136 BEGIN_C_DECLS
0137 
0138 #if PMIX_ENABLE_DEBUG
0139 /* Any kind of unique ID should do the job */
0140 #    define PMIX_OBJ_MAGIC_ID ((0xdeafbeedULL << 32) + 0xdeafbeedULL)
0141 #endif
0142 
0143 /*
0144  * Macros for variadic object instantiation: w/wout custom memory allocator.
0145  *
0146  * NOTE(skg) There is probably a nicer way to implement this functionality. In
0147  * particular, with further macro magic we can probably unify a lot of the
0148  * common code here, but that is for another day.
0149  */
0150 
0151 /**
0152  * Takes in at least three arguments, eats all of them except the third.
0153  * This allows us to do things like:
0154  * PMIX_NEW_HAS_ARITY_HELPER(sally_t, TMA, NO_TMA, ERROR) --> NO_TMA
0155  * PMIX_NEW_HAS_ARITY_HELPER(sally_t, a_tma, TMA, NO_TMA, ERROR) --> TMA
0156  */
0157 #define PMIX_NEW_HAS_ARITY_HELPER(_1, _2, N, ...) N
0158 
0159 #define PMIX_NEW_HAS_ARITY_IMPL(...) \
0160     PMIX_NEW_HAS_ARITY_HELPER(__VA_ARGS__)
0161 /*
0162  * PMIX_CONSTRUCT() takes a maximum of three arguments:
0163  * Two arguments means caller does not want a custom memory allocator.
0164  * Three arguments means caller wants a custom (TMA) memory allocator.
0165  *
0166  * Please see PMIX_NEW_HAS_ARITY_HELPER's description above for more details
0167  * about how this macro functions.
0168  */
0169 #define PMIX_CONSTRUCT_HAS_ARITY_HELPER(_1, _2, _3, N, ...) N
0170 
0171 #define PMIX_CONSTRUCT_HAS_ARITY_IMPL(...) \
0172     PMIX_CONSTRUCT_HAS_ARITY_HELPER(__VA_ARGS__)
0173 
0174 /*
0175  * Macro suffix naming convention must be _TMA or _NO_TMA.
0176  *
0177  * These are the displacement mode lists used in the PMIX_NEW_HAS_ARITY_HELPER
0178  * example above.
0179  */
0180 #define PMIX_NEW_HAS_ARGS_SOURCE() TMA, NO_TMA, ERROR
0181 
0182 #define PMIX_CONSTRUCT_HAS_ARGS_SOURCE() TMA, NO_TMA, ERROR, ERROR
0183 
0184 #define PMIX_OBJ_HAS_ARGS(...) \
0185     PMIX_NEW_HAS_ARITY_IMPL(__VA_ARGS__, PMIX_NEW_HAS_ARGS_SOURCE())
0186 
0187 #define PMIX_CONSTRUCT_HAS_ARGS(...) \
0188     PMIX_CONSTRUCT_HAS_ARITY_IMPL(__VA_ARGS__, PMIX_CONSTRUCT_HAS_ARGS_SOURCE())
0189 /*
0190  * These are used to generate the proper macro name and forward the relevant
0191  * arguments depending on the number of arguments used.
0192  */
0193 #define PMIX_NEW_DISAMBIGUATE2(has_args, ...) \
0194     PMIX_NEW_ ## has_args (__VA_ARGS__)
0195 
0196 #define PMIX_NEW_DISAMBIGUATE(has_args, ...) \
0197     PMIX_NEW_DISAMBIGUATE2(has_args, __VA_ARGS__)
0198 
0199 #define PMIX_CONSTRUCT_DISAMBIGUATE2(has_args, ...) \
0200     PMIX_CONSTRUCT_ ## has_args (__VA_ARGS__)
0201 
0202 #define PMIX_CONSTRUCT_DISAMBIGUATE(has_args, ...) \
0203     PMIX_CONSTRUCT_DISAMBIGUATE2(has_args, __VA_ARGS__)
0204 
0205 /* typedefs ***********************************************************/
0206 
0207 typedef struct pmix_object_t pmix_object_t;
0208 typedef struct pmix_class_t pmix_class_t;
0209 typedef void (*pmix_construct_t)(pmix_object_t *);
0210 typedef void (*pmix_destruct_t)(pmix_object_t *);
0211 
0212 /* types **************************************************************/
0213 
0214 /** Memory allocator for objects */
0215 typedef struct pmix_tma {
0216     /** Pointer to the TMA's malloc() function. */
0217     void *(*tma_malloc)(struct pmix_tma *, size_t);
0218     /** Pointer to the TMA's calloc() function. */
0219     void *(*tma_calloc)(struct pmix_tma *, size_t, size_t);
0220     /** Pointer to the TMA's realloc() function. */
0221     void *(*tma_realloc)(struct pmix_tma *, void *, size_t);
0222     /*
0223      * NOTE: The seemingly unnecessary name mangling here is in response to
0224      * certain compilers not liking the use of a function pointer named strdup.
0225      */
0226     /** Pointer to the TMA's strdup() function. */
0227     char *(*tma_strdup)(struct pmix_tma *, const char *s);
0228     /**
0229      * A memmove()-like function that copies the provided contents to an
0230      * appropriate location in the memory area maintained by the allocator.
0231      * Like memmove(), it returns a pointer to the content's destination.
0232      */
0233     void *(*tma_memmove)(struct pmix_tma *tma, const void *src, size_t n);
0234     /** Pointer to the TMA's free() function. */
0235     void (*tma_free)(struct pmix_tma *, void *);
0236     /** Points to a user-defined TMA context. */
0237     void *data_context;
0238     /**
0239      * Points to generic data used by a TMA. An example includes a pointer to a
0240      * value that maintains the next available address.
0241      */
0242     void **data_ptr;
0243 } pmix_tma_t;
0244 
0245 static inline void *pmix_tma_malloc(pmix_tma_t *tma, size_t size)
0246 {
0247     if (NULL != tma) {
0248         return tma->tma_malloc(tma, size);
0249     } else {
0250         return malloc(size);
0251     }
0252 }
0253 
0254 static inline void *pmix_tma_calloc(pmix_tma_t *tma, size_t nmemb, size_t size)
0255 {
0256     if (NULL != tma) {
0257         return tma->tma_calloc(tma, nmemb, size);
0258     } else {
0259         return calloc(nmemb, size);
0260     }
0261 }
0262 
0263 static inline void *pmix_tma_realloc(pmix_tma_t *tma, void *ptr, size_t size)
0264 {
0265     if (NULL != tma) {
0266         return tma->tma_realloc(tma, ptr, size);
0267     } else {
0268         return realloc(ptr, size);
0269     }
0270 }
0271 
0272 static inline char *pmix_tma_strdup(pmix_tma_t *tma, const char *src)
0273 {
0274     if (NULL != tma) {
0275         return tma->tma_strdup(tma, src);
0276     } else {
0277         return strdup(src);
0278     }
0279 }
0280 
0281 static inline void pmix_tma_free(pmix_tma_t *tma, void *ptr)
0282 {
0283     if (NULL != tma) {
0284         tma->tma_free(tma, ptr);
0285     } else {
0286         free(ptr);
0287     }
0288 }
0289 
0290 /**
0291  * Class descriptor.
0292  *
0293  * There should be a single instance of this descriptor for each class
0294  * definition.
0295  */
0296 struct pmix_class_t {
0297     const char *cls_name;           /**< symbolic name for class */
0298     pmix_class_t *cls_parent;       /**< parent class descriptor */
0299     pmix_construct_t cls_construct; /**< class constructor */
0300     pmix_destruct_t cls_destruct;   /**< class destructor */
0301     int cls_initialized;            /**< is class initialized */
0302     int cls_depth;                  /**< depth of class hierarchy tree */
0303     pmix_construct_t *cls_construct_array;
0304     /**< array of parent class constructors */
0305     pmix_destruct_t *cls_destruct_array;
0306     /**< array of parent class destructors */
0307     size_t cls_sizeof; /**< size of an object instance */
0308 };
0309 
0310 PMIX_EXPORT extern int pmix_class_init_epoch;
0311 
0312 /**
0313  * For static initializations of OBJects.
0314  *
0315  * @param NAME   Name of the class to initialize
0316  */
0317 #if PMIX_ENABLE_DEBUG
0318 #    define PMIX_OBJ_STATIC_INIT(BASE_CLASS)        \
0319         {                                           \
0320             .obj_magic_id = PMIX_OBJ_MAGIC_ID,      \
0321             .obj_class = PMIX_CLASS(BASE_CLASS),    \
0322             .obj_lock = PTHREAD_MUTEX_INITIALIZER,  \
0323             .obj_reference_count = 1,               \
0324             .obj_tma = {                            \
0325                 .tma_malloc = NULL,                 \
0326                 .tma_calloc = NULL,                 \
0327                 .tma_realloc = NULL,                \
0328                 .tma_strdup = NULL,                 \
0329                 .tma_memmove = NULL,                \
0330                 .tma_free = NULL,                   \
0331                 .data_context = NULL,               \
0332                 .data_ptr = NULL                    \
0333             },                                      \
0334             .cls_init_file_name = __FILE__,         \
0335             .cls_init_lineno = __LINE__             \
0336         }
0337 #else
0338 #    define PMIX_OBJ_STATIC_INIT(BASE_CLASS)        \
0339         {                                           \
0340             .obj_class = PMIX_CLASS(BASE_CLASS),    \
0341             .obj_lock = PTHREAD_MUTEX_INITIALIZER,  \
0342             .obj_reference_count = 1,               \
0343             .obj_tma = {                            \
0344                 .tma_malloc = NULL,                 \
0345                 .tma_calloc = NULL,                 \
0346                 .tma_realloc = NULL,                \
0347                 .tma_strdup = NULL,                 \
0348                 .tma_memmove = NULL,                \
0349                 .tma_free = NULL,                   \
0350                 .data_context = NULL,               \
0351                 .data_ptr = NULL                    \
0352             }                                       \
0353         }
0354 #endif
0355 
0356 /**
0357  * Base object.
0358  *
0359  * This is special and does not follow the pattern for other classes.
0360  */
0361 struct pmix_object_t {
0362 #if PMIX_ENABLE_DEBUG
0363     /** Magic ID -- want this to be the very first item in the
0364         struct's memory */
0365     uint64_t obj_magic_id;
0366 #endif
0367     pthread_mutex_t obj_lock;
0368     pmix_class_t *obj_class;                 /**< class descriptor */
0369     int32_t obj_reference_count;             /**< reference count */
0370     pmix_tma_t obj_tma;                      /**< allocator for this object */
0371 #if PMIX_ENABLE_DEBUG
0372     const char *cls_init_file_name; /**< In debug mode store the file where the object get constructed */
0373     int cls_init_lineno; /**< In debug mode store the line number where the object get constructed */
0374 #endif                   /* PMIX_ENABLE_DEBUG */
0375 };
0376 
0377 /* macros ************************************************************/
0378 
0379 /**
0380  * Return a pointer to the class descriptor associated with a
0381  * class type.
0382  *
0383  * @param NAME          Name of class
0384  * @return              Pointer to class descriptor
0385  */
0386 #define PMIX_CLASS(NAME) (&(NAME##_class))
0387 
0388 /**
0389  * Static initializer for a class descriptor
0390  *
0391  * @param NAME          Name of class
0392  * @param PARENT        Name of parent class
0393  * @param CONSTRUCTOR   Pointer to constructor
0394  * @param DESTRUCTOR    Pointer to destructor
0395  *
0396  * Put this in NAME.c
0397  */
0398 #define PMIX_CLASS_INSTANCE(NAME, PARENT, CONSTRUCTOR, DESTRUCTOR) \
0399     pmix_class_t NAME##_class = {#NAME,                            \
0400                                  PMIX_CLASS(PARENT),               \
0401                                  (pmix_construct_t) CONSTRUCTOR,   \
0402                                  (pmix_destruct_t) DESTRUCTOR,     \
0403                                  0,                                \
0404                                  0,                                \
0405                                  NULL,                             \
0406                                  NULL,                             \
0407                                  sizeof(NAME)}
0408 
0409 /**
0410  * Declaration for class descriptor
0411  *
0412  * @param NAME          Name of class
0413  *
0414  * Put this in NAME.h
0415  */
0416 #define PMIX_CLASS_DECLARATION(NAME) extern pmix_class_t NAME##_class
0417 
0418 /**
0419  * Create an object: dynamically allocate storage and run the class
0420  * constructor.
0421  *
0422  * @param type          Type (class) of the object
0423  * @return              Pointer to the object
0424  */
0425 static inline pmix_object_t *pmix_obj_new_tma(pmix_class_t *cls, pmix_tma_t *tma);
0426 #if PMIX_ENABLE_DEBUG
0427 static inline pmix_object_t *pmix_obj_new_debug_tma(pmix_class_t *type, pmix_tma_t *tma,
0428                                                     const char *file, int line)
0429 {
0430     pmix_object_t *object = pmix_obj_new_tma(type, tma);
0431     if (NULL != object) {
0432         object->obj_magic_id = PMIX_OBJ_MAGIC_ID;
0433         object->cls_init_file_name = file;
0434         object->cls_init_lineno = line;
0435     }
0436     return object;
0437 }
0438 
0439 #define PMIX_NEW_NO_TMA(type) \
0440     ((type *)pmix_obj_new_debug_tma(PMIX_CLASS(type), NULL, __FILE__, __LINE__))
0441 
0442 #define PMIX_NEW_TMA(type, tma) \
0443     ((type *)pmix_obj_new_debug_tma(PMIX_CLASS(type), (tma), __FILE__, __LINE__))
0444 
0445 #else
0446 #define PMIX_NEW_NO_TMA(type)   ((type *)pmix_obj_new_tma(PMIX_CLASS(type), NULL))
0447 
0448 #define PMIX_NEW_TMA(type, tma) ((type *)pmix_obj_new_tma(PMIX_CLASS(type), (tma)))
0449 
0450 #endif /* PMIX_ENABLE_DEBUG */
0451 
0452 /**
0453  * PMIX_NEW() takes a maximum of two arguments:
0454  * One argument means caller does not want a custom memory allocator, namely the
0455  * common case.
0456  * Two arguments means caller wants a custom (TMA) memory allocator.
0457  */
0458 #define PMIX_NEW(...) \
0459     PMIX_NEW_DISAMBIGUATE(PMIX_OBJ_HAS_ARGS(__VA_ARGS__), __VA_ARGS__)
0460 
0461 /**
0462  * Retain an object (by incrementing its reference count)
0463  *
0464  * @param object        Pointer to the object
0465  */
0466 #if PMIX_ENABLE_DEBUG
0467 #    define PMIX_RETAIN(object)                                                      \
0468         do {                                                                         \
0469             assert(NULL != ((pmix_object_t *) (object))->obj_class);                 \
0470             assert(PMIX_OBJ_MAGIC_ID == ((pmix_object_t *) (object))->obj_magic_id); \
0471             pmix_obj_update((pmix_object_t *) (object), 1);                          \
0472             assert(((pmix_object_t *) (object))->obj_reference_count >= 0);          \
0473         } while (0)
0474 #else
0475 #    define PMIX_RETAIN(object) pmix_obj_update((pmix_object_t *) (object), 1)
0476 #endif
0477 
0478 /**
0479  * Helper macro for the debug mode to store the locations where the status of
0480  * an object change.
0481  */
0482 #if PMIX_ENABLE_DEBUG
0483 #    define PMIX_REMEMBER_FILE_AND_LINENO(OBJECT, FILE, LINENO)      \
0484         do {                                                         \
0485             ((pmix_object_t *) (OBJECT))->cls_init_file_name = FILE; \
0486             ((pmix_object_t *) (OBJECT))->cls_init_lineno = LINENO;  \
0487         } while (0)
0488 #    define PMIX_SET_MAGIC_ID(OBJECT, VALUE)                      \
0489         do {                                                      \
0490             ((pmix_object_t *) (OBJECT))->obj_magic_id = (VALUE); \
0491         } while (0)
0492 #else
0493 #    define PMIX_REMEMBER_FILE_AND_LINENO(OBJECT, FILE, LINENO)
0494 #    define PMIX_SET_MAGIC_ID(OBJECT, VALUE)
0495 #endif /* PMIX_ENABLE_DEBUG */
0496 
0497 /**
0498  * Release an object (by decrementing its reference count).  If the
0499  * reference count reaches zero, destruct (finalize) the object and
0500  * free its storage.
0501  *
0502  * Note: If the object is freed, then the value of the pointer is set
0503  * to NULL.
0504  *
0505  * @param object        Pointer to the object
0506  */
0507 #if PMIX_ENABLE_DEBUG
0508 #    define PMIX_RELEASE(object)                                           \
0509         do {                                                               \
0510             pmix_object_t *_obj = (pmix_object_t *) object;                \
0511             assert(NULL != _obj->obj_class);                               \
0512             assert(PMIX_OBJ_MAGIC_ID == _obj->obj_magic_id);               \
0513             if (0 == pmix_obj_update(_obj, -1)) {                          \
0514                 PMIX_SET_MAGIC_ID((object), 0);                            \
0515                 pmix_obj_run_destructors(_obj);                            \
0516                 PMIX_REMEMBER_FILE_AND_LINENO(object, __FILE__, __LINE__); \
0517                 if (NULL != _obj->obj_tma.tma_free) {                      \
0518                     pmix_tma_free(&_obj->obj_tma, object);                 \
0519                 }                                                          \
0520                 else {                                                     \
0521                     free(object);                                          \
0522                 }                                                          \
0523                 object = NULL;                                             \
0524             }                                                              \
0525         } while (0)
0526 #else
0527 #    define PMIX_RELEASE(object)                            \
0528         do {                                                \
0529             pmix_object_t *_obj = (pmix_object_t *) object; \
0530             if (0 == pmix_obj_update(_obj, -1)) {           \
0531                 pmix_obj_run_destructors(_obj);             \
0532                 if (NULL != _obj->obj_tma.tma_free) {       \
0533                     pmix_tma_free(&_obj->obj_tma, object);  \
0534                 }                                           \
0535                 else {                                      \
0536                     free(object);                           \
0537                 }                                           \
0538                 object = NULL;                              \
0539             }                                               \
0540         } while (0)
0541 #endif
0542 
0543 /**
0544  * Construct (initialize) objects that are not dynamically allocated.
0545  *
0546  * @param object        Pointer to the object
0547  * @param type          The object type
0548  */
0549 static inline void pmix_obj_construct_tma(pmix_object_t *obj, pmix_tma_t *tma)
0550 {
0551     if (NULL == tma) {
0552         obj->obj_tma.tma_malloc = NULL;
0553         obj->obj_tma.tma_calloc = NULL;
0554         obj->obj_tma.tma_realloc = NULL;
0555         obj->obj_tma.tma_strdup = NULL;
0556         obj->obj_tma.tma_memmove = NULL;
0557         obj->obj_tma.tma_free = NULL;
0558         obj->obj_tma.data_context = NULL;
0559         obj->obj_tma.data_ptr = NULL;
0560     } else {
0561         obj->obj_tma = *tma;
0562     }
0563 }
0564 
0565 #define PMIX_CONSTRUCT_INTERNAL_TMA(object, type, t)               \
0566     do {                                                           \
0567         PMIX_SET_MAGIC_ID((object), PMIX_OBJ_MAGIC_ID);            \
0568         if (pmix_class_init_epoch != (type)->cls_initialized) {    \
0569             pmix_class_initialize((type));                         \
0570         }                                                          \
0571         ((pmix_object_t *) (object))->obj_class = (type);          \
0572         ((pmix_object_t *) (object))->obj_reference_count = 1;     \
0573         pmix_obj_construct_tma(((pmix_object_t *) (object)), (t)); \
0574         pmix_obj_run_constructors((pmix_object_t *) (object));     \
0575         PMIX_REMEMBER_FILE_AND_LINENO(object, __FILE__, __LINE__); \
0576     } while (0)
0577 
0578 
0579 #define PMIX_CONSTRUCT_TMA(object, type, t)                           \
0580     do {                                                              \
0581         PMIX_CONSTRUCT_INTERNAL_TMA((object), PMIX_CLASS(type), (t)); \
0582     } while (0)
0583 
0584 
0585 #define PMIX_CONSTRUCT_NO_TMA(object, type)     \
0586     do {                                        \
0587         PMIX_CONSTRUCT_TMA(object, type, NULL); \
0588     } while (0)
0589 
0590 #define PMIX_CONSTRUCT(...) \
0591     PMIX_CONSTRUCT_DISAMBIGUATE(PMIX_CONSTRUCT_HAS_ARGS(__VA_ARGS__), __VA_ARGS__)
0592 
0593 /**
0594  * Destruct (finalize) an object that is not dynamically allocated.
0595  *
0596  * @param object        Pointer to the object
0597  */
0598 #if PMIX_ENABLE_DEBUG
0599 #    define PMIX_DESTRUCT(object)                                                    \
0600         do {                                                                         \
0601             assert(PMIX_OBJ_MAGIC_ID == ((pmix_object_t *) (object))->obj_magic_id); \
0602             PMIX_SET_MAGIC_ID((object), 0);                                          \
0603             pmix_obj_run_destructors((pmix_object_t *) (object));                    \
0604             PMIX_REMEMBER_FILE_AND_LINENO(object, __FILE__, __LINE__);               \
0605         } while (0)
0606 #else
0607 #    define PMIX_DESTRUCT(object)                                      \
0608         do {                                                           \
0609             pmix_obj_run_destructors((pmix_object_t *) (object));      \
0610             PMIX_REMEMBER_FILE_AND_LINENO(object, __FILE__, __LINE__); \
0611         } while (0)
0612 #endif
0613 
0614 PMIX_CLASS_DECLARATION(pmix_object_t);
0615 
0616 /* declarations *******************************************************/
0617 
0618 /**
0619  * Lazy initialization of class descriptor.
0620  *
0621  * Specifically cache arrays of function pointers for the constructor
0622  * and destructor hierarchies for this class.
0623  *
0624  * @param class    Pointer to class descriptor
0625  */
0626 PMIX_EXPORT void pmix_class_initialize(pmix_class_t *cls);
0627 
0628 /**
0629  * Shut down the class system and release all memory
0630  *
0631  * This function should be invoked as the ABSOLUTE LAST function to
0632  * use the class subsystem.  It frees all associated memory with ALL
0633  * classes, rendering all of them inoperable.  It is here so that
0634  * tools like valgrind and purify don't report still-reachable memory
0635  * upon process termination.
0636  */
0637 PMIX_EXPORT int pmix_class_finalize(void);
0638 
0639 /**
0640  * Run the hierarchy of class constructors for this object, in a
0641  * parent-first order.
0642  *
0643  * Do not use this function directly: use PMIX_CONSTRUCT() instead.
0644  *
0645  * WARNING: This implementation relies on a hardwired maximum depth of
0646  * the inheritance tree!!!
0647  *
0648  * Hardwired for fairly shallow inheritance trees
0649  * @param size          Pointer to the object.
0650  */
0651 static inline void pmix_obj_run_constructors(pmix_object_t *object)
0652 {
0653     pmix_construct_t *cls_construct;
0654 
0655     assert(NULL != object->obj_class);
0656 
0657     cls_construct = object->obj_class->cls_construct_array;
0658     while (NULL != *cls_construct) {
0659         (*cls_construct)(object);
0660         cls_construct++;
0661     }
0662 }
0663 
0664 /**
0665  * Run the hierarchy of class destructors for this object, in a
0666  * parent-last order.
0667  *
0668  * Do not use this function directly: use PMIX_DESTRUCT() instead.
0669  *
0670  * @param size          Pointer to the object.
0671  */
0672 static inline void pmix_obj_run_destructors(pmix_object_t *object)
0673 {
0674     pmix_destruct_t *cls_destruct;
0675 
0676     assert(NULL != object->obj_class);
0677 
0678     cls_destruct = object->obj_class->cls_destruct_array;
0679     while (NULL != *cls_destruct) {
0680         (*cls_destruct)(object);
0681         cls_destruct++;
0682     }
0683 }
0684 
0685 /**
0686  * Create new object: dynamically allocate storage and run the class
0687  * constructor.
0688  *
0689  * Do not use this function directly: use PMIX_NEW() instead.
0690  *
0691  * @param size          Size of the object
0692  * @param cls           Pointer to the class descriptor of this object
0693  * @return              Pointer to the object
0694  */
0695 static inline pmix_object_t *pmix_obj_new_tma(pmix_class_t *cls, pmix_tma_t *tma)
0696 {
0697     pmix_object_t *object;
0698     assert(cls->cls_sizeof >= sizeof(pmix_object_t));
0699 
0700     object = (pmix_object_t *) pmix_tma_malloc(tma, cls->cls_sizeof);
0701 
0702     if (pmix_class_init_epoch != cls->cls_initialized) {
0703         pmix_class_initialize(cls);
0704     }
0705     if (NULL != object) {
0706 #if PMIX_ENABLE_DEBUG
0707         pthread_mutexattr_t attr;
0708         pthread_mutexattr_init(&attr);
0709 
0710         /* set type to ERRORCHECK so that we catch recursive locks */
0711 #    if PMIX_HAVE_PTHREAD_MUTEX_ERRORCHECK_NP
0712         pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK_NP);
0713 #    elif PMIX_HAVE_PTHREAD_MUTEX_ERRORCHECK
0714         pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK);
0715 #    endif /* PMIX_HAVE_PTHREAD_MUTEX_ERRORCHECK_NP */
0716 
0717         pthread_mutex_init(&object->obj_lock, &attr);
0718         pthread_mutexattr_destroy(&attr);
0719 
0720 #else
0721 
0722         /* Without debugging, choose the fastest available mutexes */
0723         pthread_mutex_init(&object->obj_lock, NULL);
0724 
0725 #endif /* PMIX_ENABLE_DEBUG */
0726         object->obj_class = cls;
0727         object->obj_reference_count = 1;
0728         if (NULL == tma) {
0729             object->obj_tma.tma_malloc = NULL;
0730             object->obj_tma.tma_calloc = NULL;
0731             object->obj_tma.tma_realloc = NULL;
0732             object->obj_tma.tma_strdup = NULL;
0733             object->obj_tma.tma_free = NULL;
0734             object->obj_tma.data_context = NULL;
0735             object->obj_tma.data_ptr = NULL;
0736         } else {
0737             object->obj_tma = *tma;
0738         }
0739         pmix_obj_run_constructors(object);
0740     }
0741     return object;
0742 }
0743 
0744 /**
0745  * Atomically update the object's reference count by some increment.
0746  *
0747  * This function should not be used directly: it is called via the
0748  * macros PMIX_RETAIN and PMIX_RELEASE
0749  *
0750  * @param object        Pointer to the object
0751  * @param inc           Increment by which to update reference count
0752  * @return              New value of the reference count
0753  */
0754 static inline int pmix_obj_update(pmix_object_t *object, int inc) __pmix_attribute_always_inline__;
0755 static inline int pmix_obj_update(pmix_object_t *object, int inc)
0756 {
0757     int ret = pthread_mutex_lock(&object->obj_lock);
0758     if (ret == EDEADLK) {
0759         errno = ret;
0760         perror("pthread_mutex_lock()");
0761         abort();
0762     }
0763     ret = (object->obj_reference_count += inc);
0764     pthread_mutex_unlock(&object->obj_lock);
0765     return ret;
0766 }
0767 
0768 /**
0769  * Get a pointer to a given object's memory allocator. Returns a pointer to the
0770  * TMA, if available. Returns NULL Otherwise.
0771  */
0772 static inline pmix_tma_t *
0773 pmix_obj_get_tma(
0774     pmix_object_t *obj
0775 ) {
0776     // Look for a given function pointer. If it isn't NULL, then assume that
0777     // this object has a custom memory allocator.
0778     if (obj->obj_tma.tma_malloc) {
0779         return &obj->obj_tma;
0780     }
0781     return NULL;
0782 }
0783 
0784 END_C_DECLS
0785 
0786 #endif