2011-11-07 00:07:53 +01:00
|
|
|
|
/*
|
|
|
|
|
|
TRACKING-HEAP-BLOCK-PROVIDER.hpp - plain heap allocating BufferProvider implementation for tests
|
|
|
|
|
|
|
Copyright: clarify and simplify the file headers
* Lumiera source code always was copyrighted by individual contributors
* there is no entity "Lumiera.org" which holds any copyrights
* Lumiera source code is provided under the GPL Version 2+
== Explanations ==
Lumiera as a whole is distributed under Copyleft, GNU General Public License Version 2 or above.
For this to become legally effective, the ''File COPYING in the root directory is sufficient.''
The licensing header in each file is not strictly necessary, yet considered good practice;
attaching a licence notice increases the likeliness that this information is retained
in case someone extracts individual code files. However, it is not by the presence of some
text, that legally binding licensing terms become effective; rather the fact matters that a
given piece of code was provably copyrighted and published under a license. Even reformatting
the code, renaming some variables or deleting parts of the code will not alter this legal
situation, but rather creates a derivative work, which is likewise covered by the GPL!
The most relevant information in the file header is the notice regarding the
time of the first individual copyright claim. By virtue of this initial copyright,
the first author is entitled to choose the terms of licensing. All further
modifications are permitted and covered by the License. The specific wording
or format of the copyright header is not legally relevant, as long as the
intention to publish under the GPL remains clear. The extended wording was
based on a recommendation by the FSF. It can be shortened, because the full terms
of the license are provided alongside the distribution, in the file COPYING.
2024-11-17 23:42:55 +01:00
|
|
|
|
Copyright (C)
|
|
|
|
|
|
2011, Hermann Vosseler <Ichthyostega@web.de>
|
2011-11-07 00:07:53 +01:00
|
|
|
|
|
Copyright: clarify and simplify the file headers
* Lumiera source code always was copyrighted by individual contributors
* there is no entity "Lumiera.org" which holds any copyrights
* Lumiera source code is provided under the GPL Version 2+
== Explanations ==
Lumiera as a whole is distributed under Copyleft, GNU General Public License Version 2 or above.
For this to become legally effective, the ''File COPYING in the root directory is sufficient.''
The licensing header in each file is not strictly necessary, yet considered good practice;
attaching a licence notice increases the likeliness that this information is retained
in case someone extracts individual code files. However, it is not by the presence of some
text, that legally binding licensing terms become effective; rather the fact matters that a
given piece of code was provably copyrighted and published under a license. Even reformatting
the code, renaming some variables or deleting parts of the code will not alter this legal
situation, but rather creates a derivative work, which is likewise covered by the GPL!
The most relevant information in the file header is the notice regarding the
time of the first individual copyright claim. By virtue of this initial copyright,
the first author is entitled to choose the terms of licensing. All further
modifications are permitted and covered by the License. The specific wording
or format of the copyright header is not legally relevant, as long as the
intention to publish under the GPL remains clear. The extended wording was
based on a recommendation by the FSF. It can be shortened, because the full terms
of the license are provided alongside the distribution, in the file COPYING.
2024-11-17 23:42:55 +01:00
|
|
|
|
**Lumiera** is free software; you can redistribute it and/or modify it
|
|
|
|
|
|
under the terms of the GNU General Public License as published by the
|
|
|
|
|
|
Free Software Foundation; either version 2 of the License, or (at your
|
|
|
|
|
|
option) any later version. See the file COPYING for further details.
|
2011-11-07 00:07:53 +01:00
|
|
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
/** @file tracking-heap-block-provider.hpp
|
|
|
|
|
|
** Dummy implementation of the BufferProvider interface to support writing unit tests.
|
|
|
|
|
|
** This BufferProvider is especially straight forward and brain dead: it just claims
|
|
|
|
|
|
** more and more heap blocks and never releases any memory dynamically. This allows
|
|
|
|
|
|
** to investigate additional tracking status flags for each allocated block after
|
|
|
|
|
|
** the fact.
|
|
|
|
|
|
**
|
|
|
|
|
|
** The allocated buffers are numbered with a simple ascending sequence of integers,
|
2024-07-27 17:17:02 +02:00
|
|
|
|
** used as LocalTag (see BufferMetadata). Clients can just request a Buffer with the
|
2011-11-07 00:07:53 +01:00
|
|
|
|
** given number, causing that block to be allocated. There is a "backdoor", allowing
|
|
|
|
|
|
** to access any allocated block, even if it is considered "released" by the terms
|
|
|
|
|
|
** of the usual lifecycle. Only when the provider object itself gets destroyed,
|
|
|
|
|
|
** all allocated blocks will be discarded.
|
|
|
|
|
|
**
|
|
|
|
|
|
** @see DiagnosticOutputSlot
|
|
|
|
|
|
** @see DiagnosticBufferProvider
|
|
|
|
|
|
** @see buffer-provider-protocol-test.cpp
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
2018-11-15 23:52:02 +01:00
|
|
|
|
#ifndef STEAM_ENGINE_TRACKING_HEAP_BLOCK_PROVIDER_H
|
|
|
|
|
|
#define STEAM_ENGINE_TRACKING_HEAP_BLOCK_PROVIDER_H
|
2011-11-07 00:07:53 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#include "lib/error.hpp"
|
2012-12-02 23:03:37 +01:00
|
|
|
|
#include "lib/hash-value.h"
|
2018-11-15 23:42:43 +01:00
|
|
|
|
#include "steam/engine/buffer-provider.hpp"
|
2011-11-07 00:07:53 +01:00
|
|
|
|
#include "lib/scoped-ptrvect.hpp"
|
|
|
|
|
|
|
2014-04-03 22:42:48 +02:00
|
|
|
|
#include <unordered_map>
|
2017-01-05 00:56:46 +01:00
|
|
|
|
#include <memory>
|
2011-11-07 00:07:53 +01:00
|
|
|
|
|
|
|
|
|
|
|
2018-11-15 23:55:13 +01:00
|
|
|
|
namespace steam {
|
2011-11-07 00:07:53 +01:00
|
|
|
|
namespace engine {
|
|
|
|
|
|
|
|
|
|
|
|
namespace error = lumiera::error;
|
|
|
|
|
|
|
2011-11-18 01:23:50 +01:00
|
|
|
|
using lib::ScopedPtrVect;
|
2012-12-02 23:03:37 +01:00
|
|
|
|
using lib::HashVal;
|
2011-11-07 00:07:53 +01:00
|
|
|
|
|
|
|
|
|
|
namespace diagn {
|
|
|
|
|
|
|
2017-01-05 00:56:46 +01:00
|
|
|
|
using std::unique_ptr;
|
2011-11-07 00:07:53 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
2011-12-08 23:02:19 +01:00
|
|
|
|
* Helper for implementing a diagnostic BufferProvider:
|
2011-11-07 00:07:53 +01:00
|
|
|
|
* A block of heap allocated storage, with the capability
|
|
|
|
|
|
* to store some additional tracking information.
|
|
|
|
|
|
*/
|
|
|
|
|
|
class Block
|
2018-03-24 05:35:13 +01:00
|
|
|
|
: util::NonCopyable
|
2011-11-07 00:07:53 +01:00
|
|
|
|
{
|
2017-01-05 00:56:46 +01:00
|
|
|
|
unique_ptr<char[]> storage_;
|
2011-11-07 00:07:53 +01:00
|
|
|
|
|
2011-11-21 02:28:44 +01:00
|
|
|
|
bool was_released_;
|
2011-11-07 00:07:53 +01:00
|
|
|
|
|
|
|
|
|
|
public:
|
2011-11-18 01:23:50 +01:00
|
|
|
|
explicit
|
|
|
|
|
|
Block(size_t bufferSize)
|
2011-11-21 02:28:44 +01:00
|
|
|
|
: storage_(bufferSize? new char[bufferSize] : NULL)
|
|
|
|
|
|
, was_released_(false)
|
2011-11-07 00:07:53 +01:00
|
|
|
|
{ }
|
|
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
|
was_used() const
|
|
|
|
|
|
{
|
2011-11-21 02:28:44 +01:00
|
|
|
|
return bool(storage_);
|
2011-11-07 00:07:53 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
|
was_closed() const
|
|
|
|
|
|
{
|
2011-11-21 02:28:44 +01:00
|
|
|
|
return was_released_;
|
2011-11-07 00:07:53 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void*
|
|
|
|
|
|
accessMemory() const
|
|
|
|
|
|
{
|
2011-11-21 02:28:44 +01:00
|
|
|
|
REQUIRE (storage_, "Block was never prepared for use");
|
2011-11-07 00:07:53 +01:00
|
|
|
|
return storage_.get();
|
|
|
|
|
|
}
|
2011-11-15 04:47:31 +01:00
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
|
markReleased()
|
|
|
|
|
|
{
|
2011-11-21 02:28:44 +01:00
|
|
|
|
was_released_ = true;
|
2011-11-15 04:47:31 +01:00
|
|
|
|
}
|
2011-11-07 00:07:53 +01:00
|
|
|
|
};
|
2011-11-13 04:20:14 +01:00
|
|
|
|
|
|
|
|
|
|
class BlockPool;
|
|
|
|
|
|
|
2014-04-03 22:42:48 +02:00
|
|
|
|
typedef std::unordered_map<HashVal,BlockPool> PoolTable;
|
2011-11-07 00:07:53 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
2011-11-13 04:20:14 +01:00
|
|
|
|
|
2011-11-07 00:07:53 +01:00
|
|
|
|
/**
|
|
|
|
|
|
* simple BufferProvider implementation with additional allocation tracking.
|
|
|
|
|
|
* @internal used as PImpl by DiagnosticBufferProvider and DiagnosticOutputSlot.
|
|
|
|
|
|
*
|
|
|
|
|
|
* This dummy implementation of the BufferProvider interface uses a linearly growing
|
|
|
|
|
|
* table of heap allocated buffer blocks, which will never be discarded, unless the object
|
|
|
|
|
|
* is discarded as a whole. There is an additional testing/diagnostics API to access the
|
|
|
|
|
|
* tracked usage information, even when blocks are already marked as "released".
|
|
|
|
|
|
*/
|
|
|
|
|
|
class TrackingHeapBlockProvider
|
|
|
|
|
|
: public BufferProvider
|
|
|
|
|
|
{
|
2017-01-05 00:56:46 +01:00
|
|
|
|
unique_ptr<diagn::PoolTable> pool_;
|
2024-12-20 01:47:40 +01:00
|
|
|
|
ScopedPtrVect<diagn::Block> outSeq_;
|
2011-11-07 00:07:53 +01:00
|
|
|
|
|
2011-11-11 23:33:59 +01:00
|
|
|
|
public:
|
|
|
|
|
|
/* === BufferProvider interface === */
|
|
|
|
|
|
|
2024-07-28 19:29:27 +02:00
|
|
|
|
virtual uint prepareBuffers (uint count, HashVal typeID) override;
|
|
|
|
|
|
virtual BuffHandle provideLockedBuffer (HashVal typeID) override;
|
|
|
|
|
|
virtual void mark_emitted (HashVal, LocalTag const&) override;
|
|
|
|
|
|
virtual void detachBuffer (HashVal, LocalTag const&, Buff&) override;
|
2011-11-07 00:07:53 +01:00
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
|
TrackingHeapBlockProvider();
|
|
|
|
|
|
virtual ~TrackingHeapBlockProvider();
|
|
|
|
|
|
|
2011-11-18 01:23:50 +01:00
|
|
|
|
size_t emittedCnt() const;
|
|
|
|
|
|
|
2011-11-21 03:26:08 +01:00
|
|
|
|
diagn::Block& access_emitted (uint bufferID);
|
2011-11-07 00:07:53 +01:00
|
|
|
|
|
2011-11-11 23:33:59 +01:00
|
|
|
|
template<typename TY>
|
|
|
|
|
|
TY& accessAs (uint bufferID);
|
|
|
|
|
|
|
2024-12-20 01:47:40 +01:00
|
|
|
|
void markAllEmitted();
|
|
|
|
|
|
|
2011-11-07 00:07:53 +01:00
|
|
|
|
private:
|
2011-11-18 01:23:50 +01:00
|
|
|
|
bool withinOutputSequence (uint bufferID) const;
|
2011-11-15 04:47:31 +01:00
|
|
|
|
diagn::BlockPool& getBlockPoolFor (HashVal typeID);
|
|
|
|
|
|
diagn::Block* locateBlock (HashVal typeID, void*);
|
2024-12-20 01:47:40 +01:00
|
|
|
|
diagn::Block* searchInOutSeqeuence (void* storage);
|
2011-11-07 00:07:53 +01:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2011-11-11 23:33:59 +01:00
|
|
|
|
/** convenience shortcut: access the buffer with the given number,
|
|
|
|
|
|
* then try to convert the raw memory to the templated type.
|
|
|
|
|
|
* @throw error::Invalid if the required fame number is beyond
|
|
|
|
|
|
* the number of buffers marked as "emitted"
|
|
|
|
|
|
* @throw error::Fatal if conversion is not possible or the
|
|
|
|
|
|
* conversion path chosen doesn't work (which might
|
|
|
|
|
|
* be due to RTTI indicating an incompatible type).
|
|
|
|
|
|
*/
|
|
|
|
|
|
template<typename TY>
|
|
|
|
|
|
TY&
|
|
|
|
|
|
TrackingHeapBlockProvider::accessAs (uint bufferID)
|
|
|
|
|
|
{
|
2011-11-18 01:23:50 +01:00
|
|
|
|
if (!withinOutputSequence (bufferID))
|
2011-11-11 23:33:59 +01:00
|
|
|
|
throw error::Invalid ("Buffer with the given ID not yet emitted");
|
|
|
|
|
|
|
2011-11-21 03:26:08 +01:00
|
|
|
|
diagn::Block& memoryBlock = access_emitted (bufferID);
|
2023-12-02 23:56:46 +01:00
|
|
|
|
TY* converted = std::launder (reinterpret_cast<TY*> (memoryBlock.accessMemory()));
|
2011-11-11 23:33:59 +01:00
|
|
|
|
|
2011-11-21 02:28:44 +01:00
|
|
|
|
REQUIRE (converted);
|
|
|
|
|
|
return *converted;
|
2011-11-11 23:33:59 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2011-11-07 00:07:53 +01:00
|
|
|
|
|
|
|
|
|
|
|
2018-11-15 23:55:13 +01:00
|
|
|
|
}} // namespace steam::engine
|
2011-11-07 00:07:53 +01:00
|
|
|
|
#endif
|