Lumiera  0.pre.03
»edit your freedom«
allocation-cluster.cpp
Go to the documentation of this file.
1 /*
2  AllocationCluster - allocating and owning a pile of objects
3 
4  Copyright (C) Lumiera.org
5  2008, Hermann Vosseler <Ichthyostega@web.de>
6 
7  This program is free software; you can redistribute it and/or
8  modify it under the terms of the GNU General Public License as
9  published by the Free Software Foundation; either version 2 of
10  the License, or (at your option) any later version.
11 
12  This program is distributed in the hope that it will be useful,
13  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  GNU General Public License for more details.
16 
17  You should have received a copy of the GNU General Public License
18  along with this program; if not, write to the Free Software
19  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 
21 * *****************************************************/
22 
23 
33 #include "lib/error.hpp"
34 #include "lib/util.hpp"
35 #include "lib/sync.hpp"
36 
37 #include <deque>
38 
39 using util::isnil;
40 
41 
42 namespace lib {
43 
69  : public Sync<RecursiveLock_NoWait>
70  {
71  typedef std::deque<char*> MemTable;
72  TypeInfo type_;
73  MemTable mem_;
74  size_t top_;
75 
76  public:
77  MemoryManager(TypeInfo info) : top_(0) { reset(info); }
78  ~MemoryManager() { purge(); }
79 
80  size_t size() const;
81 
82  void purge();
83  void reset(TypeInfo info);
84 
85  void* allocate();
86 
87  void commit (void* pendingAlloc);
88 
89  private:
90  void clearStorage();
91  };
92 
93 
94 
99  size_t
101  {
102  return top_;
103  }
104 
105 
106  void
107  AllocationCluster::MemoryManager::reset (TypeInfo info)
108  {
109  Lock sync{this};
110 
111  if (0 < mem_.size()) purge();
112  type_ = info;
113 
114  ENSURE (0==top_);
115  ENSURE (isnil (mem_));
116  ENSURE (0 < type_.allocSize);
117  ENSURE (type_.killIt);
118  }
119 
120 
121  void
122  AllocationCluster::MemoryManager::purge()
123  {
124  Lock sync{this};
125 
126  REQUIRE (type_.killIt, "we need a deleter function");
127  REQUIRE (0 < type_.allocSize, "allocation size unknown");
128  REQUIRE (top_ == mem_.size() || (top_+1) == mem_.size());
129 
130  while (top_)
131  type_.killIt (mem_[--top_]);
132  clearStorage();
133  }// note: unnecessary to kill pending allocations
134 
135 
136  inline void
137  AllocationCluster::MemoryManager::clearStorage()
138  {
139  for (size_t i=mem_.size(); 0 < i; )
140  delete[] mem_[--i];
141  mem_.clear();
142  }
143 
144 
145  inline void*
146  AllocationCluster::MemoryManager::allocate()
147  {
148  Lock sync{this};
149 
150  REQUIRE (0 < type_.allocSize);
151  REQUIRE (top_ <= mem_.size());
152 
153  if (top_==mem_.size())
154  mem_.resize(top_+1);
155 
156  if (!mem_[top_]) // re-use existing allocation, if any
157  mem_[top_] = new char[type_.allocSize];
158 
159  ENSURE (top_ < mem_.size());
160  ENSURE (mem_[top_]);
161  return mem_[top_];
162  }
163 
164 
165  inline void
166  AllocationCluster::MemoryManager::commit (void* pendingAlloc)
167  {
168  Lock sync{this};
169 
170  REQUIRE (pendingAlloc);
171  ASSERT (top_ < mem_.size());
172  ASSERT (pendingAlloc == mem_[top_], "allocation protocol violated");
173 
174  ++top_;
175 
176  ENSURE (top_ == mem_.size());
177  }
178 
179 
180 
183 
184 
190  {
191  TRACE (memory, "new AllocationCluster");
192  }
193 
194 
200  {
201  try
202  { // avoiding a per-instance lock for now.
203  ClassLock<AllocationCluster> guard; // (see note in the class description)
204 
205  TRACE (memory, "shutting down AllocationCluster");
206  for (size_t i = typeHandlers_.size(); 0 < i; --i)
207  if (handler(i))
208  handler(i)->purge();
209 
210  typeHandlers_.clear();
211 
212  }
213  catch (lumiera::Error & ex)
214  {
215  WARN (progress, "Exception while closing AllocationCluster: %s", ex.what());
216  const char* errID = lumiera_error();
217  TRACE (debugging, "Error flag was: %s", errID);
218  }
219  catch (...)
220  {
221  ALERT (progress, "Unexpected fatal Exception while closing AllocationCluster.");
222  lumiera::error::lumiera_unexpectedException(); // terminate
223  }
224  }
225 
226 
227 
228  void*
230  {
231  if (!slot or slot > typeHandlers_.size() or !handler(slot) )
232  return nullptr; // Memory manager not yet initialised
233  else
234  return handler(slot)->allocate();
235  }
236 
237 
238  void*
239  AllocationCluster::initiateAlloc (TypeInfo type, size_t& slot)
240  {
241  ASSERT (0 < slot);
242 
243  { // avoiding a per-instance lock for now.
244  ClassLock<AllocationCluster> guard; // (see note in the class description)
245 
246  if (slot > typeHandlers_.size())
247  typeHandlers_.resize(slot);
248  if (not handler(slot))
249  handler(slot).reset (new MemoryManager (type));
250 
251  }
252 
253  ASSERT (handler(slot));
254  return initiateAlloc(slot);
255  }
256 
257 
258  void
259  AllocationCluster::finishAlloc (size_t& slot, void* allocatedObj)
260  {
261  ASSERT (handler(slot));
262  ASSERT (allocatedObj);
263 
264  handler(slot)->commit(allocatedObj);
265  }
266 
267 
268  /* === diagnostics helpers === */
269 
272  size_t
274  {
275  size_t size(0);
276  typedef ManagerTable::const_iterator Iter;
277 
278  for (Iter ii= typeHandlers_.begin(); ii != typeHandlers_.end(); ++ii )
279  if (*ii)
280  size += (*ii)->size();
281 
282  return size;
283  }
284 
285 
286  size_t
288  {
289  if (handler (slot))
290  return handler(slot)->size();
291  else
292  return 0;
293  }
294 
295 
296 
297 } // namespace lib
Facility for monitor object based locking.
Definition: sync.hpp:217
static size_t maxTypeIDs
storage for static bookkeeping of type allocation slots
void finishAlloc(size_t &slot, void *)
enrol the allocation after successful ctor call
size_t size() const
the top_ index always points at the next slot not yet holding a finished, committed allocation...
size_t top_
index of the next slot available for allocation
Memory management for the low-level model (render nodes network).
void(* killIt)(void *)
deleter function
virtual CStr what() const noexcept override
std::exception interface : yield a diagnostic message
Implementation namespace for support and library code.
Object Monitor based synchronisation.
size_t countActiveInstances(size_t &slot) const
Tiny helper functions and shortcuts to be used everywhere Consider this header to be effectively incl...
void * initiateAlloc(size_t &slot)
implementation of the actual memory allocation is pushed down to the MemoryManager impl...
lumiera_err lumiera_error(void)
Get and clear current error state.
Definition: error-state.c:124
ManagerTable typeHandlers_
table of active MemoryManager instances
Lumiera error handling (C++ interface).
A synchronisation protection guard employing a lock scoped to the parameter type as a whole...
"Low-level" Memory manager for allocating small objects of a fixed size.
Interface and Base definition for all Lumiera Exceptions.
Definition: error.hpp:71
~AllocationCluster() noexcept
On shutdown of the AllocationCluster we need to assure a certain destruction order is maintained by e...
AllocationCluster()
creating a new AllocationCluster prepares a table capable of holding the individual object families t...