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-2005 The University of Tennessee and The University
7  *                         of Tennessee Research Foundation.  All rights
8  *                         reserved.
9  * Copyright (c) 2004-2007 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) 2015      Los Alamos National Security, LLC. All rights
14  *                         reserved.
15  * $COPYRIGHT$
16  *
17  * Additional copyrights may follow
18  *
19  * $HEADER$
20  */
21 
22 /**
23  * @file
24  *
25  * Implementation of opal_object_t, the base opal foundation class
26  */
27 
28 #include "opal_config.h"
29 
30 #include <stdio.h>
31 
32 #include "opal/sys/atomic.h"
33 #include "opal/class/opal_object.h"
34 #include "opal/constants.h"
35 
36 /*
37  * Instantiation of class descriptor for the base class.  This is
38  * special, since be mark it as already initialized, with no parent
39  * and no constructor or destructor.
40  */
41 opal_class_t opal_object_t_class = {
42     "opal_object_t",      /* name */
43     NULL,                 /* parent class */
44     NULL,                 /* constructor */
45     NULL,                 /* destructor */
46     1,                    /* initialized  -- this class is preinitialized */
47     0,                    /* class hierarchy depth */
48     NULL,                 /* array of constructors */
49     NULL,                 /* array of destructors */
50     sizeof(opal_object_t) /* size of the opal object */
51 };
52 
53 int opal_class_init_epoch = 1;
54 
55 /*
56  * Local variables
57  */
58 static opal_atomic_lock_t class_lock = { { OPAL_ATOMIC_LOCK_UNLOCKED } };
59 static void** classes = NULL;
60 static int num_classes = 0;
61 static int max_classes = 0;
62 static const int increment = 10;
63 
64 
65 /*
66  * Local functions
67  */
68 static void save_class(opal_class_t *cls);
69 static void expand_array(void);
70 
71 
72 /*
73  * Lazy initialization of class descriptor.
74  */
opal_class_initialize(opal_class_t * cls)75 void opal_class_initialize(opal_class_t *cls)
76 {
77     opal_class_t *c;
78     opal_construct_t* cls_construct_array;
79     opal_destruct_t* cls_destruct_array;
80     int cls_construct_array_count;
81     int cls_destruct_array_count;
82     int i;
83 
84     assert(cls);
85 
86     /* Check to see if any other thread got in here and initialized
87        this class before we got a chance to */
88 
89     if (opal_class_init_epoch == cls->cls_initialized) {
90         return;
91     }
92     opal_atomic_lock(&class_lock);
93 
94     /* If another thread initializing this same class came in at
95        roughly the same time, it may have gotten the lock and
96        initialized.  So check again. */
97 
98     if (opal_class_init_epoch == cls->cls_initialized) {
99         opal_atomic_unlock(&class_lock);
100         return;
101     }
102 
103     /*
104      * First calculate depth of class hierarchy
105      * And the number of constructors and destructors
106      */
107 
108     cls->cls_depth = 0;
109     cls_construct_array_count = 0;
110     cls_destruct_array_count  = 0;
111     for (c = cls; c; c = c->cls_parent) {
112         if( NULL != c->cls_construct ) {
113             cls_construct_array_count++;
114         }
115         if( NULL != c->cls_destruct ) {
116             cls_destruct_array_count++;
117         }
118         cls->cls_depth++;
119     }
120 
121     /*
122      * Allocate arrays for hierarchy of constructors and destructors
123      * plus for each a NULL-sentinel
124      */
125 
126     cls->cls_construct_array =
127         (void (**)(opal_object_t*))malloc((cls_construct_array_count +
128                                            cls_destruct_array_count + 2) *
129                                           sizeof(opal_construct_t) );
130     if (NULL == cls->cls_construct_array) {
131         perror("Out of memory");
132         exit(-1);
133     }
134     cls->cls_destruct_array =
135         cls->cls_construct_array + cls_construct_array_count + 1;
136 
137     /*
138      * The constructor array is reversed, so start at the end
139      */
140 
141     cls_construct_array = cls->cls_construct_array + cls_construct_array_count;
142     cls_destruct_array  = cls->cls_destruct_array;
143 
144     c = cls;
145     *cls_construct_array = NULL;  /* end marker for the constructors */
146     for (i = 0; i < cls->cls_depth; i++) {
147         if( NULL != c->cls_construct ) {
148             --cls_construct_array;
149             *cls_construct_array = c->cls_construct;
150         }
151         if( NULL != c->cls_destruct ) {
152             *cls_destruct_array = c->cls_destruct;
153             cls_destruct_array++;
154         }
155         c = c->cls_parent;
156     }
157     *cls_destruct_array = NULL;  /* end marker for the destructors */
158 
159     cls->cls_initialized = opal_class_init_epoch;
160     save_class(cls);
161 
162     /* All done */
163 
164     opal_atomic_unlock(&class_lock);
165 }
166 
167 
168 /*
169  * Note that this is finalize for *all* classes.
170  */
opal_class_finalize(void)171 int opal_class_finalize(void)
172 {
173     int i;
174 
175     if (INT_MAX == opal_class_init_epoch) {
176         opal_class_init_epoch = 1;
177     } else {
178         opal_class_init_epoch++;
179     }
180 
181     if (NULL != classes) {
182         for (i = 0; i < num_classes; ++i) {
183             if (NULL != classes[i]) {
184                 free(classes[i]);
185             }
186         }
187         free(classes);
188         classes = NULL;
189         num_classes = 0;
190         max_classes = 0;
191     }
192 
193     return OPAL_SUCCESS;
194 }
195 
196 
save_class(opal_class_t * cls)197 static void save_class(opal_class_t *cls)
198 {
199     if (num_classes >= max_classes) {
200         expand_array();
201     }
202 
203     classes[num_classes] = cls->cls_construct_array;
204     ++num_classes;
205 }
206 
207 
expand_array(void)208 static void expand_array(void)
209 {
210     int i;
211 
212     max_classes += increment;
213     classes = (void**)realloc(classes, sizeof(opal_class_t*) * max_classes);
214     if (NULL == classes) {
215         perror("class malloc failed");
216         exit(-1);
217     }
218     for (i = num_classes; i < max_classes; ++i) {
219         classes[i] = NULL;
220     }
221 }
222 
223