00001 #ifndef STATIC_MEMORY_GREMLIN_IMPLEMENTATION_FILE
00002 #define STATIC_MEMORY_GREMLIN_IMPLEMENTATION_FILE
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #include "static_memory_gremlin.h"
00019
00020 #include <basis/array.cpp>
00021 #include <basis/byte_array.h>
00022 #include <basis/function.h>
00023 #include <basis/guards.h>
00024 #include <basis/mutex.h>
00025 #include <basis/object_base.h>
00026 #include <basis/set.cpp>
00027
00028 #include <stdio.h>
00029
00030
00031
00032 #include <loggers/file_logger.h>
00033 #include <loggers/locked_logger.h>
00034 #include <loggers/null_logger.h>
00035
00036 #define static_class_name() "static_memory_gremlin"
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047 const char *_EXCEPTION_INFO_FOR_SHUTTING_DOWN
00048 = "Function must return immediately because program is shutting down.";
00049
00050 static bool _program_is_dying = false;
00051
00052
00053
00054 bool DATA_STRUCTURE_FUNCTION_STYLE program_is_dying() { return _program_is_dying; }
00055
00056 const char DATA_STRUCTURE_FUNCTION_STYLE *EXCEPTION_INFO_FOR_SHUTTING_DOWN()
00057 { return _EXCEPTION_INFO_FOR_SHUTTING_DOWN; }
00058
00059 const byte_array BASIS_EXTERN &__byte_array_empty_array()
00060 {
00061 static byte_array __hidden_byte_array;
00062 return __hidden_byte_array;
00063 }
00064
00065 const istring BASIS_EXTERN &__istring_empty_string()
00066 {
00067 static istring __hidden_empty_string;
00068 return __hidden_empty_string;
00069 }
00070
00072
00073 const int SMG_CHUNKING_FACTOR = 32;
00074
00075
00076 class object_base_record
00077 {
00078 public:
00079 object_base *_object;
00080 const char *_name;
00081 };
00082
00083 static_memory_gremlin::static_memory_gremlin()
00084 : _lock(new mutex),
00085 _top_index(0),
00086 _actual_size(0),
00087 _pointers_held(NIL),
00088 _show_debugging(false)
00089 {
00090 ensure_space_exists();
00091 }
00092
00093 static_memory_gremlin::~static_memory_gremlin()
00094 {
00095 _program_is_dying = true;
00096
00097
00098 if (!program_is_dying()) {
00099 non_continuable_error("static_memory_gremlin", "destructor",
00100 "program is not in dying state; this is a grievous error.");
00101 }
00102 #ifdef DEBUG_STATIC_MEMORY_GREMLIN
00103 if (_show_debugging)
00104 printf("SMG: beginning static object shutdown...\n");
00105 #endif
00106
00107 #ifndef SKIP_STATIC_CLEANUP
00108
00109 while (_top_index > 0) {
00110
00111
00112 int zapped_index = _top_index - 1;
00113 object_base_record *ptr = _pointers_held[zapped_index];
00114 _pointers_held[zapped_index] = NIL;
00115
00116 _top_index--;
00117
00118
00119
00120 if (ptr) {
00121 #ifdef DEBUG_STATIC_MEMORY_GREMLIN
00122 if (_show_debugging)
00123 printf((istring("SMG: deleting ") + ptr->_object->instance_name()
00124 + " called " + ptr->_name
00125 + isprintf(" at index %d.\n", zapped_index) ).s());
00126 #endif
00127 WHACK(ptr->_object);
00128 WHACK(ptr);
00129 }
00130 }
00131 #endif
00132 delete [] _pointers_held;
00133 _pointers_held = NIL;
00134 delete _lock;
00135 _lock = NIL;
00136 }
00137
00138 int static_memory_gremlin::locate(const char *unique_name)
00139 {
00140 auto_synchronizer l(*_lock);
00141 for (int i = 0; i < _top_index; i++) {
00142 if (!strcmp(_pointers_held[i]->_name, unique_name)) return i;
00143 }
00144 return common::NOT_FOUND;
00145 }
00146
00147 object_base *static_memory_gremlin::get(const char *unique_name)
00148 {
00149 auto_synchronizer l(*_lock);
00150 int indy = locate(unique_name);
00151 if (negative(indy)) return NIL;
00152 return _pointers_held[indy]->_object;
00153 }
00154
00155 const char *static_memory_gremlin::find(const object_base *ptr)
00156 {
00157 auto_synchronizer l(*_lock);
00158 for (int i = 0; i < _top_index; i++) {
00159 if (ptr == _pointers_held[i]->_object)
00160 return _pointers_held[i]->_name;
00161 }
00162 return NIL;
00163 }
00164
00165 bool static_memory_gremlin::put(const char *unique_name, object_base *to_put)
00166 {
00167 auto_synchronizer l(*_lock);
00168 int indy = locate(unique_name);
00169
00170 if (non_negative(indy)) {
00171 #ifdef DEBUG_STATIC_MEMORY_GREMLIN
00172 if (_show_debugging)
00173 printf((istring("SMG: cleaning out old object ")
00174 + _pointers_held[indy]->_object->instance_name()
00175 + " called " + _pointers_held[indy]->_name
00176 + " in favor of object " + to_put->instance_name()
00177 + " called " + unique_name
00178 + isprintf(" at index %d.\n", indy)).s());
00179 #endif
00180 WHACK(_pointers_held[indy]->_object);
00181 _pointers_held[indy]->_object = to_put;
00182 return true;
00183 }
00184 #ifdef DEBUG_STATIC_MEMORY_GREMLIN
00185 if (_show_debugging)
00186 printf((istring("SMG: storing ") + to_put->instance_name()
00187 + " called " + unique_name
00188 + isprintf(" at index %d.\n", _top_index)).s());
00189 #endif
00190 ensure_space_exists();
00191 _pointers_held[_top_index] = new object_base_record;
00192 _pointers_held[_top_index]->_object = to_put;
00193 _pointers_held[_top_index]->_name = unique_name;
00194 _top_index++;
00195 return true;
00196 }
00197
00198 void static_memory_gremlin::ensure_space_exists()
00199 {
00200 auto_synchronizer l(*_lock);
00201 if (!_pointers_held || (_top_index + 1 >= _actual_size) ) {
00202
00203 #ifdef DEBUG_STATIC_MEMORY_GREMLIN
00204 if (_show_debugging)
00205 printf(isprintf("SMG: adding space for top at %d.\n", _top_index).s());
00206 #endif
00207 _actual_size += SMG_CHUNKING_FACTOR;
00208 typedef object_base_record *base_ptr;
00209 object_base_record **new_ptr = new base_ptr[_actual_size];
00210 if (!new_ptr) {
00211 non_continuable_error("static_memory_gremlin", "ensure_space_exists",
00212 "failed to allocate memory for pointer list");
00213 }
00214 for (int i = 0; i < _actual_size; i++) new_ptr[i] = NIL;
00215 for (int j = 0; j < _actual_size - SMG_CHUNKING_FACTOR; j++)
00216 new_ptr[j] = _pointers_held[j];
00217 if (_pointers_held) delete [] _pointers_held;
00218 _pointers_held = new_ptr;
00219 }
00220 }
00221
00222
00223
00224
00225
00226
00227
00228 static_memory_gremlin &HOOPLE_GLOBALS()
00229 {
00230 static bool _initted = false;
00231 static static_memory_gremlin *_internal_gremlin = NIL;
00232
00233
00234 if (!_initted) {
00235 #ifdef DEBUG_STATIC_MEMORY_GREMLIN
00236 printf("%s: initializing HOOPLE_GLOBALS now.\n", __argv[0]);
00237 #endif
00238
00239 #ifdef ENABLE_MEMORY_HOOK
00240 void *temp = program_wide_memories().provide_memory(1, __FILE__, __LINE__);
00241
00242 program_wide_memories().release_memory(temp);
00243 #endif
00244
00245 #ifdef ENABLE_CALLSTACK_TRACKING
00246 program_wide_stack_trace().full_trace_size();
00247
00248 #endif
00249 FUNCDEF("HOOPLE_GLOBALS remainder");
00250
00251
00252
00253
00254
00255
00256
00257
00258
00259
00260
00261 _internal_gremlin = new static_memory_gremlin;
00262 _initted = true;
00263 }
00264
00265 return *_internal_gremlin;
00266 }
00267
00269
00270
00271
00272 #ifdef ENABLE_MEMORY_HOOK
00273
00274 static memory_checker *__exposed_hidden_memories = NIL;
00275
00276
00277
00278 void hoople_atexit()
00279 {
00280 if (__exposed_hidden_memories) {
00281 __exposed_hidden_memories->destruct();
00282
00283 __exposed_hidden_memories = NIL;
00284 }
00285 }
00286
00288
00294 memory_checker BASIS_EXTERN &program_wide_memories()
00295 {
00296 static memory_checker *_hidden_memories = NIL;
00297 if (!_hidden_memories) {
00298 static bool _already_here = false;
00299 if (_already_here) {
00300 printf("logic error in program_wide_memories: invoked after shutdown\n");
00301 abort();
00302 }
00303 _already_here = true;
00304
00305 _hidden_memories = (memory_checker *)malloc(sizeof(memory_checker));
00306 _hidden_memories->construct();
00307
00308 __exposed_hidden_memories = _hidden_memories;
00309
00310 atexit(hoople_atexit);
00311 }
00312 return *_hidden_memories;
00313
00314
00315
00316 }
00317
00318 #endif
00319
00321
00322
00323
00324 #ifdef ENABLE_CALLSTACK_TRACKING
00325
00327
00334 callstack_tracker BASIS_EXTERN &program_wide_stack_trace()
00335 {
00336 static callstack_tracker *_hidden_trace = NIL;
00337 if (!_hidden_trace) {
00338 #ifdef ENABLE_MEMORY_HOOK
00339 program_wide_memories().disable();
00340
00341
00342 #endif
00343 _hidden_trace = new callstack_tracker;
00344 #ifdef ENABLE_MEMORY_HOOK
00345 program_wide_memories().enable();
00346 #endif
00347 }
00348 return *_hidden_trace;
00349 }
00350
00351 #endif
00352
00354
00355 library_wide_cleanup::library_wide_cleanup()
00356 : _shared_chunks(&HOOPLE_GLOBALS())
00357 {
00358 __memory_gremlin_synchronizer();
00359
00360
00361
00362
00363
00364
00365
00366
00367
00368
00369
00370 istring::empty_string();
00371 byte_array::empty_array();
00372 }
00373
00374 library_wide_cleanup::~library_wide_cleanup() {}
00375
00376
00378
00379 program_wide_cleanup::program_wide_cleanup()
00380 {
00381
00382
00383 chaos().retrain();
00384 #ifndef OMIT_PROGRAM_WIDE_LOGGER
00385
00386
00387 SET_DEFAULT_COMBO_LOGGER;
00388 #endif
00389 }
00390
00391 program_wide_cleanup::~program_wide_cleanup()
00392 {
00393 #ifndef OMIT_PROGRAM_WIDE_LOGGER
00394 if (real_program_wide_logger().established()) {
00395 SET_DEFAULT_NULL_LOGGER;
00396
00397
00398
00399
00400 }
00401 #endif
00402
00403
00404 static_memory_gremlin *shared = &HOOPLE_GLOBALS();
00405
00406 WHACK(shared);
00407 }
00408
00410
00411
00412
00413
00414
00415
00416 mutex &__memory_gremlin_synchronizer()
00417 {
00418 const char *hoople_static_name
00419 = ":" __FILE__ ":" "only___memory_gremlin_synch" ":";
00420 static mutex *_hidden_mutt = dynamic_cast<mutex *>
00421 (HOOPLE_GLOBALS().get(hoople_static_name));
00422 if (!_hidden_mutt) {
00423 _hidden_mutt = new mutex;
00424 HOOPLE_GLOBALS().put(hoople_static_name, _hidden_mutt);
00425 }
00426 return *_hidden_mutt;
00427 }
00428
00429 int_set BASIS_EXTERN &__our_kids()
00430 { SAFE_STATIC_IMPLEMENTATION(int_set, , __LINE__); }
00431
00432 mutex BASIS_EXTERN &__uptime_synchronizer()
00433 { SAFE_STATIC_IMPLEMENTATION(mutex, , __LINE__); }
00434
00435 mutex BASIS_EXTERN &__process_synchronizer()
00436 { SAFE_STATIC_IMPLEMENTATION(mutex, , __LINE__); }
00437
00439
00440 #undef static_class_name
00441
00442 #endif //STATIC_MEMORY_GREMLIN_IMPLEMENTATION_FILE