4 #include "cetlib_except/exception.h"
5 #include "artdaq-core/Core/SharedMemoryManager.hh"
6 #include "artdaq-core/Utilities/TraceLock.hh"
7 #include "SharedMemoryManager.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_ARB(5,
"SharedMemoryManager") <<
"~SharedMemoryManager called" << TLOG_ENDL;
29 TLOG_ARB(5,
"SharedMemoryManager") <<
"~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_DEBUG(
"SharedMemoryManager") <<
"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_DEBUG(
"SharedMemoryManager") <<
"shm_key == 0x" << std::hex << shm_key_ <<
", shm_segment_id == " << shm_segment_id_ << TLOG_ENDL;
58 if (shm_segment_id_ > -1)
60 TLOG_DEBUG(
"SharedMemoryManager")
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);
65 TLOG_DEBUG(
"SharedMemoryManager")
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_ERROR(
"SharedMemoryManager") <<
"Owner encountered already-initialized Shared Memory!" << TLOG_ENDL;
77 TLOG_DEBUG(
"SharedMemoryManager") <<
"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;
95 shm_ptr_->ready_magic = 0xCAFE1111;
99 TLOG_DEBUG(
"SharedMemoryManager") <<
"Waiting for owner to initalize Shared Memory" << TLOG_ENDL;
100 while (shm_ptr_->ready_magic != 0xCAFE1111) { usleep(1000); }
101 TLOG_DEBUG(
"SharedMemoryManager") <<
"Getting ID from Shared Memory" << TLOG_ENDL;
103 shm_ptr_->lowest_seq_id_read = 0;
104 TLOG_DEBUG(
"SharedMemoryManager") <<
"Getting Shared Memory Size parameters" << TLOG_ENDL;
107 TLOG_DEBUG(
"SharedMemoryManager") <<
"Initialization Complete: "
108 <<
"key: 0x" << std::hex << shm_key_
109 <<
", manager ID: " << manager_id_
110 <<
", Buffer size: " << std::to_string(shm_ptr_->buffer_size)
111 <<
", Buffer count: " << std::to_string(shm_ptr_->buffer_count) << TLOG_ENDL;
116 TLOG_ERROR(
"SharedMemoryManager") <<
"Failed to attach to shared memory segment "
117 << shm_segment_id_ << TLOG_ENDL;
122 TLOG_ERROR(
"SharedMemoryManager") <<
"Failed to connect to shared memory segment"
123 <<
", errno = " << errno <<
". Please check "
124 <<
"if a stale shared memory segment needs to "
125 <<
"be cleaned up. (ipcs, ipcrm -m <segId>)" << TLOG_ENDL;
132 TLOG_ARB(13,
"SharedMemoryManager") <<
"GetBufferForReading BEGIN" << TLOG_ENDL;
135 TraceLock lk(search_mutex_, 11,
"GetBufferForReadingSearch");
136 auto rp = shm_ptr_->reader_pos.load();
138 TLOG_ARB(13,
"SharedMemoryManager") <<
"GetBufferForReading lock acquired, scanning buffers" << TLOG_ENDL;
143 ShmBuffer* buffer_ptr =
nullptr;
145 for (
auto ii = 0; ii < shm_ptr_->buffer_count; ++ii)
147 auto buffer = (ii + rp) % shm_ptr_->buffer_count;
150 TLOG_ARB(14,
"SharedMemoryManager") <<
"GetBufferForReading Checking if buffer " << buffer <<
" is stale" << TLOG_ENDL;
153 auto buf = getBufferInfo_(buffer);
154 TLOG_ARB(14,
"SharedMemoryManager") <<
"GetBufferForReading: Buffer " << buffer <<
": sem=" << FlagToString(buf->sem) <<
" (expected " << FlagToString(BufferSemaphoreFlags::Full) <<
"), sem_id=" << buf->sem_id <<
" (" << manager_id_ <<
" or -1), seqid=" << buf->sequence_id <<
" (> " << last_seen_id_ <<
")" << TLOG_ENDL;
155 if (buf->sem == BufferSemaphoreFlags::Full && (buf->sem_id == -1 || buf->sem_id == manager_id_) && buf->sequence_id > last_seen_id_)
157 if (buf->sequence_id < seqID)
160 seqID = buf->sequence_id;
166 if (!buffer_ptr || (buffer_ptr && buffer_ptr->sem_id != -1 && buffer_ptr->sem_id != manager_id_))
173 TLOG_ARB(13,
"SharedMemoryManager") <<
"GetBufferForReading Found buffer " << buffer_num << TLOG_ENDL;
174 buffer_ptr->sem_id = manager_id_;
175 buffer_ptr->sem = BufferSemaphoreFlags::Reading;
176 if (buffer_ptr->sem_id != manager_id_) {
continue; }
177 buffer_ptr->readPos = 0;
178 touchBuffer_(buffer_ptr);
179 if (buffer_ptr->sem_id != manager_id_) {
continue; }
180 if (shm_ptr_->destructive_read_mode && shm_ptr_->lowest_seq_id_read == last_seen_id_)
182 shm_ptr_->lowest_seq_id_read = seqID;
184 last_seen_id_ = seqID;
185 if (shm_ptr_->destructive_read_mode) shm_ptr_->reader_pos = (buffer_num + 1) % shm_ptr_->buffer_count;
190 TLOG_ARB(13,
"SharedMemoryManager") <<
"GetBufferForReading returning -1 because no buffers are ready" << TLOG_ENDL;
196 TLOG_ARB(13,
"SharedMemoryManager") <<
"GetBufferForWriting BEGIN" << TLOG_ENDL;
198 TraceLock lk(search_mutex_, 12,
"GetBufferForWritingSearch");
199 auto wp = shm_ptr_->writer_pos.load();
202 for (
auto ii = 0; ii < shm_ptr_->buffer_count; ++ii)
204 auto buffer = (ii + wp) % shm_ptr_->buffer_count;
208 auto buf = getBufferInfo_(buffer);
209 if (buf->sem == BufferSemaphoreFlags::Empty)
211 buf->sem_id = manager_id_;
212 buf->sem = BufferSemaphoreFlags::Writing;
213 if (buf->sem_id != manager_id_)
continue;
214 buf->sequence_id = ++shm_ptr_->next_sequence_id;
216 shm_ptr_->writer_pos = (buffer + 1) % shm_ptr_->buffer_count;
218 TLOG_ARB(13,
"SharedMemoryManager") <<
"GetBufferForWriting returning " << buffer << TLOG_ENDL;
226 for (
auto ii = 0; ii < shm_ptr_->buffer_count; ++ii)
228 auto buffer = (ii + wp) % shm_ptr_->buffer_count;
232 auto buf = getBufferInfo_(buffer);
233 if (buf->sem == BufferSemaphoreFlags::Full)
235 buf->sem_id = manager_id_;
236 buf->sem = BufferSemaphoreFlags::Writing;
237 if (buf->sem_id != manager_id_)
continue;
238 buf->sequence_id = ++shm_ptr_->next_sequence_id;
240 shm_ptr_->writer_pos = (buffer + 1) % shm_ptr_->buffer_count;
242 TLOG_ARB(13,
"SharedMemoryManager") <<
"GetBufferForWriting returning " << buffer << TLOG_ENDL;
248 for (
auto ii = 0; ii < shm_ptr_->buffer_count; ++ii)
250 auto buffer = (ii + wp) % shm_ptr_->buffer_count;
254 auto buf = getBufferInfo_(buffer);
255 if (buf->sem == BufferSemaphoreFlags::Reading)
257 buf->sem_id = manager_id_;
258 buf->sem = BufferSemaphoreFlags::Writing;
259 if (buf->sem_id != manager_id_)
continue;
260 buf->sequence_id = ++shm_ptr_->next_sequence_id;
262 shm_ptr_->writer_pos = (buffer + 1) % shm_ptr_->buffer_count;
263 TLOG_ARB(13,
"SharedMemoryManager") <<
"GetBufferForWriting returning " << buffer << TLOG_ENDL;
270 TLOG_ARB(13,
"SharedMemoryManager") <<
"GetBufferForWriting Returning -1 because no buffers are ready" << TLOG_ENDL;
276 if (!IsValid())
return 0;
277 TLOG_ARB(23,
"SharedMemoryManager") <<
"ReadReadyCount BEGIN" << TLOG_ENDL;
279 TraceLock lk(search_mutex_, 14,
"ReadReadyCountSearch");
281 for (
auto ii = 0; ii < shm_ptr_->buffer_count; ++ii)
283 TLOG_ARB(24,
"SharedMemoryManager") <<
"ReadReadyCount: Checking if buffer " << ii <<
" is stale." << TLOG_ENDL;
285 auto buf = getBufferInfo_(ii);
286 TLOG_ARB(24,
"SharedMemoryManager") <<
"ReadReadyCount: Buffer " << ii <<
": sem=" << FlagToString(buf->sem) <<
" (expected " << FlagToString(BufferSemaphoreFlags::Full) <<
"), sem_id=" << buf->sem_id <<
" (" << manager_id_ <<
" or -1), seqid=" << buf->sequence_id <<
" (> " << last_seen_id_ <<
")" << TLOG_ENDL;
287 if (buf->sem == BufferSemaphoreFlags::Full && (buf->sem_id == -1 || buf->sem_id == manager_id_) && buf->sequence_id > last_seen_id_)
289 TLOG_ARB(24,
"SharedMemoryManager") <<
"ReadReadyCount: Buffer " << ii <<
" is either unowned or owned by this manager, and is marked full." << TLOG_ENDL;
294 TLOG_ARB(23,
"SharedMemoryManager") <<
"ReadReadyCount returning " << std::to_string(count) << TLOG_ENDL;
300 if (!IsValid())
return 0;
302 TraceLock lk(search_mutex_, 15,
"WriteReadyCountSearch");
304 for (
auto ii = 0; ii < shm_ptr_->buffer_count; ++ii)
307 auto buf = getBufferInfo_(ii);
308 if ((buf->sem == BufferSemaphoreFlags::Empty && buf->sem_id == -1)
309 || (overwrite && buf->sem != BufferSemaphoreFlags::Writing))
320 std::deque<int> output;
321 if (!IsValid())
return output;
322 TraceLock lk(search_mutex_, 16,
"GetOwnedSearch");
323 for (
auto ii = 0; ii < shm_ptr_->buffer_count; ++ii)
325 auto buf = getBufferInfo_(ii);
326 if (buf->sem_id == manager_id_)
328 output.push_back(ii);
338 TraceLock lk(buffer_mutexes_[buffer], 17,
"DataSizeBuffer" + std::to_string(buffer));
339 auto buf = getBufferInfo_(buffer);
341 return buf->writePos;
348 TraceLock lk(buffer_mutexes_[buffer], 18,
"ResetReadPosBuffer" + std::to_string(buffer));
349 auto buf = getBufferInfo_(buffer);
357 TraceLock lk(buffer_mutexes_[buffer], 18,
"ResetWritePosBuffer" + std::to_string(buffer));
358 auto buf = getBufferInfo_(buffer);
359 checkBuffer_(buf, BufferSemaphoreFlags::Writing);
367 TraceLock lk(buffer_mutexes_[buffer], 19,
"IncReadPosBuffer" + std::to_string(buffer));
368 auto buf = getBufferInfo_(buffer);
370 TLOG_ARB(13,
"SharedMemoryManager") <<
"IncrementReadPos: buffer= " << buffer <<
", readPos=" << std::to_string(buf->readPos) <<
", bytes read=" << std::to_string(read) << TLOG_ENDL;
371 buf->readPos = buf->readPos + read;
372 TLOG_ARB(13,
"SharedMemoryManager") <<
"IncrementReadPos: buffer= " << buffer <<
", New readPos is " << std::to_string(buf->readPos) << TLOG_ENDL;
374 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_ARB(13,
"SharedMemoryManager") <<
"IncrementWritePos: buffer= " << buffer <<
", writePos=" << std::to_string(buf->writePos) <<
", bytes written=" << std::to_string(written) << TLOG_ENDL;
384 buf->writePos += written;
385 TLOG_ARB(13,
"SharedMemoryManager") <<
"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_ARB(13,
"SharedMemoryManager") <<
"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_ARB(13,
"SharedMemoryManager") <<
"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_ARB(13,
"SharedMemoryManager") <<
"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_ARB(13,
"SharedMemoryManager") <<
"MarkBufferEmpty Broadcast mode; incrementing reader_pos" << TLOG_ENDL;
443 shm_ptr_->reader_pos = (buffer + 1) % shm_ptr_->buffer_count;
447 TLOG_ARB(13,
"SharedMemoryManager") <<
"MarkBufferEmpty END" << TLOG_ENDL;
453 TraceLock lk(buffer_mutexes_[buffer], 25,
"ResetBuffer" + std::to_string(buffer));
454 auto shmBuf = getBufferInfo_(buffer);
467 if (shmBuf->sem_id == manager_id_ && shmBuf->sem == BufferSemaphoreFlags::Writing)
471 if (!shm_ptr_->destructive_read_mode && shmBuf->sem == BufferSemaphoreFlags::Full)
473 TLOG_DEBUG(
"SharedMemoryManager") <<
"Resetting old broadcast mode buffer" << TLOG_ENDL;
474 shmBuf->writePos = 0;
475 shmBuf->sem = BufferSemaphoreFlags::Empty;
477 if (shm_ptr_->reader_pos = buffer)shm_ptr_->reader_pos = (buffer + 1) % shm_ptr_->buffer_count;
481 if (shmBuf->sem_id != manager_id_ && shmBuf->sem == BufferSemaphoreFlags::Reading)
483 TLOG_WARNING(
"SharedMemoryManager") <<
"Stale Read buffer ( " << std::to_string(
TimeUtils::gettimeofday_us() - shmBuf->last_touch_time) <<
" / " << std::to_string(shm_ptr_->buffer_timeout_us) <<
" us ) detected! Resetting..." << TLOG_ENDL;
485 shmBuf->sem = BufferSemaphoreFlags::Full;
494 TLOG_ARB(13,
"SharedMemoryManager") <<
"Write BEGIN" << TLOG_ENDL;
496 TraceLock lk(buffer_mutexes_[buffer], 26,
"WriteBuffer" + std::to_string(buffer));
497 auto shmBuf = getBufferInfo_(buffer);
498 checkBuffer_(shmBuf, BufferSemaphoreFlags::Writing);
499 touchBuffer_(shmBuf);
500 TLOG_ARB(13,
"SharedMemoryManager") <<
"Buffer Write Pos is " << std::to_string(shmBuf->writePos) <<
", write size is " << std::to_string(size) << TLOG_ENDL;
501 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!");
503 auto pos = GetWritePos(buffer);
504 memcpy(pos, data, size);
505 shmBuf->writePos = shmBuf->writePos + size;
506 if (shmBuf->sequence_id > last_seen_id_)
508 last_seen_id_ = shmBuf->sequence_id;
510 TLOG_ARB(13,
"SharedMemoryManager") <<
"Write END" << TLOG_ENDL;
517 TraceLock lk(buffer_mutexes_[buffer], 27,
"ReadBuffer" + std::to_string(buffer));
518 auto shmBuf = getBufferInfo_(buffer);
519 checkBuffer_(shmBuf, BufferSemaphoreFlags::Reading);
520 touchBuffer_(shmBuf);
521 if (shmBuf->readPos + size > shm_ptr_->buffer_size) Detach(
true,
"SharedMemoryRead",
"Attempted to read more data than exists in Shared Memory!");
523 auto pos = GetReadPos(buffer);
524 memcpy(data, pos, size);
525 shmBuf->readPos += size;
526 return checkBuffer_(shmBuf, BufferSemaphoreFlags::Reading,
false);
531 std::ostringstream ostr;
532 ostr <<
"ShmStruct: " << std::endl
533 <<
"Reader Position: " << shm_ptr_->reader_pos << std::endl
534 <<
"Writer Position: " << shm_ptr_->writer_pos << std::endl
535 <<
"Next ID Number: " << shm_ptr_->next_id << std::endl
536 <<
"Buffer Count: " << shm_ptr_->buffer_count << std::endl
537 <<
"Buffer Size: " << std::to_string(shm_ptr_->buffer_size) <<
" bytes" << std::endl
538 <<
"Buffers Written: " << std::to_string(shm_ptr_->next_sequence_id) << std::endl
539 <<
"Rank of Writer: " << shm_ptr_->rank << std::endl
540 <<
"Ready Magic Bytes: 0x" << std::hex << shm_ptr_->ready_magic << std::endl << std::endl;
542 for (
auto ii = 0; ii < shm_ptr_->buffer_count; ++ii)
544 auto buf = getBufferInfo_(ii);
545 ostr <<
"ShmBuffer " << std::dec << ii << std::endl
546 <<
"sequenceID: " << std::to_string(buf->sequence_id) << std::endl
547 <<
"writePos: " << std::to_string(buf->writePos) << std::endl
548 <<
"readPos: " << std::to_string(buf->readPos) << std::endl
549 <<
"sem: " << FlagToString(buf->sem) << std::endl
550 <<
"Owner: " << std::to_string(buf->sem_id.load()) << std::endl
551 <<
"Last Touch Time: " << std::to_string(buf->last_touch_time / 1000000.0) << std::endl << std::endl;
559 auto buf = getBufferInfo_(buffer);
560 return bufferStart_(buffer) + buf->readPos;
564 auto buf = getBufferInfo_(buffer);
565 return bufferStart_(buffer) + buf->writePos;
570 return bufferStart_(buffer);
573 uint8_t* artdaq::SharedMemoryManager::dataStart_()
const
575 return reinterpret_cast<uint8_t*
>(shm_ptr_ + 1) + shm_ptr_->buffer_count *
sizeof(ShmBuffer);
578 uint8_t* artdaq::SharedMemoryManager::bufferStart_(
int buffer)
580 if (buffer >= shm_ptr_->buffer_count) Detach(
true,
"ArgumentOutOfRange",
"The specified buffer does not exist!");
581 return dataStart_() + buffer * shm_ptr_->buffer_size;
584 artdaq::SharedMemoryManager::ShmBuffer* artdaq::SharedMemoryManager::getBufferInfo_(
int buffer)
586 if (buffer >= shm_ptr_->buffer_count) Detach(
true,
"ArgumentOutOfRange",
"The specified buffer does not exist!");
587 return reinterpret_cast<ShmBuffer*
>(
reinterpret_cast<uint8_t*
>(shm_ptr_ + 1) + buffer *
sizeof(ShmBuffer));
590 bool artdaq::SharedMemoryManager::checkBuffer_(ShmBuffer* buffer, BufferSemaphoreFlags flags,
bool exceptions)
594 if (buffer->sem != flags) Detach(
true,
"StateAccessViolation",
"Shared Memory buffer is not in the correct state! (expected " + FlagToString(flags) +
", actual " + FlagToString(buffer->sem) +
")");
595 if (buffer->sem_id != manager_id_) Detach(
true,
"OwnerAccessViolation",
"Shared Memory buffer is not owned by this manager instance!");
597 bool ret = (buffer->sem_id == manager_id_ || (buffer->sem_id == -1 && (flags == BufferSemaphoreFlags::Full || flags == BufferSemaphoreFlags::Empty))) && buffer->sem == flags;
601 TLOG_WARNING(
"SharedMemoryManager") <<
"CheckBuffer detected issue with buffer " << std::to_string(buffer->sequence_id) <<
"!"
602 <<
" ID: " << buffer->sem_id <<
" (" << manager_id_ <<
"), Flag: " << FlagToString(buffer->sem) <<
" (" << FlagToString(flags) <<
"). "
603 <<
"ID -1 is okay if desired flag is \"Full\" or \"Empty\"." << TLOG_ENDL;
609 void artdaq::SharedMemoryManager::touchBuffer_(ShmBuffer* buffer)
611 if (buffer->sem_id != manager_id_)
return;
612 TLOG_TRACE(
"SharedMemoryManager") <<
"touchBuffer_: Touching buffer with sequence_id " << std::to_string(buffer->sequence_id) << TLOG_ENDL;
620 auto bufs = GetBuffersOwnedByManager();
621 for (
auto buf : bufs)
623 auto shmBuf = getBufferInfo_(buf);
624 if (shmBuf->sem == BufferSemaphoreFlags::Writing)
626 shmBuf->sem = BufferSemaphoreFlags::Empty;
628 else if (shmBuf->sem == BufferSemaphoreFlags::Reading)
630 shmBuf->sem = BufferSemaphoreFlags::Full;
642 if (manager_id_ == 0 && shm_segment_id_ > -1)
644 shmctl(shm_segment_id_, IPC_RMID, NULL);
647 if (category.size() > 0 && message.size() > 0)
649 TLOG_ERROR(
"SharedMemoryManager") << category <<
": " << message << TLOG_ENDL;
653 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. ...