first check-in of feisty meow codebase. many things broken still due to recent
[feisty_meow.git] / core / library / structures / static_memory_gremlin.h
1 #ifndef STATIC_MEMORY_GREMLIN_CLASS
2 #define STATIC_MEMORY_GREMLIN_CLASS
3
4 /*****************************************************************************\
5 *                                                                             *
6 *  Name   : static_memory_gremlin                                             *
7 *  Author : Chris Koeritz                                                     *
8 *                                                                             *
9 *******************************************************************************
10 * Copyright (c) 1992-$now By Author.  This program is free software; you can  *
11 * redistribute it and/or modify it under the terms of the GNU General Public  *
12 * License as published by the Free Software Foundation; either version 2 of   *
13 * the License or (at your option) any later version.  This is online at:      *
14 *     http://www.fsf.org/copyleft/gpl.html                                    *
15 * Please send any updates to: fred@gruntose.com                               *
16 \*****************************************************************************/
17
18 #include <basis/contracts.h>
19 #include <basis/enhance_cpp.h>
20 #include <basis/mutex.h>
21
22 namespace structures {
23
24 // forward declarations.
25 class gremlin_object_record;
26
27 //! Holds onto memory chunks that are allocated globally within the program.
28 /*!
29   The objects managed by the gremlin do not get destroyed until after the
30   program begins shutting down.  This file also provides the SAFE_STATIC macros
31   that can be used for allocating static objects safely in a multi-threaded
32   program.
33 */
34
35 class static_memory_gremlin : public virtual basis::nameable
36 {
37 public:
38   static_memory_gremlin();
39
40   ~static_memory_gremlin();
41     /*!< when destroyed, it is assumed that the program's lifetime is over and
42     all objects stored here are now unnecessary.  this implements a
43     regenerative scheme for when static shutdowns occur out of order; if an
44     object has already been destroyed, it is recreated for the purposes of
45     other statics being shutdown.  eventually this should stabilize since
46     it's completely unacceptable for static objects to depend on each other
47     in a cycle. */
48
49   DEFINE_CLASS_NAME("static_memory_gremlin");
50
51   static bool __program_is_dying();
52     //!< Reports whether the program is shutting down currently.
53     /*!< If this flag is true, then code should generally just return without
54     doing anything where possible.  It's especially important for long
55     running loops or active threads to stop if they see this, although
56     the normal program exit processes usually make it unnecessary. */
57
58   static static_memory_gremlin &__hoople_globals();
59     //!< Holds onto objects that have been allocated in a program-wide scope.
60     /*!< These objects will have a lifetime up to the point of normal static
61     object destruction and then they will be cleaned up. */
62
63   static basis::mutex &__memory_gremlin_synchronizer();
64     //!< private object for static_memory_gremlin's use only.
65
66   void enable_debugging(bool verbose) { c_show_debugging = verbose; }
67     //!< if "verbose" is true, then the object will produce a noisy log.
68
69   bool put(const char *unique_name, basis::root_object *ptr);
70     //!< adds a "ptr" to the set of static objects under the "unique_name".
71     /*!< the name must really be unique or objects will collide.  we recommend
72     using an identifier based on a line number and filename where the static
73     is going to be placed (see the safe static implementation below). */
74
75   basis::root_object *get(const char *unique_name);
76     //!< locates the pointer held for the "unique_name", if any.
77     /*!< if no pointer exists, then NIL is returned.  NOTE: the returned
78     pointer must not be destroyed, since the object could be used at any time
79     during the program's lifetime. */
80
81   const char *find(const basis::root_object *ptr);
82     //!< locates the name for "ptr" in our objects.
83     /*!< if it does not exist, then NIL is returned. */
84
85   void ensure_space_exists();
86     /*!< makes sure that the list of objects is large enough to contain all of
87     the identifiers that have been issued. */
88
89 private:
90   basis::mutex c_lock;  //!< protects object's state.
91   int c_top_index;  //!< top place that's occupied in the list.
92   int c_actual_size;  //!< the real number of indices in list.
93   gremlin_object_record **c_pointers;  //!< storage for the static pointers.
94   bool c_show_debugging;  //!< if true, then the object will log noisily.
95
96   int locate(const char *unique_name);
97     //!< returns the index number of the "unique_name".
98 };
99
100 //////////////
101
102 //! Statically defines a singleton object whose scope is the program's lifetime.
103 /*!
104   SAFE_STATIC is a macro that dynamically creates a function returning a particular
105   data type.  the object is allocated statically, so that the same object will be
106   returned ever after until the program is shut down.  the allocation is guarded so
107   that multiple threads cannot create conflicting static objects.
108
109   note: in ms-win32, if you use this macro in a static library (rather than
110   a DLL), then the heap context is different.  thus you could actually have
111   multiple copies of the underlying object.  if the object is supposed to
112   be global and unique, then that's a problem.  relocating the definitions
113   to a dll while keeping declarations in the static lib works (see the
114   program wide logger approach in <application/program_wide_logger.h>).
115     "type" is the object class to return.
116     "func_name" is the function to be created.
117     "parms" must be a list of parameters in parentheses or nothing.
118
119   example usage: @code
120   SAFE_STATIC(connection_table, conntab, (parm1, parm2)) @endcode
121   will define a function: connection_table &conntab()
122   that returns a connection table object which has been created safely,
123   given that the main synchronizer was called from the main thread at least
124   once.  @code
125   SAFE_STATIC(astring, static_string_doodle, ) @endcode
126   will define a static astring object named "static_string_doodle" that uses
127   the default constructor for astrings.
128 */
129 #define SAFE_STATIC(type, func_name, parms) \
130   type &func_name() { SAFE_STATIC_IMPLEMENTATION(type, parms, __LINE__); }
131
132 //! this version returns a constant object instead.
133 #define SAFE_STATIC_CONST(type, func_name, parms) \
134   const type &func_name() \
135   { SAFE_STATIC_IMPLEMENTATION(type, parms, __LINE__); }
136
137 //! Statically defines a string for the rest of the program's life.
138 /*! This macro can be used to make functions returning a string a little
139 simpler.  This can only be used when the string is constant.  The usual way
140 to use this macro is in a function that returns a constant reference to a
141 string.  The macro allocates the string to be returned statically so that all
142 future calls will refer to the stored string rather than recreating it again. */
143 #define STATIC_STRING(str) \
144   SAFE_STATIC_IMPLEMENTATION(astring, (str), __LINE__)
145
146 //////////////
147
148 //! this macro creates a unique const char pointer based on file location.
149 #define UNIQUE_NAME_BASED_ON_SOURCE(name, linenum) \
150   static const char *name = "file:" __FILE__ ":line:" #linenum
151
152 //! this blob is just a chunk of macro implementation for SAFE_STATIC...
153 /*! if the static object isn't initialized yet, we'll create it and store it
154 in the static_memory_gremlin.  we make sure that the program isn't shutting
155 down, because that imposes a new requirement--previously created statics might
156 have already been destroyed.  thus, during the program shutdown, we carefully
157 recreate any objects that were already toast. */
158 #define SAFE_STATIC_IMPLEMENTATION(type, parms, linenum) \
159 /*hmmm: bring all this back.*/ \
160 /*  const char *func = "allocation"; */ \
161 /*  frame_tracking_instance __trail_of_function("safe_static", func, \
162       __FILE__, __LINE__, true); */ \
163   UNIQUE_NAME_BASED_ON_SOURCE(__uid_name, linenum); \
164 /*  program_wide_memories(); */ \
165   static basis::root_object *_hidden = NIL; \
166   /* if haven't initialized yet, then definitely need to lock carefully. */ \
167   if (structures::static_memory_gremlin::__program_is_dying() || !_hidden) { \
168     basis::auto_synchronizer l(structures::static_memory_gremlin::__memory_gremlin_synchronizer()); \
169     if (structures::static_memory_gremlin::__program_is_dying()) { \
170       /* we can't rely on the pointer since we're shutting down currently. */ \
171       _hidden = structures::static_memory_gremlin::__hoople_globals().get(__uid_name); \
172     } \
173     if (!_hidden) {  /* make sure no one scooped us. */ \
174       /* try to retrieve an existing one first and use it if there. */ \
175       _hidden = structures::static_memory_gremlin::__hoople_globals().get(__uid_name); \
176       if (!_hidden) { \
177         _hidden = new type parms ; /* create the object finally. */ \
178         /* store our object using the unique name for it. */ \
179         if (!structures::static_memory_gremlin::__hoople_globals().put(__uid_name, _hidden)) { \
180           /* we failed to allocate space.  this is serious. */ \
181           throw __uid_name; \
182         } \
183       } \
184     } \
185   } \
186   if (!_hidden) { \
187     /* grab the pointer that was stored, in case we're late getting here. */ \
188     /* another thread might have scooped the object creation. */ \
189     _hidden = structures::static_memory_gremlin::__hoople_globals().get(__uid_name); \
190   } \
191   return *dynamic_cast<type *>(_hidden)
192
193 // historical note: the SAFE_STATIC approach has existed since about 1998.
194 // however, the static_memory_gremlin's role in this started much later.
195
196 } //namespace.
197
198 #endif
199