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>
19 //temp! needed for fake continuable error etc
20 
21 #include <stdio.h>
22 #include <string.h>
23 
24 using namespace application;
25 using namespace basis;
26 
27 namespace structures {
28 
29 //#define DEBUG_STATIC_MEMORY_GREMLIN
30  // comment this out to eliminate debugging print-outs. otherwise they
31  // are controlled by the class interface.
32 
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.
37 
39 
40 const int SMG_CHUNKING_FACTOR = 32;
41  // we'll allocate this many indices at a time.
42 
44 
45 static bool __global_program_is_dying = false;
46  // this is set to true when no more logging or access to static objects
47  // should be allowed.
48 
50 
51 class gremlin_object_record
52 {
53 public:
54  root_object *c_object;
55  const char *c_name;
56 };
57 
59 
60 static_memory_gremlin::static_memory_gremlin()
61 : c_lock(),
62  c_top_index(0),
63  c_actual_size(0),
64  c_pointers(NULL_POINTER),
65  c_show_debugging(false)
66 {
68 }
69 
71 {
72  __global_program_is_dying = true;
73  // now the rest of the program is on notice; we're practically gone.
74 
75 #ifdef DEBUG_STATIC_MEMORY_GREMLIN
76  if (c_show_debugging)
77  printf("SMG: beginning static object shutdown...\n");
78 #endif
79 
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] = NULL_POINTER;
88  // since we know the one we're zapping, we no longer need that index.
89  c_top_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.
93  if (ptr) {
94 #ifdef DEBUG_STATIC_MEMORY_GREMLIN
95  if (c_show_debugging)
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());
99 #endif
100  WHACK(ptr->c_object);
101  WHACK(ptr);
102  }
103  }
104 #endif
105  delete [] c_pointers;
106  c_pointers = NULL_POINTER;
107 }
108 
109 bool static_memory_gremlin::__program_is_dying() { return __global_program_is_dying; }
110 
112 {
113  static mutex __global_synch_mem;
114  return __global_synch_mem;
115 }
116 
117 int static_memory_gremlin::locate(const char *unique_name)
118 {
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;
122  }
123  return common::NOT_FOUND;
124 }
125 
126 root_object *static_memory_gremlin::get(const char *unique_name)
127 {
128  auto_synchronizer l(c_lock);
129  int indy = locate(unique_name);
130  if (negative(indy)) return NULL_POINTER;
131  return c_pointers[indy]->c_object;
132 }
133 
134 const char *static_memory_gremlin::find(const root_object *ptr)
135 {
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;
140  }
141  return NULL_POINTER;
142 }
143 
144 bool static_memory_gremlin::put(const char *unique_name, root_object *to_put)
145 {
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());
158 #endif
159  WHACK(c_pointers[indy]->c_object);
160  c_pointers[indy]->c_object = to_put;
161  return true;
162  }
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());
168 #endif
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;
173  c_top_index++;
174  return true;
175 }
176 
178 {
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());
185 #endif
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];
189  if (!new_ptr) {
190  throw "error: static_memory_gremlin::ensure_space_exists: failed to allocate memory for pointer list";
191  }
192  for (int i = 0; i < c_actual_size; i++) new_ptr[i] = NULL_POINTER;
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;
197  }
198 }
199 
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.
207 {
208  static bool _initted = false; // tells whether we've gone through yet.
209  static static_memory_gremlin *_internal_gremlin = NULL_POINTER;
210  // holds our list of shared pieces...
211 
212  if (!_initted) {
213 #ifdef DEBUG_STATIC_MEMORY_GREMLIN
214  printf("%s: initializing HOOPLE_GLOBALS now.\n", _global_argv[0]);
215 #endif
216 
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.
221 #endif
222 
223 #ifdef ENABLE_CALLSTACK_TRACKING
225  // invoke now to get callback tracking instantiated.
226 #endif
227 
228  FUNCDEF("HOOPLE_GLOBALS remainder");
229  // this definition must be postponed until after the objects that would
230  // track it actually exist.
231  if (func) {} // shut up the compiler about using it.
232 
233  // this simple approach is not going to succeed if the SAFE_STATIC macros
234  // are used in a static library which is then used in more than one dynamic
235  // library on win32. this is because each dll in win32 will have a
236  // different version of certain static objects that should only occur once
237  // per program. this problem is due to the win32 memory model, but in
238  // hoople at least this has been prevented; our only static library that
239  // appears in a bunch of dlls is basis and it is not allowed to use the
240  // SAFE_STATIC macro.
241  _internal_gremlin = new static_memory_gremlin;
242  _initted = true;
243  }
244 
245  return *_internal_gremlin;
246 }
247 
249 
250 } // namespace.
251 
int full_trace_size() const
this returns an estimated number of bytes needed for the full_trace().
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:54
#define program_wide_memories()
Implements an application lock to ensure only one is running at once.
callstack_tracker & thread_wide_stack_trace()
the single instance of callstack_tracker.
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