1 #define TRACE_NAME "SharedMemoryManager"
5 #include "cetlib_except/exception.h"
6 #include "artdaq-core/Core/SharedMemoryManager.hh"
7 #include "artdaq-core/Utilities/TraceLock.hh"
17 requested_shm_parameters_.buffer_count = buffer_count;
18 requested_shm_parameters_.buffer_size = buffer_size;
19 requested_shm_parameters_.buffer_timeout_us = buffer_timeout_us;
20 requested_shm_parameters_.destructive_read_mode = destructive_read_mode;
27 TLOG(5) <<
"~SharedMemoryManager called" << TLOG_ENDL;
29 TLOG(5) <<
"~SharedMemoryManager done" << TLOG_ENDL;
36 if (manager_id_ == 0)
return;
39 auto start_time = std::chrono::steady_clock::now();
41 size_t shmSize = requested_shm_parameters_.buffer_count * (requested_shm_parameters_.buffer_size +
sizeof(ShmBuffer)) +
sizeof(ShmStruct);
43 shm_segment_id_ = shmget(shm_key_, shmSize, 0666);
44 if (shm_segment_id_ == -1 && requested_shm_parameters_.buffer_count > 0 && manager_id_ <= 0)
46 TLOG(TLVL_DEBUG) <<
"Creating shared memory segment with key 0x" << std::hex << shm_key_ << TLOG_ENDL;
47 shm_segment_id_ = shmget(shm_key_, shmSize, IPC_CREAT | 0666);
53 shm_segment_id_ = shmget(shm_key_, shmSize, 0666);
56 TLOG(TLVL_DEBUG) <<
"shm_key == 0x" << std::hex << shm_key_ <<
", shm_segment_id == " << shm_segment_id_ << TLOG_ENDL;
58 if (shm_segment_id_ > -1)
61 <<
"Attached to shared memory segment with ID = " << shm_segment_id_
62 <<
" and size " << shmSize
63 <<
" bytes" << TLOG_ENDL;
64 shm_ptr_ = (ShmStruct*)shmat(shm_segment_id_, 0, 0);
66 <<
"Attached to shared memory segment at address "
67 << std::hex << (
void*)shm_ptr_ << std::dec << TLOG_ENDL;
68 if (shm_ptr_ && shm_ptr_ != (
void *)-1)
72 if (shm_ptr_->ready_magic == 0xCAFE1111)
74 TLOG(TLVL_ERROR) <<
"Owner encountered already-initialized Shared Memory!" << TLOG_ENDL;
77 TLOG(TLVL_DEBUG) <<
"Owner initializing Shared Memory" << TLOG_ENDL;
78 shm_ptr_->next_id = 1;
79 shm_ptr_->next_sequence_id = 0;
80 shm_ptr_->reader_pos = 0;
81 shm_ptr_->writer_pos = 0;
82 shm_ptr_->buffer_size = requested_shm_parameters_.buffer_size;
83 shm_ptr_->buffer_count = requested_shm_parameters_.buffer_count;
84 shm_ptr_->buffer_timeout_us = requested_shm_parameters_.buffer_timeout_us;
85 shm_ptr_->destructive_read_mode = requested_shm_parameters_.destructive_read_mode;
87 for (
int ii = 0; ii < static_cast<int>(requested_shm_parameters_.buffer_count); ++ii)
89 getBufferInfo_(ii)->writePos = 0;
90 getBufferInfo_(ii)->readPos = 0;
91 getBufferInfo_(ii)->sem = BufferSemaphoreFlags::Empty;
92 getBufferInfo_(ii)->sem_id = -1;
96 shm_ptr_->ready_magic = 0xCAFE1111;
100 TLOG(TLVL_DEBUG) <<
"Waiting for owner to initalize Shared Memory" << TLOG_ENDL;
101 while (shm_ptr_->ready_magic != 0xCAFE1111) { usleep(1000); }
102 TLOG(TLVL_DEBUG) <<
"Getting ID from Shared Memory" << TLOG_ENDL;
104 shm_ptr_->lowest_seq_id_read = 0;
105 TLOG(TLVL_DEBUG) <<
"Getting Shared Memory Size parameters" << TLOG_ENDL;
108 TLOG(TLVL_DEBUG) <<
"Initialization Complete: "
109 <<
"key: 0x" << std::hex << shm_key_
110 <<
", manager ID: " << manager_id_
111 <<
", Buffer size: " << std::to_string(shm_ptr_->buffer_size)
112 <<
", Buffer count: " << std::to_string(shm_ptr_->buffer_count) << TLOG_ENDL;
117 TLOG(TLVL_ERROR) <<
"Failed to attach to shared memory segment "
118 << shm_segment_id_ << TLOG_ENDL;
123 TLOG(TLVL_ERROR) <<
"Failed to connect to shared memory segment"
124 <<
", errno = " << strerror(errno) <<
". Please check "
125 <<
"if a stale shared memory segment needs to "
126 <<
"be cleaned up. (ipcs, ipcrm -m <segId>)" << TLOG_ENDL;
133 TLOG(13) <<
"GetBufferForReading BEGIN" << TLOG_ENDL;
136 TraceLock lk(search_mutex_, 11,
"GetBufferForReadingSearch");
137 auto rp = shm_ptr_->reader_pos.load();
139 TLOG(13) <<
"GetBufferForReading lock acquired, scanning buffers" << TLOG_ENDL;
144 ShmBuffer* buffer_ptr =
nullptr;
146 for (
auto ii = 0; ii < shm_ptr_->buffer_count; ++ii)
148 auto buffer = (ii + rp) % shm_ptr_->buffer_count;
151 TLOG(14) <<
"GetBufferForReading Checking if buffer " << buffer <<
" is stale" << TLOG_ENDL;
154 auto buf = getBufferInfo_(buffer);
155 TLOG(14) <<
"GetBufferForReading: Buffer " << buffer <<
": sem=" << FlagToString(buf->sem) <<
" (expected " << FlagToString(BufferSemaphoreFlags::Full) <<
"), sem_id=" << buf->sem_id <<
" )" << TLOG_ENDL;
156 if (buf->sem == BufferSemaphoreFlags::Full && (buf->sem_id == -1 || buf->sem_id == manager_id_) && buf->sequence_id > last_seen_id_)
158 if (buf->sequence_id < seqID)
161 seqID = buf->sequence_id;
167 if (!buffer_ptr || (buffer_ptr && buffer_ptr->sem_id != -1 && buffer_ptr->sem_id != manager_id_))
174 TLOG(13) <<
"GetBufferForReading Found buffer " << buffer_num << TLOG_ENDL;
175 buffer_ptr->sem_id = manager_id_;
176 buffer_ptr->sem = BufferSemaphoreFlags::Reading;
177 if (buffer_ptr->sem_id != manager_id_) {
continue; }
178 buffer_ptr->readPos = 0;
179 touchBuffer_(buffer_ptr);
180 if (buffer_ptr->sem_id != manager_id_) {
continue; }
181 if (shm_ptr_->destructive_read_mode && shm_ptr_->lowest_seq_id_read == last_seen_id_)
183 shm_ptr_->lowest_seq_id_read = seqID;
185 last_seen_id_ = seqID;
186 if (shm_ptr_->destructive_read_mode) shm_ptr_->reader_pos = (buffer_num + 1) % shm_ptr_->buffer_count;
191 TLOG(13) <<
"GetBufferForReading returning -1 because no buffers are ready" << TLOG_ENDL;
197 TLOG(14) <<
"GetBufferForWriting BEGIN" << TLOG_ENDL;
199 TraceLock lk(search_mutex_, 12,
"GetBufferForWritingSearch");
200 auto wp = shm_ptr_->writer_pos.load();
203 for (
auto ii = 0; ii < shm_ptr_->buffer_count; ++ii)
205 auto buffer = (ii + wp) % shm_ptr_->buffer_count;
209 auto buf = getBufferInfo_(buffer);
210 if (buf->sem == BufferSemaphoreFlags::Empty)
212 buf->sem_id = manager_id_;
213 buf->sem = BufferSemaphoreFlags::Writing;
214 if (buf->sem_id != manager_id_)
continue;
215 buf->sequence_id = ++shm_ptr_->next_sequence_id;
217 shm_ptr_->writer_pos = (buffer + 1) % shm_ptr_->buffer_count;
219 TLOG(14) <<
"GetBufferForWriting returning " << buffer << TLOG_ENDL;
227 for (
auto ii = 0; ii < shm_ptr_->buffer_count; ++ii)
229 auto buffer = (ii + wp) % shm_ptr_->buffer_count;
233 auto buf = getBufferInfo_(buffer);
234 if (buf->sem == BufferSemaphoreFlags::Full)
236 buf->sem_id = manager_id_;
237 buf->sem = BufferSemaphoreFlags::Writing;
238 if (buf->sem_id != manager_id_)
continue;
239 buf->sequence_id = ++shm_ptr_->next_sequence_id;
241 shm_ptr_->writer_pos = (buffer + 1) % shm_ptr_->buffer_count;
243 TLOG(14) <<
"GetBufferForWriting returning " << buffer << TLOG_ENDL;
249 for (
auto ii = 0; ii < shm_ptr_->buffer_count; ++ii)
251 auto buffer = (ii + wp) % shm_ptr_->buffer_count;
255 auto buf = getBufferInfo_(buffer);
256 if (buf->sem == BufferSemaphoreFlags::Reading)
258 buf->sem_id = manager_id_;
259 buf->sem = BufferSemaphoreFlags::Writing;
260 if (buf->sem_id != manager_id_)
continue;
261 buf->sequence_id = ++shm_ptr_->next_sequence_id;
263 shm_ptr_->writer_pos = (buffer + 1) % shm_ptr_->buffer_count;
264 TLOG(14) <<
"GetBufferForWriting returning " << buffer << TLOG_ENDL;
271 TLOG(14) <<
"GetBufferForWriting Returning -1 because no buffers are ready" << TLOG_ENDL;
277 if (!IsValid())
return 0;
278 TLOG(23) <<
"ReadReadyCount BEGIN" << TLOG_ENDL;
280 TraceLock lk(search_mutex_, 14,
"ReadReadyCountSearch");
282 for (
auto ii = 0; ii < shm_ptr_->buffer_count; ++ii)
284 TLOG(24) <<
"ReadReadyCount: Checking if buffer " << ii <<
" is stale." << TLOG_ENDL;
286 auto buf = getBufferInfo_(ii);
287 TLOG(24) <<
"ReadReadyCount: Buffer " << ii <<
": sem=" << FlagToString(buf->sem) <<
" (expected " << FlagToString(BufferSemaphoreFlags::Full) <<
"), sem_id=" << buf->sem_id <<
" )" << TLOG_ENDL;
288 if (buf->sem == BufferSemaphoreFlags::Full && (buf->sem_id == -1 || buf->sem_id == manager_id_) && buf->sequence_id > last_seen_id_)
290 TLOG(24) <<
"ReadReadyCount: Buffer " << ii <<
" is either unowned or owned by this manager, and is marked full." << TLOG_ENDL;
295 TLOG(23) << TLOG_ENDL;
301 if (!IsValid())
return 0;
303 TraceLock lk(search_mutex_, 15,
"WriteReadyCountSearch");
305 for (
auto ii = 0; ii < shm_ptr_->buffer_count; ++ii)
308 auto buf = getBufferInfo_(ii);
309 if ((buf->sem == BufferSemaphoreFlags::Empty && buf->sem_id == -1)
310 || (overwrite && buf->sem != BufferSemaphoreFlags::Writing))
321 std::deque<int> output;
322 if (!IsValid())
return output;
323 TraceLock lk(search_mutex_, 16,
"GetOwnedSearch");
324 for (
auto ii = 0; ii < shm_ptr_->buffer_count; ++ii)
326 auto buf = getBufferInfo_(ii);
327 if (buf->sem_id == manager_id_)
329 output.push_back(ii);
339 TraceLock lk(buffer_mutexes_[buffer], 17,
"DataSizeBuffer" + std::to_string(buffer));
340 auto buf = getBufferInfo_(buffer);
342 return buf->writePos;
349 TraceLock lk(buffer_mutexes_[buffer], 18,
"ResetReadPosBuffer" + std::to_string(buffer));
350 auto buf = getBufferInfo_(buffer);
358 TraceLock lk(buffer_mutexes_[buffer], 18,
"ResetWritePosBuffer" + std::to_string(buffer));
359 auto buf = getBufferInfo_(buffer);
360 checkBuffer_(buf, BufferSemaphoreFlags::Writing);
368 TraceLock lk(buffer_mutexes_[buffer], 19,
"IncReadPosBuffer" + std::to_string(buffer));
369 auto buf = getBufferInfo_(buffer);
371 TLOG(15) <<
"IncrementReadPos: buffer= " << buffer <<
", readPos=" << std::to_string(buf->readPos) <<
", bytes read=" << std::to_string(read) << TLOG_ENDL;
372 buf->readPos = buf->readPos + read;
373 TLOG(15) <<
"IncrementReadPos: buffer= " << buffer <<
", New readPos is " << std::to_string(buf->readPos) << TLOG_ENDL;
374 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) +
")");
380 TraceLock lk(buffer_mutexes_[buffer], 20,
"IncWritePosBuffer" + std::to_string(buffer));
381 auto buf = getBufferInfo_(buffer);
383 TLOG(16) <<
"IncrementWritePos: buffer= " << buffer <<
", writePos=" << std::to_string(buf->writePos) <<
", bytes written=" << std::to_string(written) << TLOG_ENDL;
384 buf->writePos += written;
385 TLOG(16) <<
"IncrementWritePos: buffer= " << buffer <<
", New writePos is " << std::to_string(buf->writePos) << TLOG_ENDL;
386 if (written == 0) Detach(
true,
"LogicError",
"Cannot increment Write pos by 0!");
392 TraceLock lk(buffer_mutexes_[buffer], 21,
"MoreDataInBuffer" + std::to_string(buffer));
393 auto buf = getBufferInfo_(buffer);
394 TLOG(17) <<
"MoreDataInBuffer: buffer= " << buffer <<
", readPos=" << std::to_string(buf->readPos) <<
", writePos=" << std::to_string(buf->writePos) << TLOG_ENDL;
395 return buf->readPos < buf->writePos;
401 TraceLock lk(buffer_mutexes_[buffer], 22,
"CheckBuffer" + std::to_string(buffer));
402 return checkBuffer_(getBufferInfo_(buffer), flags,
false);
408 TraceLock lk(buffer_mutexes_[buffer], 23,
"FillBuffer" + std::to_string(buffer));
409 auto shmBuf = getBufferInfo_(buffer);
410 touchBuffer_(shmBuf);
411 if (shmBuf->sem_id == manager_id_)
413 if (shmBuf->sem != BufferSemaphoreFlags::Full)
414 shmBuf->sem = BufferSemaphoreFlags::Full;
416 shmBuf->sem_id = destination;
422 TLOG(18) <<
"MarkBufferEmpty BEGIN" << TLOG_ENDL;
424 TraceLock lk(buffer_mutexes_[buffer], 24,
"EmptyBuffer" + std::to_string(buffer));
425 auto shmBuf = getBufferInfo_(buffer);
428 checkBuffer_(shmBuf, BufferSemaphoreFlags::Reading,
true);
430 touchBuffer_(shmBuf);
433 shmBuf->sem = BufferSemaphoreFlags::Full;
435 if ((force && (manager_id_ == 0 || manager_id_ == shmBuf->sem_id)) || (!force && shm_ptr_->destructive_read_mode))
437 TLOG(18) <<
"MarkBufferEmpty Resetting buffer to Empty state" << TLOG_ENDL;
438 shmBuf->writePos = 0;
439 shmBuf->sem = BufferSemaphoreFlags::Empty;
440 if (shm_ptr_->reader_pos == static_cast<unsigned>(buffer) && !shm_ptr_->destructive_read_mode)
442 TLOG(18) <<
"MarkBufferEmpty Broadcast mode; incrementing reader_pos" << TLOG_ENDL;
443 shm_ptr_->reader_pos = (buffer + 1) % shm_ptr_->buffer_count;
447 TLOG(18) <<
"MarkBufferEmpty END" << TLOG_ENDL;
453 TraceLock lk(buffer_mutexes_[buffer], 25,
"ResetBuffer" + std::to_string(buffer));
454 auto shmBuf = getBufferInfo_(buffer);
466 if (delta > 0xFFFFFFFF) {
467 TLOG(TLVL_TRACE) <<
"Buffer has touch time in the future, setting it to current time and ignoring..." << TLOG_ENDL;
471 if (delta <= shm_ptr_->buffer_timeout_us || shmBuf->sem == BufferSemaphoreFlags::Empty)
return false;
472 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;
474 if (shmBuf->sem_id == manager_id_ && shmBuf->sem == BufferSemaphoreFlags::Writing)
478 if (!shm_ptr_->destructive_read_mode && shmBuf->sem == BufferSemaphoreFlags::Full)
480 TLOG(TLVL_DEBUG) <<
"Resetting old broadcast mode buffer" << TLOG_ENDL;
481 shmBuf->writePos = 0;
482 shmBuf->sem = BufferSemaphoreFlags::Empty;
484 if (shm_ptr_->reader_pos == static_cast<unsigned>(buffer)) shm_ptr_->reader_pos = (buffer + 1) % shm_ptr_->buffer_count;
488 if (shmBuf->sem_id != manager_id_ && shmBuf->sem == BufferSemaphoreFlags::Reading)
490 TLOG(TLVL_WARNING) <<
"Stale Read buffer ( " << delta <<
" / " << shm_ptr_->buffer_timeout_us <<
" us ) detected! Resetting..." << TLOG_ENDL;
492 shmBuf->sem = BufferSemaphoreFlags::Full;
501 TLOG(19) <<
"Write BEGIN" << TLOG_ENDL;
503 TraceLock lk(buffer_mutexes_[buffer], 26,
"WriteBuffer" + std::to_string(buffer));
504 auto shmBuf = getBufferInfo_(buffer);
505 checkBuffer_(shmBuf, BufferSemaphoreFlags::Writing);
506 touchBuffer_(shmBuf);
507 TLOG(19) <<
"Buffer Write Pos is " << std::to_string(shmBuf->writePos) <<
", write size is " << std::to_string(size) << TLOG_ENDL;
508 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!");
510 auto pos = GetWritePos(buffer);
511 memcpy(pos, data, size);
512 shmBuf->writePos = shmBuf->writePos + size;
513 if (shmBuf->sequence_id > last_seen_id_)
515 last_seen_id_ = shmBuf->sequence_id;
517 TLOG(19) <<
"Write END" << TLOG_ENDL;
524 TraceLock lk(buffer_mutexes_[buffer], 27,
"ReadBuffer" + std::to_string(buffer));
525 auto shmBuf = getBufferInfo_(buffer);
526 checkBuffer_(shmBuf, BufferSemaphoreFlags::Reading);
527 touchBuffer_(shmBuf);
528 if (shmBuf->readPos + size > shm_ptr_->buffer_size) Detach(
true,
"SharedMemoryRead",
"Attempted to read more data than exists in Shared Memory!");
530 auto pos = GetReadPos(buffer);
531 memcpy(data, pos, size);
532 shmBuf->readPos += size;
533 touchBuffer_(shmBuf);
534 return checkBuffer_(shmBuf, BufferSemaphoreFlags::Reading,
false);
539 std::ostringstream ostr;
540 ostr <<
"ShmStruct: " << std::endl
541 <<
"Reader Position: " << shm_ptr_->reader_pos << std::endl
542 <<
"Writer Position: " << shm_ptr_->writer_pos << std::endl
543 <<
"Next ID Number: " << shm_ptr_->next_id << std::endl
544 <<
"Buffer Count: " << shm_ptr_->buffer_count << std::endl
545 <<
"Buffer Size: " << std::to_string(shm_ptr_->buffer_size) <<
" bytes" << std::endl
546 <<
"Buffers Written: " << std::to_string(shm_ptr_->next_sequence_id) << std::endl
547 <<
"Rank of Writer: " << shm_ptr_->rank << std::endl
548 <<
"Ready Magic Bytes: 0x" << std::hex << shm_ptr_->ready_magic << std::endl << std::endl;
550 for (
auto ii = 0; ii < shm_ptr_->buffer_count; ++ii)
552 auto buf = getBufferInfo_(ii);
553 ostr <<
"ShmBuffer " << std::dec << ii << std::endl
554 <<
"sequenceID: " << std::to_string(buf->sequence_id) << std::endl
555 <<
"writePos: " << std::to_string(buf->writePos) << std::endl
556 <<
"readPos: " << std::to_string(buf->readPos) << std::endl
557 <<
"sem: " << FlagToString(buf->sem) << std::endl
558 <<
"Owner: " << std::to_string(buf->sem_id.load()) << std::endl
559 <<
"Last Touch Time: " << std::to_string(buf->last_touch_time / 1000000.0) << std::endl << std::endl;
567 auto buf = getBufferInfo_(buffer);
568 return bufferStart_(buffer) + buf->readPos;
572 auto buf = getBufferInfo_(buffer);
573 return bufferStart_(buffer) + buf->writePos;
578 return bufferStart_(buffer);
581 uint8_t* artdaq::SharedMemoryManager::dataStart_()
const
583 return reinterpret_cast<uint8_t*
>(shm_ptr_ + 1) + shm_ptr_->buffer_count *
sizeof(ShmBuffer);
586 uint8_t* artdaq::SharedMemoryManager::bufferStart_(
int buffer)
588 if (buffer >= shm_ptr_->buffer_count) Detach(
true,
"ArgumentOutOfRange",
"The specified buffer does not exist!");
589 return dataStart_() + buffer * shm_ptr_->buffer_size;
592 artdaq::SharedMemoryManager::ShmBuffer* artdaq::SharedMemoryManager::getBufferInfo_(
int buffer)
594 if (buffer >= shm_ptr_->buffer_count) Detach(
true,
"ArgumentOutOfRange",
"The specified buffer does not exist!");
595 return reinterpret_cast<ShmBuffer*
>(
reinterpret_cast<uint8_t*
>(shm_ptr_ + 1) + buffer *
sizeof(ShmBuffer));
598 bool artdaq::SharedMemoryManager::checkBuffer_(ShmBuffer* buffer, BufferSemaphoreFlags flags,
bool exceptions)
602 if (buffer->sem != flags) Detach(
true,
"StateAccessViolation",
"Shared Memory buffer is not in the correct state! (expected " + FlagToString(flags) +
", actual " + FlagToString(buffer->sem) +
")");
603 if (buffer->sem_id != manager_id_) Detach(
true,
"OwnerAccessViolation",
"Shared Memory buffer is not owned by this manager instance!");
605 bool ret = (buffer->sem_id == manager_id_ || (buffer->sem_id == -1 && (flags == BufferSemaphoreFlags::Full || flags == BufferSemaphoreFlags::Empty))) && buffer->sem == flags;
609 TLOG(TLVL_WARNING) <<
"CheckBuffer detected issue with buffer " << std::to_string(buffer->sequence_id) <<
"!"
610 <<
" ID: " << buffer->sem_id <<
" (" << manager_id_ <<
"), Flag: " << FlagToString(buffer->sem) <<
" (" << FlagToString(flags) <<
"). "
611 <<
"ID -1 is okay if desired flag is \"Full\" or \"Empty\"." << TLOG_ENDL;
617 void artdaq::SharedMemoryManager::touchBuffer_(ShmBuffer* buffer)
619 if (buffer->sem_id != manager_id_)
return;
620 TLOG(TLVL_TRACE) <<
"touchBuffer_: Touching buffer with sequence_id " << std::to_string(buffer->sequence_id) << TLOG_ENDL;
628 auto bufs = GetBuffersOwnedByManager();
629 for (
auto buf : bufs)
631 auto shmBuf = getBufferInfo_(buf);
632 if (shmBuf->sem == BufferSemaphoreFlags::Writing)
634 shmBuf->sem = BufferSemaphoreFlags::Empty;
636 else if (shmBuf->sem == BufferSemaphoreFlags::Reading)
638 shmBuf->sem = BufferSemaphoreFlags::Full;
650 if (manager_id_ == 0 && shm_segment_id_ > -1)
652 shmctl(shm_segment_id_, IPC_RMID, NULL);
655 if (category.size() > 0 && message.size() > 0)
657 TLOG(TLVL_ERROR) << category <<
": " << message << TLOG_ENDL;
661 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. ...