119 lines
3.2 KiB
C++
119 lines
3.2 KiB
C++
#ifndef _SP_MC_RING_BUFFER_H
|
|
#define _SP_MC_RING_BUFFER_H
|
|
|
|
#include <vector>
|
|
#include <cstddef>
|
|
#include <stdexcept>
|
|
#include <string>
|
|
#include <new>
|
|
#include <memory>
|
|
#include <user/stimulusFrame.h>
|
|
#include <user/frameAssemblyDesc.h>
|
|
#include <user/sequenceLock.h>
|
|
#include <user/senseApiDesc.h>
|
|
#define CL_TARGET_OPENCL_VERSION 120
|
|
#include <CL/cl.h>
|
|
|
|
namespace smo {
|
|
namespace stim_buff {
|
|
|
|
/**
|
|
* @brief Single-producer, multi-consumer ring buffer w/per-slot sequence locks
|
|
*
|
|
* A ring buffer that maintains data alignment constraints while providing
|
|
* lock-free read access through per-slot sequence locks. The locks are kept
|
|
* separate from the data to preserve alignment requirements for the input
|
|
* engine.
|
|
*/
|
|
class SpMcRingBuffer
|
|
{
|
|
public:
|
|
/** EXPLANATION:
|
|
* Constructor initializes the ring buffer with FrameAssemblyDesc.
|
|
* Allocates frames vector with properly constructed StimulusFrame instances,
|
|
* each initialized with a SlotDesc from the FrameAssemblyDesc.
|
|
*/
|
|
explicit SpMcRingBuffer(
|
|
const std::shared_ptr<FrameAssemblyDesc> &frameAssemblyDesc_,
|
|
const SmoCallbacks& callbacks,
|
|
cl_mem_flags flags)
|
|
:
|
|
nBuffers(frameAssemblyDesc_ ? frameAssemblyDesc_->slots.size() : 0),
|
|
frameAssemblyDesc(frameAssemblyDesc_),
|
|
slots(nBuffers) // Default-construct all frames
|
|
{
|
|
if (!frameAssemblyDesc)
|
|
{
|
|
throw std::invalid_argument(std::string(__func__)
|
|
+ ": SpMcRingBuffer: frameAssemblyDesc must not be null");
|
|
}
|
|
|
|
if (nBuffers == 0)
|
|
{
|
|
throw std::invalid_argument(std::string(__func__)
|
|
+ ": SpMcRingBuffer: frameAssemblyDesc must have at least one "
|
|
"slot");
|
|
}
|
|
|
|
// Re-invoke constructors w/placement new on default-constructed frames
|
|
for (size_t i = 0; i < nBuffers; ++i)
|
|
{
|
|
slots[i].~StimulusFrame(); // Destroy default-constructed object
|
|
new (&slots[i]) StimulusFrame(
|
|
frameAssemblyDesc->slots[i], callbacks, flags);
|
|
}
|
|
}
|
|
|
|
~SpMcRingBuffer() = default;
|
|
|
|
// Non-copyable, non-movable (slots are non-movable)
|
|
SpMcRingBuffer(const SpMcRingBuffer&) = delete;
|
|
SpMcRingBuffer& operator=(const SpMcRingBuffer&) = delete;
|
|
SpMcRingBuffer(SpMcRingBuffer&&) = delete;
|
|
SpMcRingBuffer& operator=(SpMcRingBuffer&&) = delete;
|
|
|
|
public:
|
|
/**
|
|
* @brief Get a reference to the StimulusFrame at the specified slot
|
|
*
|
|
* @param slotIndex The index of the slot (0-based)
|
|
* @return Reference to StimulusFrame at the slot
|
|
* @throws std::out_of_range if slotIndex >= nBuffers
|
|
*/
|
|
StimulusFrame& getDataAtSlot(size_t slotIndex)
|
|
{
|
|
if (slotIndex >= nBuffers)
|
|
{
|
|
throw std::out_of_range(std::string(__func__)
|
|
+ ": SpMcRingBuffer: slotIndex must be < nBuffers");
|
|
}
|
|
return slots[slotIndex];
|
|
}
|
|
|
|
SequenceLock& getSequenceLockAtSlot(size_t slotIndex)
|
|
{
|
|
if (slotIndex >= nBuffers)
|
|
{
|
|
throw std::out_of_range(std::string(__func__)
|
|
+ ": SpMcRingBuffer: slotIndex must be < nBuffers");
|
|
}
|
|
return slots[slotIndex].lock;
|
|
}
|
|
|
|
public:
|
|
// Layout/invariants
|
|
size_t nBuffers;
|
|
|
|
private:
|
|
// FrameAssemblyDesc describing the memory layout
|
|
std::shared_ptr<FrameAssemblyDesc> frameAssemblyDesc;
|
|
// Frames vector: each frame contains a sequence lock and SlotDesc
|
|
std::vector<StimulusFrame> slots;
|
|
};
|
|
|
|
} // namespace stim_buff
|
|
} // namespace smo
|
|
|
|
#endif // _SP_MC_RING_BUFFER_H
|
|
|