artdaq_core  v3_05_07
SharedMemoryManager.hh
1 #ifndef artdaq_core_Core_SharedMemoryManager_hh
2 #define artdaq_core_Core_SharedMemoryManager_hh 1
3 
4 #include <atomic>
5 #include <deque>
6 #include <list>
7 #include <mutex>
8 #include <string>
9 #include <vector>
10 #include "artdaq-core/Utilities/TimeUtils.hh"
11 
12 namespace artdaq {
18 {
19 public:
24  {
25  Empty,
26  Writing,
27  Full,
28  Reading
29  };
30 
36  static inline std::string FlagToString(BufferSemaphoreFlags flag)
37  {
38  switch (flag)
39  {
41  return "Empty";
43  return "Writing";
45  return "Full";
47  return "Reading";
48  }
49  return "Unknown";
50  }
51 
61  SharedMemoryManager(uint32_t shm_key, size_t buffer_count = 0, size_t buffer_size = 0, uint64_t buffer_timeout_us = 100 * 1000000, bool destructive_read_mode = true);
62 
66  virtual ~SharedMemoryManager() noexcept;
67 
71  bool Attach(size_t timeout_usec = 0);
72 
77  int GetBufferForReading();
78 
84  int GetBufferForWriting(bool overwrite);
85 
90  bool ReadyForRead();
91 
97  virtual bool ReadyForWrite(bool overwrite);
98 
103  size_t ReadReadyCount();
104 
110  size_t WriteReadyCount(bool overwrite);
111 
117  std::deque<int> GetBuffersOwnedByManager(bool locked = true);
118 
124  size_t BufferDataSize(int buffer);
125 
129  size_t BufferSize() { return (shm_ptr_ != nullptr ? shm_ptr_->buffer_size : 0); }
130 
135  void ResetReadPos(int buffer);
136 
141  void ResetWritePos(int buffer);
147  void IncrementReadPos(int buffer, size_t read);
148 
155  bool IncrementWritePos(int buffer, size_t written);
156 
162  bool MoreDataInBuffer(int buffer);
163 
170  bool CheckBuffer(int buffer, BufferSemaphoreFlags flags);
171 
177  void MarkBufferFull(int buffer, int destination = -1);
178 
184  void MarkBufferEmpty(int buffer, bool force = false);
185 
192  bool ResetBuffer(int buffer);
193 
197  void GetNewId()
198  {
199  if (manager_id_ < 0 && IsValid()) manager_id_ = shm_ptr_->next_id.fetch_add(1);
200  }
201 
206  uint16_t GetAttachedCount() const;
207 
211  void ResetAttachedCount() const
212  {
213  if (manager_id_ == 0 && IsValid()) shm_ptr_->next_id = 1;
214  }
215 
220  int GetMyId() const { return manager_id_; }
221 
226  int GetRank() const { return IsValid() ? shm_ptr_->rank : -1; }
227 
232  void SetRank(int rank)
233  {
234  if (manager_id_ == 0 && IsValid()) shm_ptr_->rank = rank;
235  }
236 
241  bool IsValid() const { return shm_ptr_ ? true : false; }
242 
246  bool IsEndOfData() const;
247 
252  size_t size() const { return IsValid() ? shm_ptr_->buffer_count : 0; }
253 
261  size_t Write(int buffer, void* data, size_t size);
262 
270  bool Read(int buffer, void* data, size_t size);
271 
276  virtual std::string toString();
277 
282  uint32_t GetKey() const { return shm_key_; }
283 
289  void* GetReadPos(int buffer);
290 
296  void* GetWritePos(int buffer);
297 
303  void* GetBufferStart(int buffer);
304 
312  void Detach(bool throwException = false, std::string category = "", std::string message = "", bool force = false);
313 
318  uint64_t GetBufferTimeout() const { return IsValid() ? shm_ptr_->buffer_timeout_us : 0; }
319 
324  size_t GetBufferCount() const { return IsValid() ? shm_ptr_->next_sequence_id : 0; }
325 
330  size_t GetLastSeenBufferID() const { return last_seen_id_; }
331 
335  size_t GetLowestSeqIDRead() const { return IsValid() ? shm_ptr_->lowest_seq_id_read : 0; }
336 
341  void SetMinWriteSize(size_t size) { min_write_size_ = size; }
342 
347  std::list<std::pair<int, BufferSemaphoreFlags>> GetBufferReport();
348 
352  void TouchBuffer(int buffer) { return touchBuffer_(getBufferInfo_(buffer)); }
353 
354 private:
355  struct ShmBuffer
356  {
357  size_t writePos;
358  size_t readPos;
359  std::atomic<BufferSemaphoreFlags> sem;
360  std::atomic<int16_t> sem_id;
361  std::atomic<size_t> sequence_id;
362  std::atomic<uint64_t> last_touch_time;
363  };
364 
365  struct ShmStruct
366  {
367  std::atomic<unsigned int> reader_pos;
368  std::atomic<unsigned int> writer_pos;
369  int buffer_count;
370  size_t buffer_size;
371  size_t buffer_timeout_us;
372  size_t next_sequence_id;
373  size_t lowest_seq_id_read;
374  bool destructive_read_mode;
375 
376  std::atomic<int> next_id;
377  int rank;
378  unsigned ready_magic;
379  };
380 
381  uint8_t* dataStart_() const;
382  uint8_t* bufferStart_(int buffer);
383  ShmBuffer* getBufferInfo_(int buffer);
384  bool checkBuffer_(ShmBuffer* buffer, BufferSemaphoreFlags flags, bool exceptions = true);
385  void touchBuffer_(ShmBuffer* buffer);
386 
387  ShmStruct requested_shm_parameters_;
388 
389  int shm_segment_id_;
390  ShmStruct* shm_ptr_;
391  uint32_t shm_key_;
392  int manager_id_;
393  mutable std::vector<std::mutex> buffer_mutexes_;
394  mutable std::mutex search_mutex_;
395 
396  std::atomic<size_t> last_seen_id_;
397  size_t min_write_size_;
398 };
399 
400 } // namespace artdaq
401 
402 #endif // artdaq_core_Core_SharedMemoryManager_hh
void TouchBuffer(int buffer)
Touch the given buffer (update its last_touch_time)
bool Read(int buffer, void *data, size_t size)
Read size bytes of data from buffer into the given pointer.
void IncrementReadPos(int buffer, size_t read)
Increment the read position for a given buffer.
void ResetAttachedCount() const
Reset the attached manager count to 0.
bool IsValid() const
Is the shared memory pointer valid?
bool Attach(size_t timeout_usec=0)
Reconnect to the shared memory segment.
std::deque< int > GetBuffersOwnedByManager(bool locked=true)
Get the list of all buffers currently owned by this manager instance.
void ResetReadPos(int buffer)
Set the read position of the given buffer to the beginning of the buffer.
static std::string FlagToString(BufferSemaphoreFlags flag)
Convert a BufferSemaphoreFlags variable to its string represenatation.
bool MoreDataInBuffer(int buffer)
Determine if more data is available to be read, based on the read position and data size...
virtual std::string toString()
Write information about the SharedMemory to a string.
void GetNewId()
Assign a new ID to the current SharedMemoryManager, if one has not yet been assigned.
std::list< std::pair< int, BufferSemaphoreFlags > > GetBufferReport()
Get a report on the status of each buffer.
The buffer is full, and waiting for a reader.
BufferSemaphoreFlags
The BufferSemaphoreFlags enumeration represents the different possible &quot;states&quot; of a given shared mem...
size_t BufferDataSize(int buffer)
Get the current size of the buffer&#39;s data.
size_t BufferSize()
Get the size of of a single buffer.
void Detach(bool throwException=false, std::string category="", std::string message="", bool force=false)
Detach from the Shared Memory segment, optionally throwing a cet::exception with the specified proper...
virtual ~SharedMemoryManager() noexcept
SharedMemoryManager Destructor.
The buffer is currently being read from.
The buffer is currently being written to.
The SharedMemoryManager creates a Shared Memory area which is divided into a number of fixed-size buf...
The buffer is empty, and waiting for a writer.
size_t ReadReadyCount()
Count the number of buffers that are ready for reading.
bool ResetBuffer(int buffer)
Resets the buffer from Reading to Full. This operation will only have an effect if performed by the o...
int GetRank() const
Get the rank of the owner of the Shared Memory (artdaq assigns rank to each artdaq process for data f...
size_t GetLowestSeqIDRead() const
Gets the lowest sequence ID that has been read by any reader, as reported by the readers.
size_t size() const
Get the number of buffers in the shared memory segment.
bool IncrementWritePos(int buffer, size_t written)
Increment the write position for a given buffer.
bool IsEndOfData() const
Determine whether the Shared Memory is marked for destruction (End of Data)
bool CheckBuffer(int buffer, BufferSemaphoreFlags flags)
Check both semaphore conditions (Mode flag and manager ID) for a given buffer.
size_t GetLastSeenBufferID() const
Gets the highest buffer number either written or read by this SharedMemoryManager.
uint32_t GetKey() const
Get the key of the shared memory attached to this SharedMemoryManager.
void MarkBufferFull(int buffer, int destination=-1)
Release a buffer from a writer, marking it Full and ready for a reader.
void MarkBufferEmpty(int buffer, bool force=false)
Release a buffer from a reader, marking it Empty and ready to accept more data.
uint64_t GetBufferTimeout() const
Gets the configured timeout for buffers to be declared &quot;stale&quot;.
void ResetWritePos(int buffer)
Set the write position of the given buffer to the beginning of the buffer.
void SetMinWriteSize(size_t size)
Sets the threshold after which a buffer should be considered &quot;non-empty&quot; (in case of default headers)...
size_t GetBufferCount() const
Gets the number of buffers which have been processed through the Shared Memory.
void * GetWritePos(int buffer)
Get a pointer to the current write position of the buffer.
size_t Write(int buffer, void *data, size_t size)
Write size bytes of data from the given pointer to a buffer.
void * GetReadPos(int buffer)
Get a pointer to the current read position of the buffer.
void * GetBufferStart(int buffer)
Get a pointer to the start position of the buffer.
SharedMemoryManager(uint32_t shm_key, size_t buffer_count=0, size_t buffer_size=0, uint64_t buffer_timeout_us=100 *1000000, bool destructive_read_mode=true)
SharedMemoryManager Constructor.
bool ReadyForRead()
Whether any buffer is ready for read.
void SetRank(int rank)
Set the rank stored in the Shared Memory, if the current instance is the owner of the shared memory...
int GetBufferForWriting(bool overwrite)
Finds a buffer that is ready to be written to, and reserves it for the calling manager.
uint16_t GetAttachedCount() const
Get the number of attached SharedMemoryManagers.
size_t WriteReadyCount(bool overwrite)
Count the number of buffers that are ready for writing.
int GetMyId() const
Get the ID number of the current SharedMemoryManager.
int GetBufferForReading()
Finds a buffer that is ready to be read, and reserves it for the calling manager. ...
virtual bool ReadyForWrite(bool overwrite)
Whether any buffer is available for write.