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 <unordered_map> 00010 #include <set> 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 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() { return ReadReadyCount() > 0; } 00094 00100 bool ReadyForWrite(bool overwrite) { return WriteReadyCount(overwrite) > 0; } 00101 00106 size_t ReadReadyCount(); 00107 00113 size_t WriteReadyCount(bool overwrite); 00114 00119 std::deque<int> GetBuffersOwnedByManager(); 00120 00126 size_t BufferDataSize(int buffer); 00127 00132 void ResetReadPos(int buffer); 00133 00138 void ResetWritePos(int buffer); 00144 void IncrementReadPos(int buffer, size_t read); 00145 00151 void IncrementWritePos(int buffer, size_t written); 00152 00158 bool MoreDataInBuffer(int buffer); 00159 00166 bool CheckBuffer(int buffer, BufferSemaphoreFlags flags); 00167 00173 void MarkBufferFull(int buffer, int destination = -1); 00174 00180 void MarkBufferEmpty(int buffer, bool force = false); 00181 00188 bool ResetBuffer(int buffer); 00189 00193 void GetNewId() { if (manager_id_ < 0 && IsValid()) manager_id_ = shm_ptr_->next_id.fetch_add(1); } 00194 00199 uint16_t GetAttachedCount() const { return IsValid() ? shm_ptr_->next_id.load() - 1 : -1; } 00200 00204 void ResetAttachedCount() const { if (manager_id_ == 0 && IsValid()) shm_ptr_->next_id = 1; } 00205 00210 int GetMyId() const { return manager_id_; } 00211 00216 int GetRank()const { return IsValid() ? shm_ptr_->rank : -1; } 00217 00222 void SetRank(int rank) { if (manager_id_ == 0 && IsValid()) shm_ptr_->rank = rank; } 00223 00228 bool IsValid() const { return shm_ptr_ ? true : false; } 00229 00234 size_t size() const { return IsValid() ? shm_ptr_->buffer_count : 0; } 00235 00243 size_t Write(int buffer, void* data, size_t size); 00244 00252 bool Read(int buffer, void* data, size_t size); 00253 00258 virtual std::string toString(); 00259 00264 uint32_t GetKey() const { return shm_key_; } 00265 00271 void* GetReadPos(int buffer); 00272 00278 void* GetWritePos(int buffer); 00279 00285 void* GetBufferStart(int buffer); 00286 00293 void Detach(bool throwException = false, std::string category = "", std::string message = ""); 00294 00299 uint64_t GetBufferTimeout() const { return IsValid() ? shm_ptr_->buffer_timeout_us : 0; } 00300 00305 size_t GetBufferCount() const { return IsValid() ? shm_ptr_->next_sequence_id : 0; } 00306 00311 size_t GetLastSeenBufferID() const { return last_seen_id_; } 00312 00316 size_t GetLowestSeqIDRead() const { return IsValid() ? shm_ptr_->lowest_seq_id_read : 0; } 00317 00322 void SetMinWriteSize(size_t size) { min_write_size_ = size; } 00323 private: 00324 struct ShmBuffer 00325 { 00326 size_t writePos; 00327 size_t readPos; 00328 std::atomic<BufferSemaphoreFlags> sem; 00329 std::atomic<int16_t> sem_id; 00330 std::atomic<size_t> sequence_id; 00331 std::atomic<uint64_t> last_touch_time; 00332 }; 00333 00334 struct ShmStruct 00335 { 00336 std::atomic<unsigned int> reader_pos; 00337 std::atomic<unsigned int> writer_pos; 00338 int buffer_count; 00339 size_t buffer_size; 00340 size_t buffer_timeout_us; 00341 size_t next_sequence_id; 00342 size_t lowest_seq_id_read; 00343 bool destructive_read_mode; 00344 00345 std::atomic<int> next_id; 00346 int rank; 00347 unsigned ready_magic; 00348 }; 00349 00350 uint8_t* dataStart_() const; 00351 uint8_t* bufferStart_(int buffer); 00352 ShmBuffer* getBufferInfo_(int buffer); 00353 bool checkBuffer_(ShmBuffer* buffer, BufferSemaphoreFlags flags, bool exceptions = true); 00354 void touchBuffer_(ShmBuffer* buffer); 00355 00356 ShmStruct requested_shm_parameters_; 00357 00358 int shm_segment_id_; 00359 ShmStruct* shm_ptr_; 00360 uint32_t shm_key_; 00361 int manager_id_; 00362 mutable std::unordered_map<int, std::mutex> buffer_mutexes_; 00363 mutable std::mutex search_mutex_; 00364 00365 size_t last_seen_id_; 00366 size_t min_write_size_; 00367 }; 00368 00369 } 00370 00371 #endif // artdaq_core_Core_SharedMemoryManager_hh