Lumiera  0.pre.03
»edit your freedom«
tracking-heap-block-provider.cpp
Go to the documentation of this file.
1 /*
2  TrackingHeapBlockProvider - plain heap allocating BufferProvider implementation for tests
3 
4  Copyright (C) Lumiera.org
5  2011, 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 
29 #include "lib/error.hpp"
30 #include "include/logging.h"
31 #include "lib/scoped-ptrvect.hpp"
32 #include "lib/scoped-holder.hpp"
33 #include "lib/util-foreach.hpp"
34 
36 
37 #include <algorithm>
38 #include <vector>
39 
40 using util::and_all;
41 using std::vector;
42 using lib::ScopedHolder;
43 using lib::ScopedPtrVect;
44 
45 
46 
47 namespace steam {
48 namespace engine {
49 
50  namespace error = lumiera::error;
51 
52 
53  namespace { // implementation helpers...
54 
55  using diagn::Block;
56 
59  inline bool
60  identifyBlock (Block const& inQuestion, void* storage)
61  {
62  return storage == &inQuestion;
63  }
64 
66  inline function<bool(Block const&)>
68  {
69  return bind (identifyBlock, _1, storage);
70  }
71 
72  template<class VEC>
73  inline Block*
74  pick_Block_by_storage (VEC& vec, void* blockLocation)
75  {
76  typename VEC::iterator pos
77  = std::find_if (vec.begin(),vec.end()
78  ,search_for_block_using_this_storage(blockLocation));
79  if (pos!=vec.end())
80  return &(*pos);
81  else
82  return NULL;
83  }
84  }
85 
86 
87 
88  namespace diagn {
89 
90  typedef ScopedPtrVect<Block> PoolVec;
91  typedef ScopedHolder<PoolVec> PoolHolder;
92 
104  class BlockPool
105  {
106  uint maxAllocCount_;
107  size_t memBlockSize_;
108  PoolHolder blockList_;
109 
110  public:
111  BlockPool()
112  : maxAllocCount_(0) // unlimited by default
113  , memBlockSize_(0)
114  , blockList_()
115  { }
116 
117  void
118  initialise (size_t blockSize)
119  {
120  blockList_.create();
121  memBlockSize_ = blockSize;
122  }
123  // standard copy operations are valid, but will
124  // raise an runtime error, once BlockPool is initialised.
125 
126  ~BlockPool()
127  {
128  if (!verify_all_children_idle())
129  ERROR (test, "Block actively in use while shutting down BufferProvider "
130  "allocation pool. This might lead to Segfault and memory leaks.");
131  }
132 
133 
134  uint
135  prepare_for (uint number_of_expected_buffers)
136  {
137  if (maxAllocCount_ &&
138  maxAllocCount_ < blockList_->size() + number_of_expected_buffers)
139  {
140  ASSERT (maxAllocCount_ >= blockList_->size());
141  return maxAllocCount_ - blockList_->size();
142  }
143  // currently no hard limit imposed
144  return number_of_expected_buffers;
145  }
146 
147 
148  Block&
149  createBlock()
150  {
151  return blockList_->manage (new Block(memBlockSize_));
152  }
153 
154 
155  Block*
156  find (void* blockLocation)
157  {
158  return pick_Block_by_storage (*blockList_, blockLocation);
159  }
160 
161 
162  Block*
163  transferResponsibility (Block* allocatedBlock)
164  {
165  return blockList_->detach (allocatedBlock);
166  }
167 
168 
169  size_t
170  size() const
171  {
172  return blockList_->size();
173  }
174 
175  bool
176  isValid() const
177  {
178  return bool(blockList_);
179  }
180 
181  explicit
182  operator bool() const
183  {
184  return isValid();
185  }
186 
187  private:
188  bool
189  verify_all_children_idle()
190  {
191  try {
192  if (blockList_)
193  return and_all (*blockList_, is_in_sane_state);
194  }
195  ERROR_LOG_AND_IGNORE (test, "State verification of diagnostic BufferProvider allocation pool");
196  return true;
197  }
198 
199 
200  static bool
201  is_in_sane_state (Block const& block)
202  {
203  return not block.was_used() or block.was_closed();
204  }
205  };
206  }
207 
208 
209 
210  namespace { // Details of allocation and accounting
211 
212  const uint MAX_BUFFERS = 50;
213 
214  diagn::Block emptyPlaceholder(0);
215 
216  } // (END) Details of allocation and accounting
217 
218 
219 
224  : BufferProvider ("Diagnostic_HeapAllocated")
225  , pool_(new diagn::PoolTable)
226  , outSeq_()
227  { }
228 
229  TrackingHeapBlockProvider::~TrackingHeapBlockProvider()
230  {
231  INFO (proc_mem, "discarding %zu diagnostic buffer entries", outSeq_.size());
232  }
233 
234 
235  /* ==== Implementation of the BufferProvider interface ==== */
236 
237  uint
238  TrackingHeapBlockProvider::prepareBuffers(uint requestedAmount, HashVal typeID)
239  {
240  diagn::BlockPool& responsiblePool = getBlockPoolFor (typeID);
241  return responsiblePool.prepare_for (requestedAmount);
242  }
243 
244 
245  BuffHandle
246  TrackingHeapBlockProvider::provideLockedBuffer(HashVal typeID)
247  {
248  diagn::BlockPool& blocks = getBlockPoolFor (typeID);
249  diagn::Block& newBlock = blocks.createBlock();
250  return buildHandle (typeID, newBlock.accessMemory(), &newBlock);
251  }
252 
253 
254  void
255  TrackingHeapBlockProvider::mark_emitted (HashVal typeID, LocalKey const& implID)
256  {
257  diagn::Block* block4buffer = locateBlock (typeID, implID);
258  if (!block4buffer)
259  throw error::Logic ("Attempt to emit a buffer not known to this BufferProvider"
260  , LUMIERA_ERROR_BUFFER_MANAGEMENT);
261  diagn::BlockPool& pool = getBlockPoolFor (typeID);
262  outSeq_.manage (pool.transferResponsibility (block4buffer));
263  }
264 
265 
267  void
269  {
270  diagn::Block* block4buffer = locateBlock (typeID, implID);
271  REQUIRE (block4buffer, "releasing a buffer not allocated through this provider");
272  block4buffer->markReleased();
273  }
274 
275 
276 
277  /* ==== Implementation details ==== */
278 
279  size_t
280  TrackingHeapBlockProvider::emittedCnt() const
281  {
282  return outSeq_.size();
283  }
284 
285  diagn::Block&
286  TrackingHeapBlockProvider::access_emitted (uint bufferID)
287  {
288  if (!withinOutputSequence (bufferID))
289  return emptyPlaceholder;
290  else
291  return outSeq_[bufferID];
292  }
293 
294  bool
295  TrackingHeapBlockProvider::withinOutputSequence (uint bufferID) const
296  {
297  if (bufferID >= MAX_BUFFERS)
298  throw error::Fatal ("hardwired internal limit for test buffers exceeded");
299 
300  return bufferID < outSeq_.size();
301  }
302 
304  TrackingHeapBlockProvider::getBlockPoolFor (HashVal typeID)
305  {
306  diagn::BlockPool& pool = (*pool_)[typeID];
307  if (!pool)
308  pool.initialise(getBufferSize(typeID));
309  return pool;
310  }
311 
312  diagn::Block*
313  TrackingHeapBlockProvider::locateBlock (HashVal typeID, void* storage)
314  {
315  diagn::BlockPool& pool = getBlockPoolFor (typeID);
316  diagn::Block* block4buffer = pool.find (storage);
317  return block4buffer? block4buffer
318  : searchInOutSeqeuence (storage);
319  }
320 
321  diagn::Block*
322  TrackingHeapBlockProvider::searchInOutSeqeuence (void* blockLocation)
323  {
324  return pick_Block_by_storage (outSeq_, blockLocation);
325  }
326 
327 
328 
329 
330 }} // namespace engine
Helper for implementing a diagnostic BufferProvider: A block of heap allocated storage, with the capability to store some additional tracking information.
Some wrappers for coping with ownership problems.
#define ERROR_LOG_AND_IGNORE(_FLAG_, _OP_DESCR_)
convenience shortcut for a sequence of catch blocks just logging and consuming an error...
Definition: error.hpp:275
Definition: run.hpp:49
BuffHandle buildHandle(HashVal typeID, void *storage, LocalKey const &)
callback from implementation to build and enrol a BufferHandle, to be returned to the client as resul...
bool and_all(CON const &elements, FUN function, P1 &&bind1, ARGS &&...args)
Accept binding for arbitrary function arguments.
This header is for including and configuring NoBug.
Steam-Layer implementation namespace root.
Managing lifecycle for a collection of objects.
bool identifyBlock(Block const &inQuestion, void *storage)
helper to find Block entries based on their raw memory address
Simple vector based collection of pointers, managing lifecycle of the pointed-to objects.
Derived specific exceptions within Lumiera&#39;s exception hierarchy.
Definition: error.hpp:199
an opaque ID to be used by the BufferProvider implementation.
Dummy implementation of the BufferProvider interface to support writing unit tests.
Inline buffer holding and owning an object similar to unique_ptr.
Lumiera error handling (C++ interface).
Handle for a buffer for processing data, abstracting away the actual implementation.
Definition: buffhandle.hpp:115
size_t HashVal
a STL compatible hash value
Definition: hash-value.h:56
Interface: a facility providing and managing working buffers for media calculations.
Perform operations "for each element" of a collection.
virtual void detachBuffer(HashVal entryID, LocalKey const &)
mark a buffer as officially discarded
function< bool(Block const &)> search_for_block_using_this_storage(void *storage)
build a searching predicate