4 #include "cetlib_except/exception.h"
5 #include "artdaq-core/Core/SharedMemoryManager.hh"
6 #include "artdaq-core/Utilities/TraceLock.hh"
9 #define TRACE_NAME "SharedMemoryManager"
20 requested_shm_parameters_.buffer_count = buffer_count;
21 requested_shm_parameters_.buffer_size = buffer_size;
22 requested_shm_parameters_.buffer_timeout_us = buffer_timeout_us;
23 requested_shm_parameters_.destructive_read_mode = destructive_read_mode;
30 TLOG(5) <<
"~SharedMemoryManager called" << TLOG_ENDL;
32 TLOG(5) <<
"~SharedMemoryManager done" << TLOG_ENDL;
39 if (manager_id_ == 0)
return;
42 auto start_time = std::chrono::steady_clock::now();
44 size_t shmSize = requested_shm_parameters_.buffer_count * (requested_shm_parameters_.buffer_size +
sizeof(ShmBuffer)) +
sizeof(ShmStruct);
46 shm_segment_id_ = shmget(shm_key_, shmSize, 0666);
47 if (shm_segment_id_ == -1 && requested_shm_parameters_.buffer_count > 0 && manager_id_ <= 0)
49 TLOG(TLVL_DEBUG) <<
"Creating shared memory segment with key 0x" << std::hex << shm_key_ << TLOG_ENDL;
50 shm_segment_id_ = shmget(shm_key_, shmSize, IPC_CREAT | 0666);
56 shm_segment_id_ = shmget(shm_key_, shmSize, 0666);
59 TLOG(TLVL_DEBUG) <<
"shm_key == 0x" << std::hex << shm_key_ <<
", shm_segment_id == " << shm_segment_id_ << TLOG_ENDL;
61 if (shm_segment_id_ > -1)
64 <<
"Attached to shared memory segment with ID = " << shm_segment_id_
65 <<
" and size " << shmSize
66 <<
" bytes" << TLOG_ENDL;
67 shm_ptr_ = (ShmStruct*)shmat(shm_segment_id_, 0, 0);
69 <<
"Attached to shared memory segment at address "
70 << std::hex << (
void*)shm_ptr_ << std::dec << TLOG_ENDL;
71 if (shm_ptr_ && shm_ptr_ != (
void *)-1)
75 if (shm_ptr_->ready_magic == 0xCAFE1111)
77 TLOG(TLVL_ERROR) <<
"Owner encountered already-initialized Shared Memory!" << TLOG_ENDL;
80 TLOG(TLVL_DEBUG) <<
"Owner initializing Shared Memory" << TLOG_ENDL;
81 shm_ptr_->next_id = 1;
82 shm_ptr_->next_sequence_id = 0;
83 shm_ptr_->reader_pos = 0;
84 shm_ptr_->writer_pos = 0;
85 shm_ptr_->buffer_size = requested_shm_parameters_.buffer_size;
86 shm_ptr_->buffer_count = requested_shm_parameters_.buffer_count;
87 shm_ptr_->buffer_timeout_us = requested_shm_parameters_.buffer_timeout_us;
88 shm_ptr_->destructive_read_mode = requested_shm_parameters_.destructive_read_mode;
90 for (
int ii = 0; ii < static_cast<int>(requested_shm_parameters_.buffer_count); ++ii)
92 getBufferInfo_(ii)->writePos = 0;
93 getBufferInfo_(ii)->readPos = 0;
94 getBufferInfo_(ii)->sem = BufferSemaphoreFlags::Empty;
95 getBufferInfo_(ii)->sem_id = -1;
99 shm_ptr_->ready_magic = 0xCAFE1111;
103 TLOG(TLVL_DEBUG) <<
"Waiting for owner to initalize Shared Memory" << TLOG_ENDL;
104 while (shm_ptr_->ready_magic != 0xCAFE1111) { usleep(1000); }
105 TLOG(TLVL_DEBUG) <<
"Getting ID from Shared Memory" << TLOG_ENDL;
107 shm_ptr_->lowest_seq_id_read = 0;
108 TLOG(TLVL_DEBUG) <<
"Getting Shared Memory Size parameters" << TLOG_ENDL;
111 TLOG(TLVL_DEBUG) <<
"Initialization Complete: "
112 <<
"key: 0x" << std::hex << shm_key_
113 <<
", manager ID: " << manager_id_
114 <<
", Buffer size: " << std::to_string(shm_ptr_->buffer_size)
115 <<
", Buffer count: " << std::to_string(shm_ptr_->buffer_count) << TLOG_ENDL;
120 TLOG(TLVL_ERROR) <<
"Failed to attach to shared memory segment "
121 << shm_segment_id_ << TLOG_ENDL;
126 TLOG(TLVL_ERROR) <<
"Failed to connect to shared memory segment"
127 <<
", errno = " << strerror(errno) <<
". Please check "
128 <<
"if a stale shared memory segment needs to "
129 <<
"be cleaned up. (ipcs, ipcrm -m <segId>)" << TLOG_ENDL;
136 TLOG(13) <<
"GetBufferForReading BEGIN" << TLOG_ENDL;
139 TraceLock lk(search_mutex_, 11,
"GetBufferForReadingSearch");
140 auto rp = shm_ptr_->reader_pos.load();
142 TLOG(13) <<
"GetBufferForReading lock acquired, scanning buffers" << TLOG_ENDL;
147 ShmBuffer* buffer_ptr =
nullptr;
149 for (
auto ii = 0; ii < shm_ptr_->buffer_count; ++ii)
151 auto buffer = (ii + rp) % shm_ptr_->buffer_count;
154 TLOG(14) <<
"GetBufferForReading Checking if buffer " << buffer <<
" is stale" << TLOG_ENDL;
157 auto buf = getBufferInfo_(buffer);
158 TLOG(14) <<
"GetBufferForReading: Buffer " << buffer <<
": sem=" << FlagToString(buf->sem) <<
" (expected " << FlagToString(BufferSemaphoreFlags::Full) <<
"), sem_id=" << buf->sem_id <<
" )" << TLOG_ENDL;
159 if (buf->sem == BufferSemaphoreFlags::Full && (buf->sem_id == -1 || buf->sem_id == manager_id_) && buf->sequence_id > last_seen_id_)
161 if (buf->sequence_id < seqID)
164 seqID = buf->sequence_id;
170 if (!buffer_ptr || (buffer_ptr && buffer_ptr->sem_id != -1 && buffer_ptr->sem_id != manager_id_))
177 TLOG(13) <<
"GetBufferForReading Found buffer " << buffer_num << TLOG_ENDL;
178 buffer_ptr->sem_id = manager_id_;
179 buffer_ptr->sem = BufferSemaphoreFlags::Reading;
180 if (buffer_ptr->sem_id != manager_id_) {
continue; }
181 buffer_ptr->readPos = 0;
182 touchBuffer_(buffer_ptr);
183 if (buffer_ptr->sem_id != manager_id_) {
continue; }
184 if (shm_ptr_->destructive_read_mode && shm_ptr_->lowest_seq_id_read == last_seen_id_)
186 shm_ptr_->lowest_seq_id_read = seqID;
188 last_seen_id_ = seqID;
189 if (shm_ptr_->destructive_read_mode) shm_ptr_->reader_pos = (buffer_num + 1) % shm_ptr_->buffer_count;
194 TLOG(13) <<
"GetBufferForReading returning -1 because no buffers are ready" << TLOG_ENDL;
200 TLOG(14) <<
"GetBufferForWriting BEGIN" << TLOG_ENDL;
202 TraceLock lk(search_mutex_, 12,
"GetBufferForWritingSearch");
203 auto wp = shm_ptr_->writer_pos.load();
206 for (
auto ii = 0; ii < shm_ptr_->buffer_count; ++ii)
208 auto buffer = (ii + wp) % shm_ptr_->buffer_count;
212 auto buf = getBufferInfo_(buffer);
213 if (buf->sem == BufferSemaphoreFlags::Empty)
215 buf->sem_id = manager_id_;
216 buf->sem = BufferSemaphoreFlags::Writing;
217 if (buf->sem_id != manager_id_)
continue;
218 buf->sequence_id = ++shm_ptr_->next_sequence_id;
220 shm_ptr_->writer_pos = (buffer + 1) % shm_ptr_->buffer_count;
222 TLOG(14) <<
"GetBufferForWriting returning " << buffer << TLOG_ENDL;
230 for (
auto ii = 0; ii < shm_ptr_->buffer_count; ++ii)
232 auto buffer = (ii + wp) % shm_ptr_->buffer_count;
236 auto buf = getBufferInfo_(buffer);
237 if (buf->sem == BufferSemaphoreFlags::Full)
239 buf->sem_id = manager_id_;
240 buf->sem = BufferSemaphoreFlags::Writing;
241 if (buf->sem_id != manager_id_)
continue;
242 buf->sequence_id = ++shm_ptr_->next_sequence_id;
244 shm_ptr_->writer_pos = (buffer + 1) % shm_ptr_->buffer_count;
246 TLOG(14) <<
"GetBufferForWriting returning " << buffer << TLOG_ENDL;
252 for (
auto ii = 0; ii < shm_ptr_->buffer_count; ++ii)
254 auto buffer = (ii + wp) % shm_ptr_->buffer_count;
258 auto buf = getBufferInfo_(buffer);
259 if (buf->sem == BufferSemaphoreFlags::Reading)
261 buf->sem_id = manager_id_;
262 buf->sem = BufferSemaphoreFlags::Writing;
263 if (buf->sem_id != manager_id_)
continue;
264 buf->sequence_id = ++shm_ptr_->next_sequence_id;
266 shm_ptr_->writer_pos = (buffer + 1) % shm_ptr_->buffer_count;
267 TLOG(14) <<
"GetBufferForWriting returning " << buffer << TLOG_ENDL;
274 TLOG(14) <<
"GetBufferForWriting Returning -1 because no buffers are ready" << TLOG_ENDL;
280 if (!IsValid())
return 0;
281 TLOG(23) <<
"ReadReadyCount BEGIN" << TLOG_ENDL;
283 TraceLock lk(search_mutex_, 14,
"ReadReadyCountSearch");
285 for (
auto ii = 0; ii < shm_ptr_->buffer_count; ++ii)
287 TLOG(24) <<
"ReadReadyCount: Checking if buffer " << ii <<
" is stale." << TLOG_ENDL;
289 auto buf = getBufferInfo_(ii);
290 TLOG(24) <<
"ReadReadyCount: Buffer " << ii <<
": sem=" << FlagToString(buf->sem) <<
" (expected " << FlagToString(BufferSemaphoreFlags::Full) <<
"), sem_id=" << buf->sem_id <<
" )" << TLOG_ENDL;
291 if (buf->sem == BufferSemaphoreFlags::Full && (buf->sem_id == -1 || buf->sem_id == manager_id_) && buf->sequence_id > last_seen_id_)
293 TLOG(24) <<
"ReadReadyCount: Buffer " << ii <<
" is either unowned or owned by this manager, and is marked full." << TLOG_ENDL;
298 TLOG(23) << TLOG_ENDL;
304 if (!IsValid())
return 0;
306 TraceLock lk(search_mutex_, 15,
"WriteReadyCountSearch");
308 for (
auto ii = 0; ii < shm_ptr_->buffer_count; ++ii)
311 auto buf = getBufferInfo_(ii);
312 if ((buf->sem == BufferSemaphoreFlags::Empty && buf->sem_id == -1)
313 || (overwrite && buf->sem != BufferSemaphoreFlags::Writing))
324 std::deque<int> output;
325 if (!IsValid())
return output;
326 TraceLock lk(search_mutex_, 16,
"GetOwnedSearch");
327 for (
auto ii = 0; ii < shm_ptr_->buffer_count; ++ii)
329 auto buf = getBufferInfo_(ii);
330 if (buf->sem_id == manager_id_)
332 output.push_back(ii);
342 TraceLock lk(buffer_mutexes_[buffer], 17,
"DataSizeBuffer" + std::to_string(buffer));
343 auto buf = getBufferInfo_(buffer);
345 return buf->writePos;
352 TraceLock lk(buffer_mutexes_[buffer], 18,
"ResetReadPosBuffer" + std::to_string(buffer));
353 auto buf = getBufferInfo_(buffer);
361 TraceLock lk(buffer_mutexes_[buffer], 18,
"ResetWritePosBuffer" + std::to_string(buffer));
362 auto buf = getBufferInfo_(buffer);
363 checkBuffer_(buf, BufferSemaphoreFlags::Writing);
371 TraceLock lk(buffer_mutexes_[buffer], 19,
"IncReadPosBuffer" + std::to_string(buffer));
372 auto buf = getBufferInfo_(buffer);
374 TLOG(15) << TLOG_ENDL;
375 buf->readPos = buf->readPos + read;
376 TLOG(15) << TLOG_ENDL;
377 if (read == 0) Detach(
true,
"LogicError",
"Cannot increment Read pos by 0! (buffer=" + std::to_string(buffer) +
", readPos=" + std::to_string(buf->readPos) +
", writePos=" + std::to_string(buf->writePos) +
")");
383 TraceLock lk(buffer_mutexes_[buffer], 20,
"IncWritePosBuffer" + std::to_string(buffer));
384 auto buf = getBufferInfo_(buffer);
386 TLOG(16) << TLOG_ENDL;
387 buf->writePos += written;
388 TLOG(16) << TLOG_ENDL;
389 if (written == 0) Detach(
true,
"LogicError",
"Cannot increment Write pos by 0!");
395 TraceLock lk(buffer_mutexes_[buffer], 21,
"MoreDataInBuffer" + std::to_string(buffer));
396 auto buf = getBufferInfo_(buffer);
397 TLOG(17) << TLOG_ENDL;
398 return buf->readPos < buf->writePos;
404 TraceLock lk(buffer_mutexes_[buffer], 22,
"CheckBuffer" + std::to_string(buffer));
405 return checkBuffer_(getBufferInfo_(buffer), flags,
false);
411 TraceLock lk(buffer_mutexes_[buffer], 23,
"FillBuffer" + std::to_string(buffer));
412 auto shmBuf = getBufferInfo_(buffer);
413 touchBuffer_(shmBuf);
414 if (shmBuf->sem_id == manager_id_)
416 if (shmBuf->sem != BufferSemaphoreFlags::Full)
417 shmBuf->sem = BufferSemaphoreFlags::Full;
419 shmBuf->sem_id = destination;
425 TLOG(18) <<
"MarkBufferEmpty BEGIN" << TLOG_ENDL;
427 TraceLock lk(buffer_mutexes_[buffer], 24,
"EmptyBuffer" + std::to_string(buffer));
428 auto shmBuf = getBufferInfo_(buffer);
431 checkBuffer_(shmBuf, BufferSemaphoreFlags::Reading,
true);
433 touchBuffer_(shmBuf);
436 shmBuf->sem = BufferSemaphoreFlags::Full;
438 if ((force && (manager_id_ == 0 || manager_id_ == shmBuf->sem_id)) || (!force && shm_ptr_->destructive_read_mode))
440 TLOG(18) <<
"MarkBufferEmpty Resetting buffer to Empty state" << TLOG_ENDL;
441 shmBuf->writePos = 0;
442 shmBuf->sem = BufferSemaphoreFlags::Empty;
443 if (shm_ptr_->reader_pos == static_cast<unsigned>(buffer) && !shm_ptr_->destructive_read_mode)
445 TLOG(18) <<
"MarkBufferEmpty Broadcast mode; incrementing reader_pos" << TLOG_ENDL;
446 shm_ptr_->reader_pos = (buffer + 1) % shm_ptr_->buffer_count;
450 TLOG(18) <<
"MarkBufferEmpty END" << TLOG_ENDL;
456 TraceLock lk(buffer_mutexes_[buffer], 25,
"ResetBuffer" + std::to_string(buffer));
457 auto shmBuf = getBufferInfo_(buffer);
469 if (delta > 0xFFFFFFFF) {
470 TLOG(TLVL_TRACE) <<
"Buffer has touch time in the future, setting it to current time and ignoring..." << TLOG_ENDL;
474 if (delta <= shm_ptr_->buffer_timeout_us || shmBuf->sem == BufferSemaphoreFlags::Empty)
return false;
475 TLOG(TLVL_TRACE) <<
"Buffer " << buffer <<
" is stale, time=" <<
TimeUtils::gettimeofday_us() <<
", last touch=" << shmBuf->last_touch_time <<
", d=" << delta <<
", timeout=" << shm_ptr_->buffer_timeout_us << TLOG_ENDL;
477 if (shmBuf->sem_id == manager_id_ && shmBuf->sem == BufferSemaphoreFlags::Writing)
481 if (!shm_ptr_->destructive_read_mode && shmBuf->sem == BufferSemaphoreFlags::Full)
483 TLOG(TLVL_DEBUG) <<
"Resetting old broadcast mode buffer" << TLOG_ENDL;
484 shmBuf->writePos = 0;
485 shmBuf->sem = BufferSemaphoreFlags::Empty;
487 if (shm_ptr_->reader_pos == static_cast<unsigned>(buffer)) shm_ptr_->reader_pos = (buffer + 1) % shm_ptr_->buffer_count;
491 if (shmBuf->sem_id != manager_id_ && shmBuf->sem == BufferSemaphoreFlags::Reading)
493 TLOG(TLVL_WARNING) <<
"Stale Read buffer ( " << delta <<
" / " << shm_ptr_->buffer_timeout_us <<
" us ) detected! Resetting..." << TLOG_ENDL;
495 shmBuf->sem = BufferSemaphoreFlags::Full;
504 TLOG(19) <<
"Write BEGIN" << TLOG_ENDL;
506 TraceLock lk(buffer_mutexes_[buffer], 26,
"WriteBuffer" + std::to_string(buffer));
507 auto shmBuf = getBufferInfo_(buffer);
508 checkBuffer_(shmBuf, BufferSemaphoreFlags::Writing);
509 touchBuffer_(shmBuf);
510 TLOG(19) << TLOG_ENDL;
511 if (shmBuf->writePos + size > shm_ptr_->buffer_size) Detach(
true,
"SharedMemoryWrite",
"Attempted to write more data than fits into Shared Memory! \nRe-run with a larger buffer size!");
513 auto pos = GetWritePos(buffer);
514 memcpy(pos, data, size);
515 shmBuf->writePos = shmBuf->writePos + size;
516 if (shmBuf->sequence_id > last_seen_id_)
518 last_seen_id_ = shmBuf->sequence_id;
520 TLOG(19) <<
"Write END" << TLOG_ENDL;
527 TraceLock lk(buffer_mutexes_[buffer], 27,
"ReadBuffer" + std::to_string(buffer));
528 auto shmBuf = getBufferInfo_(buffer);
529 checkBuffer_(shmBuf, BufferSemaphoreFlags::Reading);
530 touchBuffer_(shmBuf);
531 if (shmBuf->readPos + size > shm_ptr_->buffer_size) Detach(
true,
"SharedMemoryRead",
"Attempted to read more data than exists in Shared Memory!");
533 auto pos = GetReadPos(buffer);
534 memcpy(data, pos, size);
535 shmBuf->readPos += size;
536 touchBuffer_(shmBuf);
537 return checkBuffer_(shmBuf, BufferSemaphoreFlags::Reading,
false);
542 std::ostringstream ostr;
543 ostr <<
"ShmStruct: " << std::endl
544 <<
"Reader Position: " << shm_ptr_->reader_pos << std::endl
545 <<
"Writer Position: " << shm_ptr_->writer_pos << std::endl
546 <<
"Next ID Number: " << shm_ptr_->next_id << std::endl
547 <<
"Buffer Count: " << shm_ptr_->buffer_count << std::endl
548 <<
"Buffer Size: " << std::to_string(shm_ptr_->buffer_size) <<
" bytes" << std::endl
549 <<
"Buffers Written: " << std::to_string(shm_ptr_->next_sequence_id) << std::endl
550 <<
"Rank of Writer: " << shm_ptr_->rank << std::endl
551 <<
"Ready Magic Bytes: 0x" << std::hex << shm_ptr_->ready_magic << std::endl << std::endl;
553 for (
auto ii = 0; ii < shm_ptr_->buffer_count; ++ii)
555 auto buf = getBufferInfo_(ii);
556 ostr <<
"ShmBuffer " << std::dec << ii << std::endl
557 <<
"sequenceID: " << std::to_string(buf->sequence_id) << std::endl
558 <<
"writePos: " << std::to_string(buf->writePos) << std::endl
559 <<
"readPos: " << std::to_string(buf->readPos) << std::endl
560 <<
"sem: " << FlagToString(buf->sem) << std::endl
561 <<
"Owner: " << std::to_string(buf->sem_id.load()) << std::endl
562 <<
"Last Touch Time: " << std::to_string(buf->last_touch_time / 1000000.0) << std::endl << std::endl;
570 auto buf = getBufferInfo_(buffer);
571 return bufferStart_(buffer) + buf->readPos;
575 auto buf = getBufferInfo_(buffer);
576 return bufferStart_(buffer) + buf->writePos;
581 return bufferStart_(buffer);
584 uint8_t* artdaq::SharedMemoryManager::dataStart_()
const
586 return reinterpret_cast<uint8_t*
>(shm_ptr_ + 1) + shm_ptr_->buffer_count *
sizeof(ShmBuffer);
589 uint8_t* artdaq::SharedMemoryManager::bufferStart_(
int buffer)
591 if (buffer >= shm_ptr_->buffer_count) Detach(
true,
"ArgumentOutOfRange",
"The specified buffer does not exist!");
592 return dataStart_() + buffer * shm_ptr_->buffer_size;
595 artdaq::SharedMemoryManager::ShmBuffer* artdaq::SharedMemoryManager::getBufferInfo_(
int buffer)
597 if (buffer >= shm_ptr_->buffer_count) Detach(
true,
"ArgumentOutOfRange",
"The specified buffer does not exist!");
598 return reinterpret_cast<ShmBuffer*
>(
reinterpret_cast<uint8_t*
>(shm_ptr_ + 1) + buffer *
sizeof(ShmBuffer));
601 bool artdaq::SharedMemoryManager::checkBuffer_(ShmBuffer* buffer, BufferSemaphoreFlags flags,
bool exceptions)
605 if (buffer->sem != flags) Detach(
true,
"StateAccessViolation",
"Shared Memory buffer is not in the correct state! (expected " + FlagToString(flags) +
", actual " + FlagToString(buffer->sem) +
")");
606 if (buffer->sem_id != manager_id_) Detach(
true,
"OwnerAccessViolation",
"Shared Memory buffer is not owned by this manager instance!");
608 bool ret = (buffer->sem_id == manager_id_ || (buffer->sem_id == -1 && (flags == BufferSemaphoreFlags::Full || flags == BufferSemaphoreFlags::Empty))) && buffer->sem == flags;
612 TLOG(TLVL_WARNING) <<
"CheckBuffer detected issue with buffer " << std::to_string(buffer->sequence_id) <<
"!"
613 <<
" ID: " << buffer->sem_id <<
" (" << manager_id_ <<
"), Flag: " << FlagToString(buffer->sem) <<
" (" << FlagToString(flags) <<
"). "
614 <<
"ID -1 is okay if desired flag is \"Full\" or \"Empty\"." << TLOG_ENDL;
620 void artdaq::SharedMemoryManager::touchBuffer_(ShmBuffer* buffer)
622 if (buffer->sem_id != manager_id_)
return;
623 TLOG(TLVL_TRACE) <<
"touchBuffer_: Touching buffer with sequence_id " << std::to_string(buffer->sequence_id) << TLOG_ENDL;
631 auto bufs = GetBuffersOwnedByManager();
632 for (
auto buf : bufs)
634 auto shmBuf = getBufferInfo_(buf);
635 if (shmBuf->sem == BufferSemaphoreFlags::Writing)
637 shmBuf->sem = BufferSemaphoreFlags::Empty;
639 else if (shmBuf->sem == BufferSemaphoreFlags::Reading)
641 shmBuf->sem = BufferSemaphoreFlags::Full;
653 if (manager_id_ == 0 && shm_segment_id_ > -1)
655 shmctl(shm_segment_id_, IPC_RMID, NULL);
658 if (category.size() > 0 && message.size() > 0)
660 TLOG(TLVL_ERROR) << category <<
": " << message << TLOG_ENDL;
664 throw cet::exception(category) << message;
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.
constexpr size_t GetElapsedTimeMilliseconds(std::chrono::steady_clock::time_point then, std::chrono::steady_clock::time_point now=std::chrono::steady_clock::now())
Gets the number of milliseconds in the given time interval
void ResetReadPos(int buffer)
Set the read position of the given buffer to the beginning of the buffer.
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.
BufferSemaphoreFlags
The BufferSemaphoreFlags enumeration represents the different possible "states" of a given shared mem...
size_t BufferDataSize(int buffer)
Get the current size of the buffer's data.
void Attach()
Reconnect to the shared memory segment.
virtual ~SharedMemoryManager() noexcept
SharedMemoryManager Destructor.
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...
bool CheckBuffer(int buffer, BufferSemaphoreFlags flags)
Check both semaphore conditions (Mode flag and manager ID) for a given buffer.
void IncrementWritePos(int buffer, size_t written)
Increment the write position for a given buffer.
The TraceLock class allows a user to debug the acquisition and releasing of locks, by wrapping the unique_lock<std::mutex> API with TRACE calls.
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.
void ResetWritePos(int buffer)
Set the write position of the given buffer to the beginning of the buffer.
std::deque< int > GetBuffersOwnedByManager()
Get the list of all buffers currently owned by this manager instance.
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.
void Detach(bool throwException=false, std::string category="", std::string message="")
Detach from the Shared Memory segment, optionally throwing a cet::exception with the specified proper...
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.
int GetBufferForWriting(bool overwrite)
Finds a buffer that is ready to be written to, and reserves it for the calling manager.
size_t WriteReadyCount(bool overwrite)
Count the number of buffers that are ready for writing.
uint64_t gettimeofday_us()
Get the current time of day in microseconds (from gettimeofday system call)
int GetBufferForReading()
Finds a buffer that is ready to be read, and reserves it for the calling manager. ...