2 * Name : static_memory_gremlin
3 * Author : Chris Koeritz
5 * Copyright (c) 2004-$now By Author. This program is free software; you can
6 * redistribute it and/or modify it under the terms of the GNU General Public
7 * License as published by the Free Software Foundation; either version 2 of
8 * the License or (at your option) any later version. This is online at:
9 * http://www.fsf.org/copyleft/gpl.html
10 * Please send any updates to: fred@gruntose.com
13 #include "static_memory_gremlin.h"
15 #include <basis/functions.h>
17 #include <basis/array.h>
18 //temp! needed for fake continuable error etc
23 using namespace basis;
25 namespace structures {
27 //#define DEBUG_STATIC_MEMORY_GREMLIN
28 // comment this out to eliminate debugging print-outs. otherwise they
29 // are controlled by the class interface.
31 //#define SKIP_STATIC_CLEANUP
32 // don't uncomment this unless you want all static objects to be left
33 // allocated on shutdown of the program. that's very sloppy but may
34 // sometimes be needed for testing.
38 const int SMG_CHUNKING_FACTOR = 32;
39 // we'll allocate this many indices at a time.
43 static bool __global_program_is_dying = false;
44 // this is set to true when no more logging or access to static objects
49 class gremlin_object_record
52 root_object *c_object;
58 static_memory_gremlin::static_memory_gremlin()
62 c_pointers(NULL_POINTER),
63 c_show_debugging(false)
65 ensure_space_exists();
68 static_memory_gremlin::~static_memory_gremlin()
70 __global_program_is_dying = true;
71 // now the rest of the program is on notice; we're practically gone.
73 #ifdef DEBUG_STATIC_MEMORY_GREMLIN
75 printf("SMG: beginning static object shutdown...\n");
78 #ifndef SKIP_STATIC_CLEANUP
79 // clean up any allocated pointers in reverse order of addition.
80 while (c_top_index > 0) {
81 // make sure we fixate on which guy is shutting down. some new ones
82 // could be added on the end of the list as a result of this destruction.
83 int zapped_index = c_top_index - 1;
84 gremlin_object_record *ptr = c_pointers[zapped_index];
85 c_pointers[zapped_index] = NULL_POINTER;
86 // since we know the one we're zapping, we no longer need that index.
88 // this should allow us to keep chewing on items that are newly being
89 // added during static shutdown, since we have taken the current object
90 // entirely out of the picture.
92 #ifdef DEBUG_STATIC_MEMORY_GREMLIN
94 printf((astring("SMG: deleting ") + ptr->c_object->instance_name()
95 + " called " + ptr->c_name
96 + a_sprintf(" at index %d.\n", zapped_index) ).s());
103 delete [] c_pointers;
104 c_pointers = NULL_POINTER;
107 bool static_memory_gremlin::__program_is_dying() { return __global_program_is_dying; }
109 mutex &static_memory_gremlin::__memory_gremlin_synchronizer()
111 static mutex __globabl_synch_mem;
112 return __globabl_synch_mem;
115 int static_memory_gremlin::locate(const char *unique_name)
117 auto_synchronizer l(c_lock);
118 for (int i = 0; i < c_top_index; i++) {
119 if (!strcmp(c_pointers[i]->c_name, unique_name)) return i;
121 return common::NOT_FOUND;
124 root_object *static_memory_gremlin::get(const char *unique_name)
126 auto_synchronizer l(c_lock);
127 int indy = locate(unique_name);
128 if (negative(indy)) return NULL_POINTER;
129 return c_pointers[indy]->c_object;
132 const char *static_memory_gremlin::find(const root_object *ptr)
134 auto_synchronizer l(c_lock);
135 for (int i = 0; i < c_top_index; i++) {
136 if (ptr == c_pointers[i]->c_object)
137 return c_pointers[i]->c_name;
142 bool static_memory_gremlin::put(const char *unique_name, root_object *to_put)
144 auto_synchronizer l(c_lock);
145 int indy = locate(unique_name);
146 // see if that name already exists.
147 if (non_negative(indy)) {
148 #ifdef DEBUG_STATIC_MEMORY_GREMLIN
149 if (c_show_debugging)
150 printf((astring("SMG: cleaning out old object ")
151 + c_pointers[indy]->c_object->instance_name()
152 + " called " + c_pointers[indy]->c_name
153 + " in favor of object " + to_put->instance_name()
154 + " called " + unique_name
155 + a_sprintf(" at index %d.\n", indy)).s());
157 WHACK(c_pointers[indy]->c_object);
158 c_pointers[indy]->c_object = to_put;
161 #ifdef DEBUG_STATIC_MEMORY_GREMLIN
162 if (c_show_debugging)
163 printf((astring("SMG: storing ") + to_put->instance_name()
164 + " called " + unique_name
165 + a_sprintf(" at index %d.\n", c_top_index)).s());
167 ensure_space_exists();
168 c_pointers[c_top_index] = new gremlin_object_record;
169 c_pointers[c_top_index]->c_object = to_put;
170 c_pointers[c_top_index]->c_name = unique_name;
175 void static_memory_gremlin::ensure_space_exists()
177 auto_synchronizer l(c_lock);
178 if (!c_pointers || (c_top_index + 1 >= c_actual_size) ) {
179 // never had any contents yet or not enough space exists.
180 #ifdef DEBUG_STATIC_MEMORY_GREMLIN
181 if (c_show_debugging)
182 printf(a_sprintf("SMG: adding space for top at %d.\n", c_top_index).s());
184 c_actual_size += SMG_CHUNKING_FACTOR;
185 typedef gremlin_object_record *base_ptr;
186 gremlin_object_record **new_ptr = new base_ptr[c_actual_size];
188 throw "error: static_memory_gremlin::ensure_space_exists: failed to allocate memory for pointer list";
190 for (int i = 0; i < c_actual_size; i++) new_ptr[i] = NULL_POINTER;
191 for (int j = 0; j < c_actual_size - SMG_CHUNKING_FACTOR; j++)
192 new_ptr[j] = c_pointers[j];
193 if (c_pointers) delete [] c_pointers;
194 c_pointers = new_ptr;
198 // this function ensures that the space for the global objects is kept until
199 // the program goes away. if it's the first time through, then the gremlin
200 // gets created; otherwise the existing one is used. this function should
201 // always be called by the main program before any attempts to use global
202 // features like SAFE_STATIC or the program wide logger. it is crucial that no
203 // user-level threads have been created in the program before this is called.
204 static_memory_gremlin &static_memory_gremlin::__hoople_globals()
206 static bool _initted = false; // tells whether we've gone through yet.
207 static static_memory_gremlin *_internal_gremlin = NULL_POINTER;
208 // holds our list of shared pieces...
211 #ifdef DEBUG_STATIC_MEMORY_GREMLIN
212 printf("%s: initializing HOOPLE_GLOBALS now.\n", _global_argv[0]);
215 #ifdef ENABLE_MEMORY_HOOK
216 void *temp = program_wide_memories().provide_memory(1, __FILE__, __LINE__);
217 // invoke now to get memory engine instantiated.
218 program_wide_memories().release_memory(temp); // clean up junk.
221 #ifdef ENABLE_CALLSTACK_TRACKING
222 program_wide_stack_trace().full_trace_size();
223 // invoke now to get callback tracking instantiated.
225 FUNCDEF("HOOPLE_GLOBALS remainder");
226 // this definition must be postponed until after the objects that would
227 // track it actually exist.
228 if (func) {} // shut up the compiler about using it.
230 // this simple approach is not going to succeed if the SAFE_STATIC macros
231 // are used in a static library which is then used in more than one dynamic
232 // library on win32. this is because each dll in win32 will have a
233 // different version of certain static objects that should only occur once
234 // per program. this problem is due to the win32 memory model, but in
235 // hoople at least this has been prevented; our only static library that
236 // appears in a bunch of dlls is basis and it is not allowed to use the
237 // SAFE_STATIC macro.
238 _internal_gremlin = new static_memory_gremlin;
242 return *_internal_gremlin;