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)
5  2011, Hermann Vosseler <Ichthyostega@web.de>
6 
7   **Lumiera** is free software; you can redistribute it and/or modify it
8   under the terms of the GNU General Public License as published by the
9   Free Software Foundation; either version 2 of the License, or (at your
10   option) any later version. See the file COPYING for further details.
11 
12 * *****************************************************************/
13 
14 
20 #include "lib/error.hpp"
21 #include "include/logging.h"
22 #include "lib/scoped-ptrvect.hpp"
23 #include "lib/scoped-holder.hpp"
24 #include "lib/util-foreach.hpp"
25 
27 
28 #include <algorithm>
29 #include <vector>
30 
31 using util::and_all;
32 using std::vector;
33 using lib::ScopedHolder;
34 using lib::ScopedPtrVect;
35 
36 
37 
38 namespace steam {
39 namespace engine {
40 
41  namespace error = lumiera::error;
42 
43  using Buff = StreamType::ImplFacade::DataBuffer;
44 
45 
46  namespace { // implementation helpers...
47 
48  inline Buff*
49  asBuffer(void* mem)
50  {// type tag to mark memory address as Buffer
51  return static_cast<Buff*> (mem);
52  }
53 
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, asBuffer(newBlock.accessMemory()), &newBlock);
251  }
252 
253 
254  void
255  TrackingHeapBlockProvider::mark_emitted (HashVal typeID, LocalTag const& specifics)
256  {
257  diagn::Block* block4buffer = locateBlock (typeID, specifics);
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
268  TrackingHeapBlockProvider::detachBuffer (HashVal typeID, LocalTag const& specifics, Buff& storage)
269  {
270  diagn::Block* block4buffer = locateBlock (typeID, specifics);
271  REQUIRE (block4buffer, "releasing a buffer not allocated through this provider");
272  REQUIRE (util::isSameAdr (storage, block4buffer->accessMemory()));
273  block4buffer->markReleased();
274  }
275 
276 
277 
278  /* ==== Implementation details ==== */
279 
280  size_t
281  TrackingHeapBlockProvider::emittedCnt() const
282  {
283  return outSeq_.size();
284  }
285 
286  diagn::Block&
287  TrackingHeapBlockProvider::access_emitted (uint bufferID)
288  {
289  if (!withinOutputSequence (bufferID))
290  return emptyPlaceholder;
291  else
292  return outSeq_[bufferID];
293  }
294 
295  bool
296  TrackingHeapBlockProvider::withinOutputSequence (uint bufferID) const
297  {
298  if (bufferID >= MAX_BUFFERS)
299  throw error::Fatal ("hardwired internal limit for test buffers exceeded");
300 
301  return bufferID < outSeq_.size();
302  }
303 
305  TrackingHeapBlockProvider::getBlockPoolFor (HashVal typeID)
306  {
307  diagn::BlockPool& pool = (*pool_)[typeID];
308  if (!pool)
309  pool.initialise(getBufferSize(typeID));
310  return pool;
311  }
312 
313  diagn::Block*
314  TrackingHeapBlockProvider::locateBlock (HashVal typeID, void* storage)
315  {
316  diagn::BlockPool& pool = getBlockPoolFor (typeID);
317  diagn::Block* block4buffer = pool.find (storage);
318  return block4buffer? block4buffer
319  : searchInOutSeqeuence (storage);
320  }
321 
322  diagn::Block*
323  TrackingHeapBlockProvider::searchInOutSeqeuence (void* blockLocation)
324  {
325  return pick_Block_by_storage (outSeq_, blockLocation);
326  }
327 
328 
329 
330 
331 }} // 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:266
Definition: run.hpp:40
virtual void detachBuffer(HashVal, LocalTag const &, Buff &) override
mark a buffer as officially discarded
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.
an opaque mark to be used by the BufferProvider implementation.
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:190
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:111
size_t HashVal
a STL compatible hash value
Definition: hash-value.h:52
Interface: a facility providing and managing working buffers for media calculations.
BuffHandle buildHandle(HashVal typeID, Buff *storage, LocalTag const &=LocalTag::UNKNOWN)
callback from implementation to build and enrol a BufferHandle, to be returned to the client as resul...
placeholder type for the contents of a data buffer.
Definition: streamtype.hpp:112
Perform operations "for each element" of a collection.
function< bool(Block const &)> search_for_block_using_this_storage(void *storage)
build a searching predicate