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