root/opal/mca/pmix/pmix4x/pmix/src/class/pmix_object.h

/* [<][>][^][v][top][bottom][index][help] */

INCLUDED FROM


DEFINITIONS

This source file includes following definitions.
  1. pmix_obj_new_debug
  2. pmix_obj_run_constructors
  3. pmix_obj_run_destructors
  4. pmix_obj_new
  5. pmix_obj_update

   1 /* -*- Mode: C; c-basic-offset:4 ; -*- */
   2 /*
   3  * Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana
   4  *                         University Research and Technology
   5  *                         Corporation.  All rights reserved.
   6  * Copyright (c) 2004-2007 The University of Tennessee and The University
   7  *                         of Tennessee Research Foundation.  All rights
   8  *                         reserved.
   9  * Copyright (c) 2004-2006 High Performance Computing Center Stuttgart,
  10  *                         University of Stuttgart.  All rights reserved.
  11  * Copyright (c) 2004-2005 The Regents of the University of California.
  12  *                         All rights reserved.
  13  * Copyright (c) 2007      Cisco Systems, Inc.  All rights reserved.
  14  * Copyright (c) 2013-2018 Intel, Inc. All rights reserved.
  15  * Copyright (c) 2016      Research Organization for Information Science
  16  *                         and Technology (RIST). All rights reserved.
  17  * $COPYRIGHT$
  18  *
  19  * Additional copyrights may follow
  20  *
  21  * $HEADER$
  22  */
  23 
  24 /**
  25  * @file:
  26  *
  27  * A simple C-language object-oriented system with single inheritance
  28  * and ownership-based memory management using a retain/release model.
  29  *
  30  * A class consists of a struct and singly-instantiated class
  31  * descriptor.  The first element of the struct must be the parent
  32  * class's struct.  The class descriptor must be given a well-known
  33  * name based upon the class struct name (if the struct is sally_t,
  34  * the class descriptor should be sally_t_class) and must be
  35  * statically initialized as discussed below.
  36  *
  37  * (a) To define a class
  38  *
  39  * In a interface (.h) file, define the class.  The first element
  40  * should always be the parent class, for example
  41  * @code
  42  *   struct sally_t
  43  *   {
  44  *     parent_t parent;
  45  *     void *first_member;
  46  *     ...
  47  *   };
  48  *   typedef struct sally_t sally_t;
  49  *
  50  *   PMIX_CLASS_DECLARATION(sally_t);
  51  * @endcode
  52  * All classes must have a parent which is also class.
  53  *
  54  * In an implementation (.c) file, instantiate a class descriptor for
  55  * the class like this:
  56  * @code
  57  *   PMIX_CLASS_INSTANCE(sally_t, parent_t, sally_construct, sally_destruct);
  58  * @endcode
  59  * This macro actually expands to
  60  * @code
  61  *   pmix_class_t sally_t_class = {
  62  *     "sally_t",
  63  *     PMIX_CLASS(parent_t),  // pointer to parent_t_class
  64  *     sally_construct,
  65  *     sally_destruct,
  66  *     0, 0, NULL, NULL,
  67  *     sizeof ("sally_t")
  68  *   };
  69  * @endcode
  70  * This variable should be declared in the interface (.h) file using
  71  * the PMIX_CLASS_DECLARATION macro as shown above.
  72  *
  73  * sally_construct, and sally_destruct are function pointers to the
  74  * constructor and destructor for the class and are best defined as
  75  * static functions in the implementation file.  NULL pointers maybe
  76  * supplied instead.
  77  *
  78  * Other class methods may be added to the struct.
  79  *
  80  * (b) Class instantiation: dynamic
  81  *
  82  * To create a instance of a class (an object) use PMIX_NEW:
  83  * @code
  84  *   sally_t *sally = PMIX_NEW(sally_t);
  85  * @endcode
  86  * which allocates memory of sizeof(sally_t) and runs the class's
  87  * constructors.
  88  *
  89  * Use PMIX_RETAIN, PMIX_RELEASE to do reference-count-based
  90  * memory management:
  91  * @code
  92  *   PMIX_RETAIN(sally);
  93  *   PMIX_RELEASE(sally);
  94  *   PMIX_RELEASE(sally);
  95  * @endcode
  96  * When the reference count reaches zero, the class's destructor, and
  97  * those of its parents, are run and the memory is freed.
  98  *
  99  * N.B. There is no explicit free/delete method for dynamic objects in
 100  * this model.
 101  *
 102  * (c) Class instantiation: static
 103  *
 104  * For an object with static (or stack) allocation, it is only
 105  * necessary to initialize the memory, which is done using
 106  * PMIX_CONSTRUCT:
 107  * @code
 108  *   sally_t sally;
 109  *
 110  *   PMIX_CONSTRUCT(&sally, sally_t);
 111  * @endcode
 112  * The retain/release model is not necessary here, but before the
 113  * object goes out of scope, PMIX_DESTRUCT should be run to release
 114  * initialized resources:
 115  * @code
 116  *   PMIX_DESTRUCT(&sally);
 117  * @endcode
 118  */
 119 
 120 #ifndef PMIX_OBJECT_H
 121 #define PMIX_OBJECT_H
 122 
 123 #include <src/include/pmix_config.h>
 124 #include <pmix_common.h>
 125 
 126 #include <assert.h>
 127 #ifdef HAVE_STDLIB_H
 128 #include <stdlib.h>
 129 #endif  /* HAVE_STDLIB_H */
 130 
 131 #include "src/threads/thread_usage.h"
 132 
 133 BEGIN_C_DECLS
 134 
 135 #if PMIX_ENABLE_DEBUG
 136 /* Any kind of unique ID should do the job */
 137 #define PMIX_OBJ_MAGIC_ID ((0xdeafbeedULL << 32) + 0xdeafbeedULL)
 138 #endif
 139 
 140 /* typedefs ***********************************************************/
 141 
 142 typedef struct pmix_object_t pmix_object_t;
 143 typedef struct pmix_class_t pmix_class_t;
 144 typedef void (*pmix_construct_t) (pmix_object_t *);
 145 typedef void (*pmix_destruct_t) (pmix_object_t *);
 146 
 147 
 148 /* types **************************************************************/
 149 
 150 /**
 151  * Class descriptor.
 152  *
 153  * There should be a single instance of this descriptor for each class
 154  * definition.
 155  */
 156 struct pmix_class_t {
 157     const char *cls_name;           /**< symbolic name for class */
 158     pmix_class_t *cls_parent;       /**< parent class descriptor */
 159     pmix_construct_t cls_construct; /**< class constructor */
 160     pmix_destruct_t cls_destruct;   /**< class destructor */
 161     int cls_initialized;            /**< is class initialized */
 162     int cls_depth;                  /**< depth of class hierarchy tree */
 163     pmix_construct_t *cls_construct_array;
 164                                     /**< array of parent class constructors */
 165     pmix_destruct_t *cls_destruct_array;
 166                                     /**< array of parent class destructors */
 167     size_t cls_sizeof;              /**< size of an object instance */
 168 };
 169 
 170 PMIX_EXPORT extern int pmix_class_init_epoch;
 171 
 172 /**
 173  * For static initializations of OBJects.
 174  *
 175  * @param NAME   Name of the class to initialize
 176  */
 177 #if PMIX_ENABLE_DEBUG
 178 #define PMIX_OBJ_STATIC_INIT(BASE_CLASS) { PMIX_OBJ_MAGIC_ID, PMIX_CLASS(BASE_CLASS), 1, __FILE__, __LINE__ }
 179 #else
 180 #define PMIX_OBJ_STATIC_INIT(BASE_CLASS) { PMIX_CLASS(BASE_CLASS), 1 }
 181 #endif
 182 
 183 /**
 184  * Base object.
 185  *
 186  * This is special and does not follow the pattern for other classes.
 187  */
 188 struct pmix_object_t {
 189 #if PMIX_ENABLE_DEBUG
 190     /** Magic ID -- want this to be the very first item in the
 191         struct's memory */
 192     uint64_t obj_magic_id;
 193 #endif
 194     pmix_class_t *obj_class;            /**< class descriptor */
 195     pmix_atomic_int32_t obj_reference_count;   /**< reference count */
 196 #if PMIX_ENABLE_DEBUG
 197    const char* cls_init_file_name;        /**< In debug mode store the file where the object get contructed */
 198    int   cls_init_lineno;           /**< In debug mode store the line number where the object get contructed */
 199 #endif  /* PMIX_ENABLE_DEBUG */
 200 };
 201 
 202 /* macros ************************************************************/
 203 
 204 /**
 205  * Return a pointer to the class descriptor associated with a
 206  * class type.
 207  *
 208  * @param NAME          Name of class
 209  * @return              Pointer to class descriptor
 210  */
 211 #define PMIX_CLASS(NAME)     (&(NAME ## _class))
 212 
 213 
 214 /**
 215  * Static initializer for a class descriptor
 216  *
 217  * @param NAME          Name of class
 218  * @param PARENT        Name of parent class
 219  * @param CONSTRUCTOR   Pointer to constructor
 220  * @param DESTRUCTOR    Pointer to destructor
 221  *
 222  * Put this in NAME.c
 223  */
 224 #define PMIX_CLASS_INSTANCE(NAME, PARENT, CONSTRUCTOR, DESTRUCTOR)       \
 225     pmix_class_t NAME ## _class = {                                     \
 226         # NAME,                                                         \
 227         PMIX_CLASS(PARENT),                                              \
 228         (pmix_construct_t) CONSTRUCTOR,                                 \
 229         (pmix_destruct_t) DESTRUCTOR,                                   \
 230         0, 0, NULL, NULL,                                               \
 231         sizeof(NAME)                                                    \
 232     }
 233 
 234 
 235 /**
 236  * Declaration for class descriptor
 237  *
 238  * @param NAME          Name of class
 239  *
 240  * Put this in NAME.h
 241  */
 242 #define PMIX_CLASS_DECLARATION(NAME)             \
 243     extern pmix_class_t NAME ## _class
 244 
 245 
 246 /**
 247  * Create an object: dynamically allocate storage and run the class
 248  * constructor.
 249  *
 250  * @param type          Type (class) of the object
 251  * @return              Pointer to the object
 252  */
 253 static inline pmix_object_t *pmix_obj_new(pmix_class_t * cls);
 254 #if PMIX_ENABLE_DEBUG
 255 static inline pmix_object_t *pmix_obj_new_debug(pmix_class_t* type, const char* file, int line)
 256 {
 257     pmix_object_t* object = pmix_obj_new(type);
 258     object->obj_magic_id = PMIX_OBJ_MAGIC_ID;
 259     object->cls_init_file_name = file;
 260     object->cls_init_lineno = line;
 261     return object;
 262 }
 263 #define PMIX_NEW(type)                                   \
 264     ((type *)pmix_obj_new_debug(PMIX_CLASS(type), __FILE__, __LINE__))
 265 #else
 266 #define PMIX_NEW(type)                                   \
 267     ((type *) pmix_obj_new(PMIX_CLASS(type)))
 268 #endif  /* PMIX_ENABLE_DEBUG */
 269 
 270 /**
 271  * Retain an object (by incrementing its reference count)
 272  *
 273  * @param object        Pointer to the object
 274  */
 275 #if PMIX_ENABLE_DEBUG
 276 #define PMIX_RETAIN(object)                                              \
 277     do {                                                                \
 278         assert(NULL != ((pmix_object_t *) (object))->obj_class);        \
 279         assert(PMIX_OBJ_MAGIC_ID == ((pmix_object_t *) (object))->obj_magic_id); \
 280         pmix_obj_update((pmix_object_t *) (object), 1);                 \
 281         assert(((pmix_object_t *) (object))->obj_reference_count >= 0); \
 282     } while (0)
 283 #else
 284 #define PMIX_RETAIN(object)  pmix_obj_update((pmix_object_t *) (object), 1);
 285 #endif
 286 
 287 /**
 288  * Helper macro for the debug mode to store the locations where the status of
 289  * an object change.
 290  */
 291 #if PMIX_ENABLE_DEBUG
 292 #define PMIX_REMEMBER_FILE_AND_LINENO( OBJECT, FILE, LINENO )    \
 293     do {                                                        \
 294         ((pmix_object_t*)(OBJECT))->cls_init_file_name = FILE;  \
 295         ((pmix_object_t*)(OBJECT))->cls_init_lineno = LINENO;   \
 296     } while (0)
 297 #define PMIX_SET_MAGIC_ID( OBJECT, VALUE )                       \
 298     do {                                                        \
 299         ((pmix_object_t*)(OBJECT))->obj_magic_id = (VALUE);     \
 300     } while (0)
 301 #else
 302 #define PMIX_REMEMBER_FILE_AND_LINENO( OBJECT, FILE, LINENO )
 303 #define PMIX_SET_MAGIC_ID( OBJECT, VALUE )
 304 #endif  /* PMIX_ENABLE_DEBUG */
 305 
 306 /**
 307  * Release an object (by decrementing its reference count).  If the
 308  * reference count reaches zero, destruct (finalize) the object and
 309  * free its storage.
 310  *
 311  * Note: If the object is freed, then the value of the pointer is set
 312  * to NULL.
 313  *
 314  * @param object        Pointer to the object
 315  */
 316 #if PMIX_ENABLE_DEBUG
 317 #define PMIX_RELEASE(object)                                             \
 318     do {                                                                \
 319         assert(NULL != ((pmix_object_t *) (object))->obj_class);        \
 320         assert(PMIX_OBJ_MAGIC_ID == ((pmix_object_t *) (object))->obj_magic_id); \
 321         if (0 == pmix_obj_update((pmix_object_t *) (object), -1)) {     \
 322             PMIX_SET_MAGIC_ID((object), 0);                              \
 323             pmix_obj_run_destructors((pmix_object_t *) (object));       \
 324             PMIX_REMEMBER_FILE_AND_LINENO( object, __FILE__, __LINE__ ); \
 325             free(object);                                               \
 326             object = NULL;                                              \
 327         }                                                               \
 328     } while (0)
 329 #else
 330 #define PMIX_RELEASE(object)                                             \
 331     do {                                                                \
 332         if (0 == pmix_obj_update((pmix_object_t *) (object), -1)) {     \
 333             pmix_obj_run_destructors((pmix_object_t *) (object));       \
 334             free(object);                                               \
 335             object = NULL;                                              \
 336         }                                                               \
 337     } while (0)
 338 #endif
 339 
 340 
 341 /**
 342  * Construct (initialize) objects that are not dynamically allocated.
 343  *
 344  * @param object        Pointer to the object
 345  * @param type          The object type
 346  */
 347 
 348 #define PMIX_CONSTRUCT(object, type)                             \
 349 do {                                                            \
 350     PMIX_CONSTRUCT_INTERNAL((object), PMIX_CLASS(type));          \
 351 } while (0)
 352 
 353 #define PMIX_CONSTRUCT_INTERNAL(object, type)                        \
 354 do {                                                                \
 355     PMIX_SET_MAGIC_ID((object), PMIX_OBJ_MAGIC_ID);              \
 356     if (pmix_class_init_epoch != (type)->cls_initialized) {                             \
 357         pmix_class_initialize((type));                              \
 358     }                                                               \
 359     ((pmix_object_t *) (object))->obj_class = (type);               \
 360     ((pmix_object_t *) (object))->obj_reference_count = 1;          \
 361     pmix_obj_run_constructors((pmix_object_t *) (object));          \
 362     PMIX_REMEMBER_FILE_AND_LINENO( object, __FILE__, __LINE__ ); \
 363 } while (0)
 364 
 365 
 366 /**
 367  * Destruct (finalize) an object that is not dynamically allocated.
 368  *
 369  * @param object        Pointer to the object
 370  */
 371 #if PMIX_ENABLE_DEBUG
 372 #define PMIX_DESTRUCT(object)                                    \
 373 do {                                                            \
 374     assert(PMIX_OBJ_MAGIC_ID == ((pmix_object_t *) (object))->obj_magic_id); \
 375     PMIX_SET_MAGIC_ID((object), 0);                              \
 376     pmix_obj_run_destructors((pmix_object_t *) (object));       \
 377     PMIX_REMEMBER_FILE_AND_LINENO( object, __FILE__, __LINE__ ); \
 378 } while (0)
 379 #else
 380 #define PMIX_DESTRUCT(object)                                    \
 381 do {                                                            \
 382     pmix_obj_run_destructors((pmix_object_t *) (object));       \
 383     PMIX_REMEMBER_FILE_AND_LINENO( object, __FILE__, __LINE__ ); \
 384 } while (0)
 385 #endif
 386 
 387 PMIX_CLASS_DECLARATION(pmix_object_t);
 388 
 389 /* declarations *******************************************************/
 390 
 391 /**
 392  * Lazy initialization of class descriptor.
 393  *
 394  * Specifically cache arrays of function pointers for the constructor
 395  * and destructor hierarchies for this class.
 396  *
 397  * @param class    Pointer to class descriptor
 398  */
 399 PMIX_EXPORT void pmix_class_initialize(pmix_class_t *);
 400 
 401 /**
 402  * Shut down the class system and release all memory
 403  *
 404  * This function should be invoked as the ABSOLUTE LAST function to
 405  * use the class subsystem.  It frees all associated memory with ALL
 406  * classes, rendering all of them inoperable.  It is here so that
 407  * tools like valgrind and purify don't report still-reachable memory
 408  * upon process termination.
 409  */
 410 PMIX_EXPORT int pmix_class_finalize(void);
 411 
 412 /**
 413  * Run the hierarchy of class constructors for this object, in a
 414  * parent-first order.
 415  *
 416  * Do not use this function directly: use PMIX_CONSTRUCT() instead.
 417  *
 418  * WARNING: This implementation relies on a hardwired maximum depth of
 419  * the inheritance tree!!!
 420  *
 421  * Hardwired for fairly shallow inheritance trees
 422  * @param size          Pointer to the object.
 423  */
 424 static inline void pmix_obj_run_constructors(pmix_object_t * object)
 425 {
 426     pmix_construct_t* cls_construct;
 427 
 428     assert(NULL != object->obj_class);
 429 
 430     cls_construct = object->obj_class->cls_construct_array;
 431     while( NULL != *cls_construct ) {
 432         (*cls_construct)(object);
 433         cls_construct++;
 434     }
 435 }
 436 
 437 
 438 /**
 439  * Run the hierarchy of class destructors for this object, in a
 440  * parent-last order.
 441  *
 442  * Do not use this function directly: use PMIX_DESTRUCT() instead.
 443  *
 444  * @param size          Pointer to the object.
 445  */
 446 static inline void pmix_obj_run_destructors(pmix_object_t * object)
 447 {
 448     pmix_destruct_t* cls_destruct;
 449 
 450     assert(NULL != object->obj_class);
 451 
 452     cls_destruct = object->obj_class->cls_destruct_array;
 453     while( NULL != *cls_destruct ) {
 454         (*cls_destruct)(object);
 455         cls_destruct++;
 456     }
 457 }
 458 
 459 
 460 /**
 461  * Create new object: dynamically allocate storage and run the class
 462  * constructor.
 463  *
 464  * Do not use this function directly: use PMIX_NEW() instead.
 465  *
 466  * @param size          Size of the object
 467  * @param cls           Pointer to the class descriptor of this object
 468  * @return              Pointer to the object
 469  */
 470 static inline pmix_object_t *pmix_obj_new(pmix_class_t * cls)
 471 {
 472     pmix_object_t *object;
 473     assert(cls->cls_sizeof >= sizeof(pmix_object_t));
 474 
 475     object = (pmix_object_t *) malloc(cls->cls_sizeof);
 476     if (pmix_class_init_epoch != cls->cls_initialized) {
 477         pmix_class_initialize(cls);
 478     }
 479     if (NULL != object) {
 480         object->obj_class = cls;
 481         object->obj_reference_count = 1;
 482         pmix_obj_run_constructors(object);
 483     }
 484     return object;
 485 }
 486 
 487 
 488 /**
 489  * Atomically update the object's reference count by some increment.
 490  *
 491  * This function should not be used directly: it is called via the
 492  * macros PMIX_RETAIN and PMIX_RELEASE
 493  *
 494  * @param object        Pointer to the object
 495  * @param inc           Increment by which to update reference count
 496  * @return              New value of the reference count
 497  */
 498 static inline int pmix_obj_update(pmix_object_t *object, int inc) __pmix_attribute_always_inline__;
 499 static inline int pmix_obj_update(pmix_object_t *object, int inc)
 500 {
 501     return PMIX_THREAD_ADD_FETCH32(&object->obj_reference_count, inc);
 502 }
 503 
 504 END_C_DECLS
 505 
 506 #endif

/* [<][>][^][v][top][bottom][index][help] */