00001 #ifndef artdaq_core_Core_SharedMemoryManager_hh 00002 #define artdaq_core_Core_SharedMemoryManager_hh 1 00003 00004 #include <atomic> 00005 #include <string> 00006 #include <deque> 00007 #include "artdaq-core/Utilities/TimeUtils.hh" 00008 #include <mutex> 00009 #include <vector> 00010 #include <list> 00011 00012 namespace artdaq 00013 { 00018 class SharedMemoryManager 00019 { 00020 public: 00021 00025 enum class BufferSemaphoreFlags 00026 { 00027 Empty, 00028 Writing, 00029 Full, 00030 Reading 00031 }; 00032 00038 static inline std::string FlagToString(BufferSemaphoreFlags flag) 00039 { 00040 switch (flag) 00041 { 00042 case BufferSemaphoreFlags::Empty: 00043 return "Empty"; 00044 case BufferSemaphoreFlags::Writing: 00045 return "Writing"; 00046 case BufferSemaphoreFlags::Full: 00047 return "Full"; 00048 case BufferSemaphoreFlags::Reading: 00049 return "Reading"; 00050 } 00051 return "Unknown"; 00052 } 00053 00063 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); 00064 00068 virtual ~SharedMemoryManager() noexcept; 00069 00070 00074 void Attach(); 00075 00080 int GetBufferForReading(); 00081 00087 int GetBufferForWriting(bool overwrite); 00088 00093 bool ReadyForRead(); 00094 00100 virtual bool ReadyForWrite(bool overwrite); 00101 00106 size_t ReadReadyCount(); 00107 00113 size_t WriteReadyCount(bool overwrite); 00114 00120 std::deque<int> GetBuffersOwnedByManager(bool locked = true); 00121 00127 size_t BufferDataSize(int buffer); 00128 00132 size_t BufferSize() {return (shm_ptr_ != nullptr ? shm_ptr_->buffer_size : 0);} 00133 00138 void ResetReadPos(int buffer); 00139 00144 void ResetWritePos(int buffer); 00150 void IncrementReadPos(int buffer, size_t read); 00151 00158 bool IncrementWritePos(int buffer, size_t written); 00159 00165 bool MoreDataInBuffer(int buffer); 00166 00173 bool CheckBuffer(int buffer, BufferSemaphoreFlags flags); 00174 00180 void MarkBufferFull(int buffer, int destination = -1); 00181 00187 void MarkBufferEmpty(int buffer, bool force = false); 00188 00195 bool ResetBuffer(int buffer); 00196 00200 void GetNewId() { if (manager_id_ < 0 && IsValid()) manager_id_ = shm_ptr_->next_id.fetch_add(1); } 00201 00206 uint16_t GetAttachedCount() const; 00207 00211 void ResetAttachedCount() const { if (manager_id_ == 0 && IsValid()) shm_ptr_->next_id = 1; } 00212 00217 int GetMyId() const { return manager_id_; } 00218 00223 int GetRank()const { return IsValid() ? shm_ptr_->rank : -1; } 00224 00229 void SetRank(int rank) { if (manager_id_ == 0 && IsValid()) shm_ptr_->rank = rank; } 00230 00235 bool IsValid() const { return shm_ptr_ ? true : false; } 00236 00240 bool IsEndOfData() const; 00241 00246 size_t size() const { return IsValid() ? shm_ptr_->buffer_count : 0; } 00247 00255 size_t Write(int buffer, void* data, size_t size); 00256 00264 bool Read(int buffer, void* data, size_t size); 00265 00270 virtual std::string toString(); 00271 00276 uint32_t GetKey() const { return shm_key_; } 00277 00283 void* GetReadPos(int buffer); 00284 00290 void* GetWritePos(int buffer); 00291 00297 void* GetBufferStart(int buffer); 00298 00306 void Detach(bool throwException = false, std::string category = "", std::string message = "", bool force = false); 00307 00312 uint64_t GetBufferTimeout() const { return IsValid() ? shm_ptr_->buffer_timeout_us : 0; } 00313 00318 size_t GetBufferCount() const { return IsValid() ? shm_ptr_->next_sequence_id : 0; } 00319 00324 size_t GetLastSeenBufferID() const { return last_seen_id_; } 00325 00329 size_t GetLowestSeqIDRead() const { return IsValid() ? shm_ptr_->lowest_seq_id_read : 0; } 00330 00335 void SetMinWriteSize(size_t size) { min_write_size_ = size; } 00336 00341 std::list<std::pair<int, BufferSemaphoreFlags>> GetBufferReport(); 00342 00346 void TouchBuffer(int buffer) { return touchBuffer_(getBufferInfo_(buffer)); } 00347 private: 00348 struct ShmBuffer 00349 { 00350 size_t writePos; 00351 size_t readPos; 00352 std::atomic<BufferSemaphoreFlags> sem; 00353 std::atomic<int16_t> sem_id; 00354 std::atomic<size_t> sequence_id; 00355 std::atomic<uint64_t> last_touch_time; 00356 }; 00357 00358 struct ShmStruct 00359 { 00360 std::atomic<unsigned int> reader_pos; 00361 std::atomic<unsigned int> writer_pos; 00362 int buffer_count; 00363 size_t buffer_size; 00364 size_t buffer_timeout_us; 00365 size_t next_sequence_id; 00366 size_t lowest_seq_id_read; 00367 bool destructive_read_mode; 00368 00369 std::atomic<int> next_id; 00370 int rank; 00371 unsigned ready_magic; 00372 }; 00373 00374 uint8_t* dataStart_() const; 00375 uint8_t* bufferStart_(int buffer); 00376 ShmBuffer* getBufferInfo_(int buffer); 00377 bool checkBuffer_(ShmBuffer* buffer, BufferSemaphoreFlags flags, bool exceptions = true); 00378 void touchBuffer_(ShmBuffer* buffer); 00379 00380 ShmStruct requested_shm_parameters_; 00381 00382 int shm_segment_id_; 00383 ShmStruct* shm_ptr_; 00384 uint32_t shm_key_; 00385 int manager_id_; 00386 mutable std::vector<std::mutex> buffer_mutexes_; 00387 mutable std::mutex search_mutex_; 00388 00389 std::atomic<size_t> last_seen_id_; 00390 size_t min_write_size_; 00391 }; 00392 00393 } 00394 00395 #endif // artdaq_core_Core_SharedMemoryManager_hh