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