3 #include "cetlib_except/exception.h"
4 #include "artdaq-core/Core/SharedMemoryManager.hh"
5 #include "artdaq-core/Utilities/TraceLock.hh"
15 requested_shm_parameters_.buffer_count = buffer_count;
16 requested_shm_parameters_.buffer_size = buffer_size;
17 requested_shm_parameters_.buffer_timeout_us = buffer_timeout_us;
18 requested_shm_parameters_.destructive_read_mode = destructive_read_mode;
25 TLOG_ARB(5,
"SharedMemoryManager") <<
"~SharedMemoryManager called" << TLOG_ENDL;
27 TLOG_ARB(5,
"SharedMemoryManager") <<
"~SharedMemoryManager done" << TLOG_ENDL;
34 if (manager_id_ == 0)
return;
37 auto start_time = std::chrono::steady_clock::now();
39 size_t shmSize = requested_shm_parameters_.buffer_count * (requested_shm_parameters_.buffer_size +
sizeof(ShmBuffer)) +
sizeof(ShmStruct);
41 shm_segment_id_ = shmget(shm_key_, shmSize, 0666);
42 if (shm_segment_id_ == -1 && requested_shm_parameters_.buffer_count > 0 && manager_id_ <= 0)
44 TLOG_DEBUG(
"SharedMemoryManager") <<
"Creating shared memory segment with key 0x" << std::hex << shm_key_ << TLOG_ENDL;
45 shm_segment_id_ = shmget(shm_key_, shmSize, IPC_CREAT | 0666);
51 shm_segment_id_ = shmget(shm_key_, shmSize, 0666);
54 TLOG_DEBUG(
"SharedMemoryManager") <<
"shm_key == 0x" << std::hex << shm_key_ <<
", shm_segment_id == " << shm_segment_id_ << TLOG_ENDL;
56 if (shm_segment_id_ > -1)
58 TLOG_DEBUG(
"SharedMemoryManager")
59 <<
"Attached to shared memory segment with ID = " << shm_segment_id_
60 <<
" and size " << shmSize
61 <<
" bytes" << TLOG_ENDL;
62 shm_ptr_ = (ShmStruct*)shmat(shm_segment_id_, 0, 0);
63 TLOG_DEBUG(
"SharedMemoryManager")
64 <<
"Attached to shared memory segment at address "
65 << std::hex << (
void*)shm_ptr_ << std::dec << TLOG_ENDL;
66 if (shm_ptr_ && shm_ptr_ != (
void *)-1)
70 if (shm_ptr_->ready_magic == 0xCAFE1111)
72 TLOG_ERROR(
"SharedMemoryManager") <<
"Owner encountered already-initialized Shared Memory!" << TLOG_ENDL;
75 TLOG_DEBUG(
"SharedMemoryManager") <<
"Owner initializing Shared Memory" << TLOG_ENDL;
76 shm_ptr_->next_id = 1;
77 shm_ptr_->next_sequence_id = 0;
78 shm_ptr_->reader_pos = 0;
79 shm_ptr_->writer_pos = 0;
80 shm_ptr_->buffer_size = requested_shm_parameters_.buffer_size;
81 shm_ptr_->buffer_count = requested_shm_parameters_.buffer_count;
82 shm_ptr_->buffer_timeout_us = requested_shm_parameters_.buffer_timeout_us;
83 shm_ptr_->destructive_read_mode = requested_shm_parameters_.destructive_read_mode;
85 for (
int ii = 0; ii < static_cast<int>(requested_shm_parameters_.buffer_count); ++ii)
87 getBufferInfo_(ii)->writePos = 0;
88 getBufferInfo_(ii)->readPos = 0;
89 getBufferInfo_(ii)->sem = BufferSemaphoreFlags::Empty;
90 getBufferInfo_(ii)->sem_id = -1;
94 shm_ptr_->ready_magic = 0xCAFE1111;
98 TLOG_DEBUG(
"SharedMemoryManager") <<
"Waiting for owner to initalize Shared Memory" << TLOG_ENDL;
99 while (shm_ptr_->ready_magic != 0xCAFE1111) { usleep(1000); }
100 TLOG_DEBUG(
"SharedMemoryManager") <<
"Getting ID from Shared Memory" << TLOG_ENDL;
102 shm_ptr_->lowest_seq_id_read = 0;
103 TLOG_DEBUG(
"SharedMemoryManager") <<
"Getting Shared Memory Size parameters" << TLOG_ENDL;
106 TLOG_DEBUG(
"SharedMemoryManager") <<
"Initialization Complete: "
107 <<
"key: 0x" << std::hex << shm_key_
108 <<
", manager ID: " << manager_id_
109 <<
", Buffer size: " << std::to_string(shm_ptr_->buffer_size)
110 <<
", Buffer count: " << std::to_string(shm_ptr_->buffer_count) << TLOG_ENDL;
115 TLOG_ERROR(
"SharedMemoryManager") <<
"Failed to attach to shared memory segment "
116 << shm_segment_id_ << TLOG_ENDL;
121 TLOG_ERROR(
"SharedMemoryManager") <<
"Failed to connect to shared memory segment"
122 <<
", errno = " << errno <<
". Please check "
123 <<
"if a stale shared memory segment needs to "
124 <<
"be cleaned up. (ipcs, ipcrm -m <segId>)" << TLOG_ENDL;
131 TLOG_ARB(13,
"SharedMemoryManager") <<
"GetBufferForReading BEGIN" << TLOG_ENDL;
134 TraceLock lk(search_mutex_, 11,
"GetBufferForReadingSearch");
135 auto rp = shm_ptr_->reader_pos.load();
137 TLOG_ARB(13,
"SharedMemoryManager") <<
"GetBufferForReading lock acquired, scanning buffers" << TLOG_ENDL;
142 ShmBuffer* buffer_ptr =
nullptr;
144 for (
auto ii = 0; ii < shm_ptr_->buffer_count; ++ii)
146 auto buffer = (ii + rp) % shm_ptr_->buffer_count;
149 TLOG_ARB(14,
"SharedMemoryManager") <<
"GetBufferForReading Checking if buffer " << buffer <<
" is stale" << TLOG_ENDL;
152 auto buf = getBufferInfo_(buffer);
153 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;
154 if (buf->sem == BufferSemaphoreFlags::Full && (buf->sem_id == -1 || buf->sem_id == manager_id_) && buf->sequence_id > last_seen_id_)
156 if (buf->sequence_id < seqID)
159 seqID = buf->sequence_id;
165 if (!buffer_ptr || (buffer_ptr && buffer_ptr->sem_id != -1 && buffer_ptr->sem_id != manager_id_))
172 TLOG_ARB(13,
"SharedMemoryManager") <<
"GetBufferForReading Found buffer " << buffer_num << TLOG_ENDL;
173 buffer_ptr->sem_id = manager_id_;
174 buffer_ptr->sem = BufferSemaphoreFlags::Reading;
175 if (buffer_ptr->sem_id != manager_id_) {
continue; }
176 buffer_ptr->readPos = 0;
177 touchBuffer_(buffer_ptr);
178 if (buffer_ptr->sem_id != manager_id_) {
continue; }
179 if (shm_ptr_->destructive_read_mode && shm_ptr_->lowest_seq_id_read == last_seen_id_)
181 shm_ptr_->lowest_seq_id_read = seqID;
183 last_seen_id_ = seqID;
184 if (shm_ptr_->destructive_read_mode) shm_ptr_->reader_pos = (buffer_num + 1) % shm_ptr_->buffer_count;
189 TLOG_ARB(13,
"SharedMemoryManager") <<
"GetBufferForReading returning -1 because no buffers are ready" << TLOG_ENDL;
195 TLOG_ARB(13,
"SharedMemoryManager") <<
"GetBufferForWriting BEGIN" << TLOG_ENDL;
197 TraceLock lk(search_mutex_, 12,
"GetBufferForWritingSearch");
198 auto wp = shm_ptr_->writer_pos.load();
201 for (
auto ii = 0; ii < shm_ptr_->buffer_count; ++ii)
203 auto buffer = (ii + wp) % shm_ptr_->buffer_count;
207 auto buf = getBufferInfo_(buffer);
208 if (buf->sem == BufferSemaphoreFlags::Empty)
210 buf->sem_id = manager_id_;
211 buf->sem = BufferSemaphoreFlags::Writing;
212 if (buf->sem_id != manager_id_)
continue;
213 buf->sequence_id = ++shm_ptr_->next_sequence_id;
215 shm_ptr_->writer_pos = (buffer + 1) % shm_ptr_->buffer_count;
217 TLOG_ARB(13,
"SharedMemoryManager") <<
"GetBufferForWriting returning " << buffer << TLOG_ENDL;
225 for (
auto ii = 0; ii < shm_ptr_->buffer_count; ++ii)
227 auto buffer = (ii + wp) % shm_ptr_->buffer_count;
231 auto buf = getBufferInfo_(buffer);
232 if (buf->sem == BufferSemaphoreFlags::Full)
234 buf->sem_id = manager_id_;
235 buf->sem = BufferSemaphoreFlags::Writing;
236 if (buf->sem_id != manager_id_)
continue;
237 buf->sequence_id = ++shm_ptr_->next_sequence_id;
239 shm_ptr_->writer_pos = (buffer + 1) % shm_ptr_->buffer_count;
241 TLOG_ARB(13,
"SharedMemoryManager") <<
"GetBufferForWriting returning " << buffer << TLOG_ENDL;
247 for (
auto ii = 0; ii < shm_ptr_->buffer_count; ++ii)
249 auto buffer = (ii + wp) % shm_ptr_->buffer_count;
253 auto buf = getBufferInfo_(buffer);
254 if (buf->sem == BufferSemaphoreFlags::Reading)
256 buf->sem_id = manager_id_;
257 buf->sem = BufferSemaphoreFlags::Writing;
258 if (buf->sem_id != manager_id_)
continue;
259 buf->sequence_id = ++shm_ptr_->next_sequence_id;
261 shm_ptr_->writer_pos = (buffer + 1) % shm_ptr_->buffer_count;
262 TLOG_ARB(13,
"SharedMemoryManager") <<
"GetBufferForWriting returning " << buffer << TLOG_ENDL;
269 TLOG_ARB(13,
"SharedMemoryManager") <<
"GetBufferForWriting Returning -1 because no buffers are ready" << TLOG_ENDL;
275 if (!IsValid())
return 0;
276 TLOG_ARB(23,
"SharedMemoryManager") <<
"ReadReadyCount BEGIN" << TLOG_ENDL;
278 TraceLock lk(search_mutex_, 14,
"ReadReadyCountSearch");
280 for (
auto ii = 0; ii < shm_ptr_->buffer_count; ++ii)
282 TLOG_ARB(24,
"SharedMemoryManager") <<
"ReadReadyCount: Checking if buffer " << ii <<
" is stale." << TLOG_ENDL;
284 auto buf = getBufferInfo_(ii);
285 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;
286 if (buf->sem == BufferSemaphoreFlags::Full && (buf->sem_id == -1 || buf->sem_id == manager_id_) && buf->sequence_id > last_seen_id_)
288 TLOG_ARB(24,
"SharedMemoryManager") <<
"ReadReadyCount: Buffer " << ii <<
" is either unowned or owned by this manager, and is marked full." << TLOG_ENDL;
293 TLOG_ARB(23,
"SharedMemoryManager") <<
"ReadReadyCount returning " << std::to_string(count) << TLOG_ENDL;
299 if (!IsValid())
return 0;
301 TraceLock lk(search_mutex_, 15,
"WriteReadyCountSearch");
303 for (
auto ii = 0; ii < shm_ptr_->buffer_count; ++ii)
306 auto buf = getBufferInfo_(ii);
307 if ((buf->sem == BufferSemaphoreFlags::Empty && buf->sem_id == -1)
308 || (overwrite && buf->sem != BufferSemaphoreFlags::Writing))
319 std::deque<int> output;
320 if (!IsValid())
return output;
321 TraceLock lk(search_mutex_, 16,
"GetOwnedSearch");
322 for (
auto ii = 0; ii < shm_ptr_->buffer_count; ++ii)
324 auto buf = getBufferInfo_(ii);
325 if (buf->sem_id == manager_id_)
327 output.push_back(ii);
337 TraceLock lk(buffer_mutexes_[buffer], 17,
"DataSizeBuffer" + std::to_string(buffer));
338 auto buf = getBufferInfo_(buffer);
340 return buf->writePos;
347 TraceLock lk(buffer_mutexes_[buffer], 18,
"ResetReadPosBuffer" + std::to_string(buffer));
348 auto buf = getBufferInfo_(buffer);
356 TraceLock lk(buffer_mutexes_[buffer], 18,
"ResetWritePosBuffer" + std::to_string(buffer));
357 auto buf = getBufferInfo_(buffer);
358 checkBuffer_(buf, BufferSemaphoreFlags::Writing);
366 TraceLock lk(buffer_mutexes_[buffer], 19,
"IncReadPosBuffer" + std::to_string(buffer));
367 auto buf = getBufferInfo_(buffer);
369 TLOG_ARB(13,
"SharedMemoryManager") <<
"IncrementReadPos: buffer= " << buffer <<
", readPos=" << std::to_string(buf->readPos) <<
", bytes read=" << std::to_string(read) << TLOG_ENDL;
370 buf->readPos = buf->readPos + read;
371 TLOG_ARB(13,
"SharedMemoryManager") <<
"IncrementReadPos: buffer= " << buffer <<
", New readPos is " << std::to_string(buf->readPos) << TLOG_ENDL;
372 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) +
")");
378 TraceLock lk(buffer_mutexes_[buffer], 20,
"IncWritePosBuffer" + std::to_string(buffer));
379 auto buf = getBufferInfo_(buffer);
381 TLOG_ARB(13,
"SharedMemoryManager") <<
"IncrementWritePos: buffer= " << buffer <<
", writePos=" << std::to_string(buf->writePos) <<
", bytes written=" << std::to_string(written) << TLOG_ENDL;
382 buf->writePos += written;
383 TLOG_ARB(13,
"SharedMemoryManager") <<
"IncrementWritePos: buffer= " << buffer <<
", New writePos is " << std::to_string(buf->writePos) << TLOG_ENDL;
384 if (written == 0) Detach(
true,
"LogicError",
"Cannot increment Write pos by 0!");
390 TraceLock lk(buffer_mutexes_[buffer], 21,
"MoreDataInBuffer" + std::to_string(buffer));
391 auto buf = getBufferInfo_(buffer);
392 TLOG_ARB(13,
"SharedMemoryManager") <<
"MoreDataInBuffer: buffer= " << buffer <<
", readPos=" << std::to_string(buf->readPos) <<
", writePos=" << std::to_string(buf->writePos) << TLOG_ENDL;
393 return buf->readPos < buf->writePos;
399 TraceLock lk(buffer_mutexes_[buffer], 22,
"CheckBuffer" + std::to_string(buffer));
400 return checkBuffer_(getBufferInfo_(buffer), flags,
false);
406 TraceLock lk(buffer_mutexes_[buffer], 23,
"FillBuffer" + std::to_string(buffer));
407 auto shmBuf = getBufferInfo_(buffer);
408 touchBuffer_(shmBuf);
409 if (shmBuf->sem_id == manager_id_)
411 if (shmBuf->sem != BufferSemaphoreFlags::Full)
412 shmBuf->sem = BufferSemaphoreFlags::Full;
414 shmBuf->sem_id = destination;
420 TLOG_ARB(13,
"SharedMemoryManager") <<
"MarkBufferEmpty BEGIN" << TLOG_ENDL;
422 TraceLock lk(buffer_mutexes_[buffer], 24,
"EmptyBuffer" + std::to_string(buffer));
423 auto shmBuf = getBufferInfo_(buffer);
426 checkBuffer_(shmBuf, BufferSemaphoreFlags::Reading,
true);
428 touchBuffer_(shmBuf);
431 shmBuf->sem = BufferSemaphoreFlags::Full;
433 if ((force && (manager_id_ == 0 || manager_id_ == shmBuf->sem_id)) || (!force && shm_ptr_->destructive_read_mode))
435 TLOG_ARB(13,
"SharedMemoryManager") <<
"MarkBufferEmpty Resetting buffer to Empty state" << TLOG_ENDL;
436 shmBuf->writePos = 0;
437 shmBuf->sem = BufferSemaphoreFlags::Empty;
438 if (shm_ptr_->reader_pos == static_cast<unsigned>(buffer) && !shm_ptr_->destructive_read_mode)
440 TLOG_ARB(13,
"SharedMemoryManager") <<
"MarkBufferEmpty Broadcast mode; incrementing reader_pos" << TLOG_ENDL;
441 shm_ptr_->reader_pos = (buffer + 1) % shm_ptr_->buffer_count;
445 TLOG_ARB(13,
"SharedMemoryManager") <<
"MarkBufferEmpty END" << TLOG_ENDL;
451 TraceLock lk(buffer_mutexes_[buffer], 25,
"ResetBuffer" + std::to_string(buffer));
452 auto shmBuf = getBufferInfo_(buffer);
464 if (delta > 0xFFFFFFFF) {
465 TLOG_TRACE(
"SharedMemoryManager") <<
"Buffer has touch time in the future, setting it to current time and ignoring..." << TLOG_ENDL;
469 if (delta <= shm_ptr_->buffer_timeout_us || shmBuf->sem == BufferSemaphoreFlags::Empty)
return false;
470 TLOG_TRACE(
"SharedMemoryManager") <<
"Buffer " << buffer <<
" is stale, time=" <<
TimeUtils::gettimeofday_us() <<
", last touch=" << shmBuf->last_touch_time <<
", d=" << delta <<
", timeout=" << shm_ptr_->buffer_timeout_us << TLOG_ENDL;
472 if (shmBuf->sem_id == manager_id_ && shmBuf->sem == BufferSemaphoreFlags::Writing)
476 if (!shm_ptr_->destructive_read_mode && shmBuf->sem == BufferSemaphoreFlags::Full)
478 TLOG_DEBUG(
"SharedMemoryManager") <<
"Resetting old broadcast mode buffer" << TLOG_ENDL;
479 shmBuf->writePos = 0;
480 shmBuf->sem = BufferSemaphoreFlags::Empty;
482 if (shm_ptr_->reader_pos = buffer)shm_ptr_->reader_pos = (buffer + 1) % shm_ptr_->buffer_count;
486 if (shmBuf->sem_id != manager_id_ && shmBuf->sem == BufferSemaphoreFlags::Reading)
488 TLOG_WARNING(
"SharedMemoryManager") <<
"Stale Read buffer ( " << delta <<
" / " << shm_ptr_->buffer_timeout_us <<
" us ) detected! Resetting..." << TLOG_ENDL;
490 shmBuf->sem = BufferSemaphoreFlags::Full;
499 TLOG_ARB(13,
"SharedMemoryManager") <<
"Write BEGIN" << TLOG_ENDL;
501 TraceLock lk(buffer_mutexes_[buffer], 26,
"WriteBuffer" + std::to_string(buffer));
502 auto shmBuf = getBufferInfo_(buffer);
503 checkBuffer_(shmBuf, BufferSemaphoreFlags::Writing);
504 touchBuffer_(shmBuf);
505 TLOG_ARB(13,
"SharedMemoryManager") <<
"Buffer Write Pos is " << std::to_string(shmBuf->writePos) <<
", write size is " << std::to_string(size) << TLOG_ENDL;
506 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!");
508 auto pos = GetWritePos(buffer);
509 memcpy(pos, data, size);
510 shmBuf->writePos = shmBuf->writePos + size;
511 if (shmBuf->sequence_id > last_seen_id_)
513 last_seen_id_ = shmBuf->sequence_id;
515 TLOG_ARB(13,
"SharedMemoryManager") <<
"Write END" << TLOG_ENDL;
522 TraceLock lk(buffer_mutexes_[buffer], 27,
"ReadBuffer" + std::to_string(buffer));
523 auto shmBuf = getBufferInfo_(buffer);
524 checkBuffer_(shmBuf, BufferSemaphoreFlags::Reading);
525 touchBuffer_(shmBuf);
526 if (shmBuf->readPos + size > shm_ptr_->buffer_size) Detach(
true,
"SharedMemoryRead",
"Attempted to read more data than exists in Shared Memory!");
528 auto pos = GetReadPos(buffer);
529 memcpy(data, pos, size);
530 shmBuf->readPos += size;
531 touchBuffer_(shmBuf);
532 return checkBuffer_(shmBuf, BufferSemaphoreFlags::Reading,
false);
537 std::ostringstream ostr;
538 ostr <<
"ShmStruct: " << std::endl
539 <<
"Reader Position: " << shm_ptr_->reader_pos << std::endl
540 <<
"Writer Position: " << shm_ptr_->writer_pos << std::endl
541 <<
"Next ID Number: " << shm_ptr_->next_id << std::endl
542 <<
"Buffer Count: " << shm_ptr_->buffer_count << std::endl
543 <<
"Buffer Size: " << std::to_string(shm_ptr_->buffer_size) <<
" bytes" << std::endl
544 <<
"Buffers Written: " << std::to_string(shm_ptr_->next_sequence_id) << std::endl
545 <<
"Rank of Writer: " << shm_ptr_->rank << std::endl
546 <<
"Ready Magic Bytes: 0x" << std::hex << shm_ptr_->ready_magic << std::endl << std::endl;
548 for (
auto ii = 0; ii < shm_ptr_->buffer_count; ++ii)
550 auto buf = getBufferInfo_(ii);
551 ostr <<
"ShmBuffer " << std::dec << ii << std::endl
552 <<
"sequenceID: " << std::to_string(buf->sequence_id) << std::endl
553 <<
"writePos: " << std::to_string(buf->writePos) << std::endl
554 <<
"readPos: " << std::to_string(buf->readPos) << std::endl
555 <<
"sem: " << FlagToString(buf->sem) << std::endl
556 <<
"Owner: " << std::to_string(buf->sem_id.load()) << std::endl
557 <<
"Last Touch Time: " << std::to_string(buf->last_touch_time / 1000000.0) << std::endl << std::endl;
565 auto buf = getBufferInfo_(buffer);
566 return bufferStart_(buffer) + buf->readPos;
570 auto buf = getBufferInfo_(buffer);
571 return bufferStart_(buffer) + buf->writePos;
576 return bufferStart_(buffer);
579 uint8_t* artdaq::SharedMemoryManager::dataStart_()
const
581 return reinterpret_cast<uint8_t*
>(shm_ptr_ + 1) + shm_ptr_->buffer_count *
sizeof(ShmBuffer);
584 uint8_t* artdaq::SharedMemoryManager::bufferStart_(
int buffer)
586 if (buffer >= shm_ptr_->buffer_count) Detach(
true,
"ArgumentOutOfRange",
"The specified buffer does not exist!");
587 return dataStart_() + buffer * shm_ptr_->buffer_size;
590 artdaq::SharedMemoryManager::ShmBuffer* artdaq::SharedMemoryManager::getBufferInfo_(
int buffer)
592 if (buffer >= shm_ptr_->buffer_count) Detach(
true,
"ArgumentOutOfRange",
"The specified buffer does not exist!");
593 return reinterpret_cast<ShmBuffer*
>(
reinterpret_cast<uint8_t*
>(shm_ptr_ + 1) + buffer *
sizeof(ShmBuffer));
596 bool artdaq::SharedMemoryManager::checkBuffer_(ShmBuffer* buffer, BufferSemaphoreFlags flags,
bool exceptions)
600 if (buffer->sem != flags) Detach(
true,
"StateAccessViolation",
"Shared Memory buffer is not in the correct state! (expected " + FlagToString(flags) +
", actual " + FlagToString(buffer->sem) +
")");
601 if (buffer->sem_id != manager_id_) Detach(
true,
"OwnerAccessViolation",
"Shared Memory buffer is not owned by this manager instance!");
603 bool ret = (buffer->sem_id == manager_id_ || (buffer->sem_id == -1 && (flags == BufferSemaphoreFlags::Full || flags == BufferSemaphoreFlags::Empty))) && buffer->sem == flags;
607 TLOG_WARNING(
"SharedMemoryManager") <<
"CheckBuffer detected issue with buffer " << std::to_string(buffer->sequence_id) <<
"!"
608 <<
" ID: " << buffer->sem_id <<
" (" << manager_id_ <<
"), Flag: " << FlagToString(buffer->sem) <<
" (" << FlagToString(flags) <<
"). "
609 <<
"ID -1 is okay if desired flag is \"Full\" or \"Empty\"." << TLOG_ENDL;
615 void artdaq::SharedMemoryManager::touchBuffer_(ShmBuffer* buffer)
617 if (buffer->sem_id != manager_id_)
return;
618 TLOG_TRACE(
"SharedMemoryManager") <<
"touchBuffer_: Touching buffer with sequence_id " << std::to_string(buffer->sequence_id) << TLOG_ENDL;
626 auto bufs = GetBuffersOwnedByManager();
627 for (
auto buf : bufs)
629 auto shmBuf = getBufferInfo_(buf);
630 if (shmBuf->sem == BufferSemaphoreFlags::Writing)
632 shmBuf->sem = BufferSemaphoreFlags::Empty;
634 else if (shmBuf->sem == BufferSemaphoreFlags::Reading)
636 shmBuf->sem = BufferSemaphoreFlags::Full;
648 if (manager_id_ == 0 && shm_segment_id_ > -1)
650 shmctl(shm_segment_id_, IPC_RMID, NULL);
653 if (category.size() > 0 && message.size() > 0)
655 TLOG_ERROR(
"SharedMemoryManager") << category <<
": " << message << TLOG_ENDL;
659 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. ...