feisty meow concerns codebase  2.140
static_memory_gremlin.cpp
Go to the documentation of this file.
1 /*
2 * Name : static_memory_gremlin
3 * Author : Chris Koeritz
4 *
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
11 */
12 
13 #include "static_memory_gremlin.h"
14 
15 #include <basis/functions.h>
16 
17 #include <basis/array.h>
18 //temp! needed for fake continuable error etc
19 
20 #include <stdio.h>
21 #include <string.h>
22 
23 using namespace basis;
24 
25 namespace structures {
26 
27 //#define DEBUG_STATIC_MEMORY_GREMLIN
28  // comment this out to eliminate debugging print-outs. otherwise they
29  // are controlled by the class interface.
30 
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.
35 
37 
38 const int SMG_CHUNKING_FACTOR = 32;
39  // we'll allocate this many indices at a time.
40 
42 
43 static bool __global_program_is_dying = false;
44  // this is set to true when no more logging or access to static objects
45  // should be allowed.
46 
48 
49 class gremlin_object_record
50 {
51 public:
52  root_object *c_object;
53  const char *c_name;
54 };
55 
57 
58 static_memory_gremlin::static_memory_gremlin()
59 : c_lock(),
60  c_top_index(0),
61  c_actual_size(0),
62  c_pointers(NULL_POINTER),
63  c_show_debugging(false)
64 {
66 }
67 
69 {
70  __global_program_is_dying = true;
71  // now the rest of the program is on notice; we're practically gone.
72 
73 #ifdef DEBUG_STATIC_MEMORY_GREMLIN
74  if (c_show_debugging)
75  printf("SMG: beginning static object shutdown...\n");
76 #endif
77 
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.
87  c_top_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.
91  if (ptr) {
92 #ifdef DEBUG_STATIC_MEMORY_GREMLIN
93  if (c_show_debugging)
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());
97 #endif
98  WHACK(ptr->c_object);
99  WHACK(ptr);
100  }
101  }
102 #endif
103  delete [] c_pointers;
104  c_pointers = NULL_POINTER;
105 }
106 
107 bool static_memory_gremlin::__program_is_dying() { return __global_program_is_dying; }
108 
110 {
111  static mutex __globabl_synch_mem;
112  return __globabl_synch_mem;
113 }
114 
115 int static_memory_gremlin::locate(const char *unique_name)
116 {
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;
120  }
121  return common::NOT_FOUND;
122 }
123 
124 root_object *static_memory_gremlin::get(const char *unique_name)
125 {
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;
130 }
131 
132 const char *static_memory_gremlin::find(const root_object *ptr)
133 {
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;
138  }
139  return NULL_POINTER;
140 }
141 
142 bool static_memory_gremlin::put(const char *unique_name, root_object *to_put)
143 {
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());
156 #endif
157  WHACK(c_pointers[indy]->c_object);
158  c_pointers[indy]->c_object = to_put;
159  return true;
160  }
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());
166 #endif
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;
171  c_top_index++;
172  return true;
173 }
174 
176 {
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());
183 #endif
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];
187  if (!new_ptr) {
188  throw "error: static_memory_gremlin::ensure_space_exists: failed to allocate memory for pointer list";
189  }
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;
195  }
196 }
197 
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.
205 {
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...
209 
210  if (!_initted) {
211 #ifdef DEBUG_STATIC_MEMORY_GREMLIN
212  printf("%s: initializing HOOPLE_GLOBALS now.\n", _global_argv[0]);
213 #endif
214 
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.
219 #endif
220 
221 #ifdef ENABLE_CALLSTACK_TRACKING
222  program_wide_stack_trace().full_trace_size();
223  // invoke now to get callback tracking instantiated.
224 #endif
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.
229 
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;
239  _initted = true;
240  }
241 
242  return *_internal_gremlin;
243 }
244 
246 
247 } // namespace.
248 
a_sprintf is a specialization of astring that provides printf style support.
Definition: astring.h:440
Provides a dynamically resizable ASCII character string.
Definition: astring.h:35
auto_synchronizer simplifies concurrent code by automatically unlocking.
Definition: mutex.h:113
Holds onto memory chunks that are allocated globally within the program.
bool put(const char *unique_name, basis::root_object *ptr)
adds a "ptr" to the set of static objects under the "unique_name".
basis::root_object * get(const char *unique_name)
locates the pointer held for the "unique_name", if any.
static bool __program_is_dying()
Reports whether the program is shutting down currently.
static static_memory_gremlin & __hoople_globals()
Holds onto objects that have been allocated in a program-wide scope.
static basis::mutex & __memory_gremlin_synchronizer()
private object for static_memory_gremlin's use only.
const char * find(const basis::root_object *ptr)
locates the name for "ptr" in our objects.
#define NULL_POINTER
The value representing a pointer to nothing.
Definition: definitions.h:32
#define FUNCDEF(func_in)
FUNCDEF sets the name of a function (and plugs it into the callstack).
Definition: enhance_cpp.h:57
#define program_wide_memories()
char ** _global_argv
The guards collection helps in testing preconditions and reporting errors.
Definition: array.h:30
void WHACK(contents *&ptr)
deletion with clearing of the pointer.
Definition: functions.h:121
bool non_negative(const type &a)
non_negative returns true if "a" is greater than or equal to zero.
Definition: functions.h:45
bool negative(const type &a)
negative returns true if "a" is less than zero.
Definition: functions.h:43
A dynamic container class that holds any kind of object via pointers.
Definition: amorph.h:55
const int SMG_CHUNKING_FACTOR