$treeview $search $mathjax $extrastylesheet
artdaq_core
v3_06_01
$projectbrief
|
$projectbrief
|
$searchbox |
00001 #ifndef artdaq_core_Core_SharedMemoryManager_hh 00002 #define artdaq_core_Core_SharedMemoryManager_hh 1 00003 00004 #include <atomic> 00005 #include <deque> 00006 #include <list> 00007 #include <mutex> 00008 #include <string> 00009 #include <vector> 00010 #include "artdaq-core/Utilities/TimeUtils.hh" 00011 00012 namespace artdaq { 00017 class SharedMemoryManager 00018 { 00019 public: 00023 enum class BufferSemaphoreFlags 00024 { 00025 Empty, 00026 Writing, 00027 Full, 00028 Reading 00029 }; 00030 00036 static inline std::string FlagToString(BufferSemaphoreFlags flag) 00037 { 00038 switch (flag) 00039 { 00040 case BufferSemaphoreFlags::Empty: 00041 return "Empty"; 00042 case BufferSemaphoreFlags::Writing: 00043 return "Writing"; 00044 case BufferSemaphoreFlags::Full: 00045 return "Full"; 00046 case BufferSemaphoreFlags::Reading: 00047 return "Reading"; 00048 } 00049 return "Unknown"; 00050 } 00051 00061 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); 00062 00066 virtual ~SharedMemoryManager() noexcept; // NOLINT(bugprone-exception-escape) See implementation for more details 00067 00071 bool Attach(size_t timeout_usec = 0); 00072 00077 int GetBufferForReading(); 00078 00084 int GetBufferForWriting(bool overwrite); 00085 00090 bool ReadyForRead(); 00091 00097 virtual bool ReadyForWrite(bool overwrite); 00098 00103 size_t ReadReadyCount(); 00104 00110 size_t WriteReadyCount(bool overwrite); 00111 00117 std::deque<int> GetBuffersOwnedByManager(bool locked = true); 00118 00124 size_t BufferDataSize(int buffer); 00125 00130 size_t BufferSize() { return (shm_ptr_ != nullptr ? shm_ptr_->buffer_size : 0); } 00131 00136 void ResetReadPos(int buffer); 00137 00142 void ResetWritePos(int buffer); 00148 void IncrementReadPos(int buffer, size_t read); 00149 00156 bool IncrementWritePos(int buffer, size_t written); 00157 00163 bool MoreDataInBuffer(int buffer); 00164 00171 bool CheckBuffer(int buffer, BufferSemaphoreFlags flags); 00172 00178 void MarkBufferFull(int buffer, int destination = -1); 00179 00185 void MarkBufferEmpty(int buffer, bool force = false); 00186 00193 bool ResetBuffer(int buffer); 00194 00198 void GetNewId() 00199 { 00200 if (manager_id_ < 0 && IsValid()) manager_id_ = shm_ptr_->next_id.fetch_add(1); 00201 } 00202 00207 uint16_t GetAttachedCount() const; 00208 00212 void ResetAttachedCount() const 00213 { 00214 if (manager_id_ == 0 && IsValid()) shm_ptr_->next_id = 1; 00215 } 00216 00221 int GetMyId() const { return manager_id_; } 00222 00227 int GetRank() const { return IsValid() ? shm_ptr_->rank : -1; } 00228 00233 void SetRank(int rank) 00234 { 00235 if (manager_id_ == 0 && IsValid()) shm_ptr_->rank = rank; 00236 } 00237 00242 bool IsValid() const { return shm_ptr_ ? true : false; } 00243 00247 bool IsEndOfData() const; 00248 00253 size_t size() const { return IsValid() ? shm_ptr_->buffer_count : 0; } 00254 00262 size_t Write(int buffer, void* data, size_t size); 00263 00271 bool Read(int buffer, void* data, size_t size); 00272 00277 virtual std::string toString(); 00278 00283 uint32_t GetKey() const { return shm_key_; } 00284 00290 void* GetReadPos(int buffer); 00291 00297 void* GetWritePos(int buffer); 00298 00304 void* GetBufferStart(int buffer); 00305 00313 void Detach(bool throwException = false, const std::string& category = "", const std::string& message = "", bool force = false); 00314 00319 uint64_t GetBufferTimeout() const { return IsValid() ? shm_ptr_->buffer_timeout_us : 0; } 00320 00325 size_t GetBufferCount() const { return IsValid() ? shm_ptr_->next_sequence_id : 0; } 00326 00331 size_t GetLastSeenBufferID() const { return last_seen_id_; } 00332 00336 size_t GetLowestSeqIDRead() const { return IsValid() ? shm_ptr_->lowest_seq_id_read : 0; } 00337 00342 void SetMinWriteSize(size_t size) { min_write_size_ = size; } 00343 00348 std::vector<std::pair<int, BufferSemaphoreFlags>> GetBufferReport(); 00349 00353 void TouchBuffer(int buffer) { return touchBuffer_(getBufferInfo_(buffer)); } 00354 00355 private: 00356 SharedMemoryManager(SharedMemoryManager const&) = delete; 00357 SharedMemoryManager(SharedMemoryManager&&) = delete; 00358 SharedMemoryManager& operator=(SharedMemoryManager const&) = delete; 00359 SharedMemoryManager& operator=(SharedMemoryManager&&) = delete; 00360 00361 struct ShmBuffer 00362 { 00363 size_t writePos; 00364 size_t readPos; 00365 std::atomic<BufferSemaphoreFlags> sem; 00366 std::atomic<int16_t> sem_id; 00367 std::atomic<size_t> sequence_id; 00368 std::atomic<uint64_t> last_touch_time; 00369 }; 00370 00371 struct ShmStruct 00372 { 00373 std::atomic<unsigned int> reader_pos; 00374 std::atomic<unsigned int> writer_pos; 00375 int buffer_count; 00376 size_t buffer_size; 00377 size_t buffer_timeout_us; 00378 size_t next_sequence_id; 00379 size_t lowest_seq_id_read; 00380 bool destructive_read_mode; 00381 00382 std::atomic<int> next_id; 00383 int rank; 00384 unsigned ready_magic; 00385 }; 00386 00387 inline uint8_t* dataStart_() const 00388 { 00389 if (shm_ptr_ == nullptr) return nullptr; 00390 return reinterpret_cast<uint8_t*>(shm_ptr_ + 1) + shm_ptr_->buffer_count * sizeof(ShmBuffer); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast,cppcoreguidelines-pro-bounds-pointer-arithmetic) 00391 } 00392 00393 inline uint8_t* bufferStart_(int buffer) 00394 { 00395 if (shm_ptr_ == nullptr) return nullptr; 00396 if (buffer >= requested_shm_parameters_.buffer_count && buffer >= shm_ptr_->buffer_count) Detach(true, "ArgumentOutOfRange", "The specified buffer does not exist!"); 00397 return dataStart_() + buffer * shm_ptr_->buffer_size; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) 00398 } 00399 00400 inline ShmBuffer* getBufferInfo_(int buffer) 00401 { 00402 if (shm_ptr_ == nullptr) return nullptr; 00403 // Check local variable first, but re-check shared memory 00404 if (buffer >= requested_shm_parameters_.buffer_count && buffer >= shm_ptr_->buffer_count) 00405 Detach(true, "ArgumentOutOfRange", "The specified buffer does not exist!"); 00406 return buffer_ptrs_[buffer]; 00407 } 00408 bool checkBuffer_(ShmBuffer* buffer, BufferSemaphoreFlags flags, bool exceptions = true); 00409 void touchBuffer_(ShmBuffer* buffer); 00410 00411 ShmStruct requested_shm_parameters_; 00412 00413 int shm_segment_id_; 00414 ShmStruct* shm_ptr_; 00415 uint32_t shm_key_; 00416 int manager_id_; 00417 std::vector<ShmBuffer*> buffer_ptrs_; 00418 mutable std::vector<std::mutex> buffer_mutexes_; 00419 mutable std::mutex search_mutex_; 00420 00421 std::atomic<size_t> last_seen_id_; 00422 size_t min_write_size_; 00423 }; 00424 00425 } // namespace artdaq 00426 00427 #endif // artdaq_core_Core_SharedMemoryManager_hh