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