startup_code.cpp

Go to the documentation of this file.
00001 #ifndef STARTUP_CODE_IMPLEMENTATION_FILE
00002 #define STARTUP_CODE_IMPLEMENTATION_FILE
00003 
00004 /*****************************************************************************\
00005 *                                                                             *
00006 *  Name   : hoople startup support                                            *
00007 *  Author : Chris Koeritz                                                     *
00008 *                                                                             *
00009 *******************************************************************************
00010 * Copyright (c) 1994-$now By Author.  This program is free software; you can  *
00011 * redistribute it and/or modify it under the terms of the GNU General Public  *
00012 * License as published by the Free Software Foundation; either version 2 of   *
00013 * the License or (at your option) any later version.  This is online at:      *
00014 *     http://www.fsf.org/copyleft/gpl.html                                    *
00015 * Please send any updates to: fred@gruntose.com                               *
00016 \*****************************************************************************/
00017 
00018 #include "critical_events.h"
00019 #include "path_configuration.h"
00020 #include "startup_code.h"
00021 #ifndef OMIT_PROGRAM_WIDE_LOGGER
00022   #include "console_logger.h"
00023   #include "file_logger.h"
00024   #include "locked_logger.h"
00025   #include "null_logger.h"
00026 #endif
00027 #include "system_values.h"
00028 
00029 #include <basis/byte_array.h>
00030 #include <basis/chaos.h>
00031 #include <basis/guards.h>
00032 #include <basis/istring.h>
00033 #include <basis/memory_checker.h>
00034 #include <data_struct/static_memory_gremlin.h>
00035 
00036 #include <stdio.h>
00037 #include <stdlib.h>
00038 #include <memory.h>
00039 
00040 //#define DEBUG_STARTUP_CODE
00041   // uncomment for additional checks and noises.
00042 
00043 #ifdef DEBUG_STARTUP_CODE
00044   #include <stdio.h>
00045 #endif
00046 
00047 #define static_class_name() "startup_code"
00048 
00050 
00051 namespace startup_code {
00052   const char *_EXCEPTION_INFO_FOR_SHUTTING_DOWN
00053       = "Function must return immediately because program is shutting down.";
00054   static bool _program_is_dying = false;
00055     // this is set to true when no more logging or access to static objects
00056     // should be allowed.
00057 
00058   bool BASIS_EXTERN program_is_dying() { return _program_is_dying; }
00059 
00060   const char BASIS_EXTERN *EXCEPTION_INFO_FOR_SHUTTING_DOWN()
00061   { return _EXCEPTION_INFO_FOR_SHUTTING_DOWN; }
00062 }
00063 
00065 
00066 #ifdef ENABLE_MEMORY_HOOK
00067 
00068 static memory_checker *__exposed_hidden_memories = NIL;
00069   // set once the real memory object is created below.  not to be used by
00070   // anyone else besides the atexit method.
00071 
00072 void hoople_atexit()
00073 {
00074   if (__exposed_hidden_memories) {
00075     __exposed_hidden_memories->destruct();
00076       // this renders the object useless but leaves it able to alloc/dealloc.
00077     __exposed_hidden_memories = NIL;
00078   }
00079 }
00080 
00082 
00084 
00090 memory_checker BASIS_EXTERN &program_wide_memories()
00091 {
00092   static memory_checker *_hidden_memories = NIL;
00093   if (!_hidden_memories) {
00094     static bool _already_here = false;
00095     if (_already_here) {
00096       printf("logic error in program_wide_memories: invoked after shutdown\n");
00097       abort();
00098     }
00099     _already_here = true;
00100 
00101     _hidden_memories = (memory_checker *)malloc(sizeof(memory_checker));
00102     _hidden_memories->construct();
00103     // we make an external copy of our internal object here.
00104     __exposed_hidden_memories = _hidden_memories;
00105     // register a program shutdown handler to report leaks.
00106     atexit(hoople_atexit); 
00107   }
00108   return *_hidden_memories;
00109     // there will be at least one reported memory leak if this program is
00110     // analyzed with external tools; the hidden memories pointer is never
00111     // deallocated here.
00112 }
00113 
00114 #endif
00115 
00117 
00118 #ifdef ENABLE_CALLSTACK_TRACKING
00119 
00121 
00128 callstack_tracker BASIS_EXTERN &program_wide_stack_trace()
00129 {
00130   static callstack_tracker *_hidden_trace = NIL;
00131   if (!_hidden_trace) {
00132 #ifdef ENABLE_MEMORY_HOOK
00133     program_wide_memories().disable();
00134       // we don't want infinite loops tracking the call stack during this
00135       // object's construction.
00136 #endif
00137     _hidden_trace = new callstack_tracker;
00138 #ifdef ENABLE_MEMORY_HOOK
00139     program_wide_memories().enable();
00140 #endif
00141   }
00142   return *_hidden_trace;
00143 }
00144 
00145 #endif
00146 
00148 
00149 locked_logger OPSYSTEM_FUNCTION_STYLE &real_program_wide_logger()
00150 {
00151   SAFE_STATIC_IMPLEMENTATION(locked_logger, , __LINE__);
00152 }
00153 
00154 #ifndef OMIT_PROGRAM_WIDE_LOGGER
00155 // provides the more generic version of the real logger.
00156 log_base OPSYSTEM_FUNCTION_STYLE &program_wide_logger()
00157 {
00158   if (!real_program_wide_logger().established()) {
00159     SET_DEFAULT_NULL_LOGGER;
00160     critical_events::write_to_critical_events((timestamp(true, true)
00161         + "the program-wide logger isn't set!").s());
00162   }
00163   return real_program_wide_logger(); 
00164 }
00165 
00166 log_base OPSYSTEM_FUNCTION_STYLE *retask_program_wide_logger
00167     (log_base *new_logger)
00168 {
00169   return real_program_wide_logger().swap(new_logger);
00170 }
00171 #endif
00172 
00174 
00175 namespace startup_code {
00176 
00177 // this function ensures that the space for the global objects is kept until
00178 // the program goes away.  if it's the first time through, then the gremlin
00179 // gets created; otherwise the existing one is used.  this function should
00180 // always be called by the main program before any attempts to use global
00181 // features like SAFE_STATIC or the program wide logger.  it is crucial that no
00182 // user-level threads have been created in the program before this is called.
00183 static_memory_gremlin &HOOPLE_GLOBALS()
00184 {
00185   static bool _initted = false;  // tells whether we've gone through yet.
00186   static static_memory_gremlin *_internal_gremlin = NIL;
00187     // holds our list of shared pieces...
00188 
00189   if (!_initted) {
00190 #ifdef DEBUG_STARTUP_CODE
00191     printf("%s: initializing HOOPLE_GLOBALS now.\n", __argv[0]); 
00192 #endif
00193 
00194 #ifdef ENABLE_MEMORY_HOOK
00195     void *temp = program_wide_memories().provide_memory(1, __FILE__, __LINE__);
00196       // invoke now to get memory engine instantiated.
00197     program_wide_memories().release_memory(temp);  // clean up junk.
00198 #endif
00199 
00200 #ifdef ENABLE_CALLSTACK_TRACKING
00201     program_wide_stack_trace().full_trace_size();
00202       // invoke now to get callback tracking instantiated.
00203 #endif
00204     FUNCDEF("HOOPLE_GLOBALS remainder");
00205       // this definition must be postponed until after the objects that would
00206       // track it actually exist.
00207 
00208     // this simple approach is not going to succeed if the SAFE_STATIC macros
00209     // are used in a static library which is then used in more than one dynamic
00210     // library on win32.  this is because each dll in win32 will have a
00211     // different version of certain static objects that should only occur once
00212     // per program.  this problem is due to the win32 memory model, but in
00213     // hoople at least this has been prevented; our only static library that
00214     // appears in a bunch of dlls is basis and it is not allowed to use the
00215     // SAFE_STATIC macro.
00216     _internal_gremlin = new static_memory_gremlin;
00217     _initted = true;
00218   }
00219 
00220   return *_internal_gremlin;
00221 }
00222 
00224 
00225 library_wide_cleanup::library_wide_cleanup()
00226 : _shared_chunks(&HOOPLE_GLOBALS())  // create the memory chunk if needed.
00227 {
00228   startup_code::__memory_gremlin_synchronizer();
00229     // invoke this at least once; this is our most critical synchro primitive.
00230 
00231   // these force static objects in the statically linked basis library to be
00232   // created properly on win32.  we want to ensure that the wacky memory
00233   // context of a static library's statics are set up properly for use in each
00234   // dynamic library, since there seem to be a separate static heap context in
00235   // each DLL.  that poses a problem in general for more complex objects if
00236   // they are contained in a widely-used static library.  basis is the only
00237   // real case of that in our system, and it's been reduced down to just the
00238   // following statics (which are wrapped in creator methods).
00239 //hmmm: get these back to being exported from opsys instead; singletons.
00240   istring::empty_string();
00241   byte_array::empty_array();
00242 }
00243 
00244 library_wide_cleanup::~library_wide_cleanup() {}
00245   // nothing here yet.
00246 
00248 
00249 program_wide_cleanup::program_wide_cleanup()
00250 {
00251   // reset the random number seed.  we only do this once during startup
00252   // although anyone can reset it again later.
00253   chaos().retrain();
00254 #ifndef OMIT_PROGRAM_WIDE_LOGGER
00255   // assume we're okay by creating a file + console logger until they decide
00256   // to set up a different type.
00257   SET_DEFAULT_COMBO_LOGGER;
00258 #endif
00259 }
00260 
00261 program_wide_cleanup::~program_wide_cleanup()
00262 {
00263 #ifndef OMIT_PROGRAM_WIDE_LOGGER
00264   if (real_program_wide_logger().established()) {
00265     SET_DEFAULT_NULL_LOGGER;
00266       // reset to a non-asynchronous logger.  if a logger that's busy in the
00267       // background (like the uls) is hooked in here, it could still be trying
00268       // to deliver sends while the program is trying to shut down.  we just
00269       // ensure it gets closed before much more of static shutdown happens.
00270   }
00271 #endif
00272 
00273   // remove our shared segments.
00274   static_memory_gremlin *shared = &HOOPLE_GLOBALS();
00275 
00276   _program_is_dying = true;
00277     // now the rest of the program is on notice; we're practically gone.
00278 
00279   WHACK(shared);  // now really remove the object.
00280 }
00281 
00283 
00284 // internal secret below: we are always planning on this function being called
00285 // before any other functions that use it, and this object should always exist
00286 // for program-wide synchronization needs, so we just assume it is safe to
00287 // always take the zeroth identifier/slot from the gremlin.  we do this
00288 // because the SAFE_STATIC macros actually use the private synchronizer.
00289 mutex &__memory_gremlin_synchronizer()
00290 {
00291   const char *hoople_static_name
00292       = ":" __FILE__ ":" "only___memory_gremlin_synch" ":";
00293   static mutex *_hidden_mutt = dynamic_cast<mutex *>
00294       (HOOPLE_GLOBALS().get(hoople_static_name));
00295   if (!_hidden_mutt) {
00296     _hidden_mutt = new mutex;
00297     HOOPLE_GLOBALS().put(hoople_static_name, _hidden_mutt);
00298   }
00299   return *_hidden_mutt;
00300 }
00301 
00302 mutex &__uptime_synchronizer()
00303 { SAFE_STATIC_IMPLEMENTATION(mutex, , __LINE__); }
00304 
00305 mutex &__process_synchronizer()
00306 { SAFE_STATIC_IMPLEMENTATION(mutex, , __LINE__); }
00307 
00308 } // namespace
00309 
00311 
00312 // we hide our static methods from basis here, since we do not want to
00313 // see multiple instances of these (one per dll in windows).
00314 
00315 const byte_array &startup_code::byte_array_empty_array()
00316 {
00317   static byte_array __hidden_byte_array;
00318   return __hidden_byte_array;
00319 }
00320 
00321 const istring &startup_code::istring_empty_string()
00322 {
00323   static istring __hidden_empty_string;
00324   return __hidden_empty_string;
00325 }
00326 
00327 #undef static_class_name
00328 
00329 
00330 #endif //STARTUP_CODE_IMPLEMENTATION_FILE
00331 

Generated on Mon Jan 14 04:31:07 2008 for HOOPLE Libraries by  doxygen 1.5.1