00001 #include <sys/shm.h>
00002 #include <thread>
00003 #include "tracemf.h"
00004 #include "cetlib_except/exception.h"
00005 #include "artdaq-core/Core/SharedMemoryManager.hh"
00006 #include "artdaq-core/Utilities/TraceLock.hh"
00007 #include "SharedMemoryManager.hh"
00008
00009 artdaq::SharedMemoryManager::SharedMemoryManager(uint32_t shm_key, size_t buffer_count, size_t buffer_size, uint64_t buffer_timeout_us, bool destructive_read_mode)
00010 : shm_segment_id_(-1)
00011 , shm_ptr_(NULL)
00012 , shm_key_(shm_key)
00013 , manager_id_(-1)
00014 , buffer_mutexes_()
00015 , last_seen_id_(0)
00016 {
00017 requested_shm_parameters_.buffer_count = buffer_count;
00018 requested_shm_parameters_.buffer_size = buffer_size;
00019 requested_shm_parameters_.buffer_timeout_us = buffer_timeout_us;
00020 requested_shm_parameters_.destructive_read_mode = destructive_read_mode;
00021
00022 Attach();
00023 }
00024
00025 artdaq::SharedMemoryManager::~SharedMemoryManager()
00026 {
00027 TLOG_ARB(5, "SharedMemoryManager") << "~SharedMemoryManager called" << TLOG_ENDL;
00028 Detach();
00029 TLOG_ARB(5, "SharedMemoryManager") << "~SharedMemoryManager done" << TLOG_ENDL;
00030 }
00031
00032 void artdaq::SharedMemoryManager::Attach()
00033 {
00034 if (IsValid())
00035 {
00036 if (manager_id_ == 0) return;
00037 Detach();
00038 }
00039 auto start_time = std::chrono::steady_clock::now();
00040 last_seen_id_ = 0;
00041 size_t shmSize = requested_shm_parameters_.buffer_count * (requested_shm_parameters_.buffer_size + sizeof(ShmBuffer)) + sizeof(ShmStruct);
00042
00043 shm_segment_id_ = shmget(shm_key_, shmSize, 0666);
00044 if (shm_segment_id_ == -1 && requested_shm_parameters_.buffer_count > 0 && manager_id_ <= 0)
00045 {
00046 TLOG_DEBUG("SharedMemoryManager") << "Creating shared memory segment with key 0x" << std::hex << shm_key_ << TLOG_ENDL;
00047 shm_segment_id_ = shmget(shm_key_, shmSize, IPC_CREAT | 0666);
00048 manager_id_ = 0;
00049 }
00050
00051 while (shm_segment_id_ == -1 && TimeUtils::GetElapsedTimeMilliseconds(start_time) < 1000)
00052 {
00053 shm_segment_id_ = shmget(shm_key_, shmSize, 0666);
00054
00055 }
00056 TLOG_DEBUG("SharedMemoryManager") << "shm_key == 0x" << std::hex << shm_key_ << ", shm_segment_id == " << shm_segment_id_ << TLOG_ENDL;
00057
00058 if (shm_segment_id_ > -1)
00059 {
00060 TLOG_DEBUG("SharedMemoryManager")
00061 << "Attached to shared memory segment with ID = " << shm_segment_id_
00062 << " and size " << shmSize
00063 << " bytes" << TLOG_ENDL;
00064 shm_ptr_ = (ShmStruct*)shmat(shm_segment_id_, 0, 0);
00065 TLOG_DEBUG("SharedMemoryManager")
00066 << "Attached to shared memory segment at address "
00067 << std::hex << (void*)shm_ptr_ << std::dec << TLOG_ENDL;
00068 if (shm_ptr_ && shm_ptr_ != (void *)-1)
00069 {
00070 if (manager_id_ == 0)
00071 {
00072 if (shm_ptr_->ready_magic == 0xCAFE1111)
00073 {
00074 TLOG_ERROR("SharedMemoryManager") << "Owner encountered already-initialized Shared Memory!" << TLOG_ENDL;
00075 exit(-2);
00076 }
00077 TLOG_DEBUG("SharedMemoryManager") << "Owner initializing Shared Memory" << TLOG_ENDL;
00078 shm_ptr_->next_id = 1;
00079 shm_ptr_->next_sequence_id = 0;
00080 shm_ptr_->reader_pos = 0;
00081 shm_ptr_->writer_pos = 0;
00082 shm_ptr_->buffer_size = requested_shm_parameters_.buffer_size;
00083 shm_ptr_->buffer_count = requested_shm_parameters_.buffer_count;
00084 shm_ptr_->buffer_timeout_us = requested_shm_parameters_.buffer_timeout_us;
00085 shm_ptr_->destructive_read_mode = requested_shm_parameters_.destructive_read_mode;
00086
00087 for (int ii = 0; ii < static_cast<int>(requested_shm_parameters_.buffer_count); ++ii)
00088 {
00089 getBufferInfo_(ii)->writePos = 0;
00090 getBufferInfo_(ii)->readPos = 0;
00091 getBufferInfo_(ii)->sem = BufferSemaphoreFlags::Empty;
00092 getBufferInfo_(ii)->sem_id = -1;
00093 }
00094
00095 shm_ptr_->ready_magic = 0xCAFE1111;
00096 }
00097 else
00098 {
00099 TLOG_DEBUG("SharedMemoryManager") << "Waiting for owner to initalize Shared Memory" << TLOG_ENDL;
00100 while (shm_ptr_->ready_magic != 0xCAFE1111) { usleep(1000); }
00101 TLOG_DEBUG("SharedMemoryManager") << "Getting ID from Shared Memory" << TLOG_ENDL;
00102 GetNewId();
00103 shm_ptr_->lowest_seq_id_read = 0;
00104 TLOG_DEBUG("SharedMemoryManager") << "Getting Shared Memory Size parameters" << TLOG_ENDL;
00105 }
00106
00107 TLOG_DEBUG("SharedMemoryManager") << "Initialization Complete: "
00108 << "key: 0x" << std::hex << shm_key_
00109 << ", manager ID: " << manager_id_
00110 << ", Buffer size: " << std::to_string(shm_ptr_->buffer_size)
00111 << ", Buffer count: " << std::to_string(shm_ptr_->buffer_count) << TLOG_ENDL;
00112 return;
00113 }
00114 else
00115 {
00116 TLOG_ERROR("SharedMemoryManager") << "Failed to attach to shared memory segment "
00117 << shm_segment_id_ << TLOG_ENDL;
00118 }
00119 }
00120 else
00121 {
00122 TLOG_ERROR("SharedMemoryManager") << "Failed to connect to shared memory segment"
00123 << ", errno = " << errno << ". Please check "
00124 << "if a stale shared memory segment needs to "
00125 << "be cleaned up. (ipcs, ipcrm -m <segId>)" << TLOG_ENDL;
00126 }
00127 return;
00128 }
00129
00130 int artdaq::SharedMemoryManager::GetBufferForReading()
00131 {
00132 TLOG_ARB(13, "SharedMemoryManager") << "GetBufferForReading BEGIN" << TLOG_ENDL;
00133
00134
00135 TraceLock lk(search_mutex_, 11, "GetBufferForReadingSearch");
00136 auto rp = shm_ptr_->reader_pos.load();
00137
00138 TLOG_ARB(13, "SharedMemoryManager") << "GetBufferForReading lock acquired, scanning buffers" << TLOG_ENDL;
00139 bool retry = true;
00140 int buffer_num = -1;
00141 while (retry)
00142 {
00143 ShmBuffer* buffer_ptr = nullptr;
00144 uint64_t seqID = -1;
00145 for (auto ii = 0; ii < shm_ptr_->buffer_count; ++ii)
00146 {
00147 auto buffer = (ii + rp) % shm_ptr_->buffer_count;
00148
00149
00150 TLOG_ARB(14, "SharedMemoryManager") << "GetBufferForReading Checking if buffer " << buffer << " is stale" << TLOG_ENDL;
00151 ResetBuffer(buffer);
00152
00153 auto buf = getBufferInfo_(buffer);
00154 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;
00155 if (buf->sem == BufferSemaphoreFlags::Full && (buf->sem_id == -1 || buf->sem_id == manager_id_) && buf->sequence_id > last_seen_id_)
00156 {
00157 if (buf->sequence_id < seqID)
00158 {
00159 buffer_ptr = buf;
00160 seqID = buf->sequence_id;
00161 buffer_num = buffer;
00162 }
00163 }
00164 }
00165
00166 if (!buffer_ptr || (buffer_ptr && buffer_ptr->sem_id != -1 && buffer_ptr->sem_id != manager_id_))
00167 {
00168 continue;
00169 }
00170
00171 if (buffer_num >= 0)
00172 {
00173 TLOG_ARB(13, "SharedMemoryManager") << "GetBufferForReading Found buffer " << buffer_num << TLOG_ENDL;
00174 buffer_ptr->sem_id = manager_id_;
00175 buffer_ptr->sem = BufferSemaphoreFlags::Reading;
00176 if (buffer_ptr->sem_id != manager_id_) { continue; }
00177 buffer_ptr->readPos = 0;
00178 touchBuffer_(buffer_ptr);
00179 if (buffer_ptr->sem_id != manager_id_) { continue; }
00180 if (shm_ptr_->destructive_read_mode && shm_ptr_->lowest_seq_id_read == last_seen_id_)
00181 {
00182 shm_ptr_->lowest_seq_id_read = seqID;
00183 }
00184 last_seen_id_ = seqID;
00185 if (shm_ptr_->destructive_read_mode) shm_ptr_->reader_pos = (buffer_num + 1) % shm_ptr_->buffer_count;
00186 }
00187 retry = false;
00188 }
00189
00190 TLOG_ARB(13, "SharedMemoryManager") << "GetBufferForReading returning -1 because no buffers are ready" << TLOG_ENDL;
00191 return buffer_num;
00192 }
00193
00194 int artdaq::SharedMemoryManager::GetBufferForWriting(bool overwrite)
00195 {
00196 TLOG_ARB(13, "SharedMemoryManager") << "GetBufferForWriting BEGIN" << TLOG_ENDL;
00197
00198 TraceLock lk(search_mutex_, 12, "GetBufferForWritingSearch");
00199 auto wp = shm_ptr_->writer_pos.load();
00200
00201
00202 for (auto ii = 0; ii < shm_ptr_->buffer_count; ++ii)
00203 {
00204 auto buffer = (ii + wp) % shm_ptr_->buffer_count;
00205
00206 ResetBuffer(buffer);
00207
00208 auto buf = getBufferInfo_(buffer);
00209 if (buf->sem == BufferSemaphoreFlags::Empty)
00210 {
00211 buf->sem_id = manager_id_;
00212 buf->sem = BufferSemaphoreFlags::Writing;
00213 if (buf->sem_id != manager_id_) continue;
00214 buf->sequence_id = ++shm_ptr_->next_sequence_id;
00215 buf->writePos = 0;
00216 shm_ptr_->writer_pos = (buffer + 1) % shm_ptr_->buffer_count;
00217 touchBuffer_(buf);
00218 TLOG_ARB(13, "SharedMemoryManager") << "GetBufferForWriting returning " << buffer << TLOG_ENDL;
00219 return buffer;
00220 }
00221 }
00222
00223 if (overwrite)
00224 {
00225
00226 for (auto ii = 0; ii < shm_ptr_->buffer_count; ++ii)
00227 {
00228 auto buffer = (ii + wp) % shm_ptr_->buffer_count;
00229
00230 ResetBuffer(buffer);
00231
00232 auto buf = getBufferInfo_(buffer);
00233 if (buf->sem == BufferSemaphoreFlags::Full)
00234 {
00235 buf->sem_id = manager_id_;
00236 buf->sem = BufferSemaphoreFlags::Writing;
00237 if (buf->sem_id != manager_id_) continue;
00238 buf->sequence_id = ++shm_ptr_->next_sequence_id;
00239 buf->writePos = 0;
00240 shm_ptr_->writer_pos = (buffer + 1) % shm_ptr_->buffer_count;
00241 touchBuffer_(buf);
00242 TLOG_ARB(13, "SharedMemoryManager") << "GetBufferForWriting returning " << buffer << TLOG_ENDL;
00243 return buffer;
00244 }
00245 }
00246
00247
00248 for (auto ii = 0; ii < shm_ptr_->buffer_count; ++ii)
00249 {
00250 auto buffer = (ii + wp) % shm_ptr_->buffer_count;
00251
00252 ResetBuffer(buffer);
00253
00254 auto buf = getBufferInfo_(buffer);
00255 if (buf->sem == BufferSemaphoreFlags::Reading)
00256 {
00257 buf->sem_id = manager_id_;
00258 buf->sem = BufferSemaphoreFlags::Writing;
00259 if (buf->sem_id != manager_id_) continue;
00260 buf->sequence_id = ++shm_ptr_->next_sequence_id;
00261 buf->writePos = 0;
00262 shm_ptr_->writer_pos = (buffer + 1) % shm_ptr_->buffer_count;
00263 TLOG_ARB(13, "SharedMemoryManager") << "GetBufferForWriting returning " << buffer << TLOG_ENDL;
00264 touchBuffer_(buf);
00265 return buffer;
00266 }
00267 }
00268 }
00269
00270 TLOG_ARB(13, "SharedMemoryManager") << "GetBufferForWriting Returning -1 because no buffers are ready" << TLOG_ENDL;
00271 return -1;
00272 }
00273
00274 size_t artdaq::SharedMemoryManager::ReadReadyCount()
00275 {
00276 if (!IsValid()) return 0;
00277 TLOG_ARB(23, "SharedMemoryManager") << "ReadReadyCount BEGIN" << TLOG_ENDL;
00278
00279 TraceLock lk(search_mutex_, 14, "ReadReadyCountSearch");
00280 size_t count = 0;
00281 for (auto ii = 0; ii < shm_ptr_->buffer_count; ++ii)
00282 {
00283 TLOG_ARB(24, "SharedMemoryManager") << "ReadReadyCount: Checking if buffer " << ii << " is stale." << TLOG_ENDL;
00284 ResetBuffer(ii);
00285 auto buf = getBufferInfo_(ii);
00286 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;
00287 if (buf->sem == BufferSemaphoreFlags::Full && (buf->sem_id == -1 || buf->sem_id == manager_id_) && buf->sequence_id > last_seen_id_)
00288 {
00289 TLOG_ARB(24, "SharedMemoryManager") << "ReadReadyCount: Buffer " << ii << " is either unowned or owned by this manager, and is marked full." << TLOG_ENDL;
00290 ++count;
00291 }
00292 }
00293
00294 TLOG_ARB(23, "SharedMemoryManager") << "ReadReadyCount returning " << std::to_string(count) << TLOG_ENDL;
00295 return count;
00296 }
00297
00298 size_t artdaq::SharedMemoryManager::WriteReadyCount(bool overwrite)
00299 {
00300 if (!IsValid()) return 0;
00301
00302 TraceLock lk(search_mutex_, 15, "WriteReadyCountSearch");
00303 size_t count = 0;
00304 for (auto ii = 0; ii < shm_ptr_->buffer_count; ++ii)
00305 {
00306 ResetBuffer(ii);
00307 auto buf = getBufferInfo_(ii);
00308 if ((buf->sem == BufferSemaphoreFlags::Empty && buf->sem_id == -1)
00309 || (overwrite && buf->sem != BufferSemaphoreFlags::Writing))
00310 {
00311 ++count;
00312 }
00313 }
00314 return count;
00315 }
00316
00317 std::deque<int> artdaq::SharedMemoryManager::GetBuffersOwnedByManager()
00318 {
00319
00320 std::deque<int> output;
00321 if (!IsValid()) return output;
00322 TraceLock lk(search_mutex_, 16, "GetOwnedSearch");
00323 for (auto ii = 0; ii < shm_ptr_->buffer_count; ++ii)
00324 {
00325 auto buf = getBufferInfo_(ii);
00326 if (buf->sem_id == manager_id_)
00327 {
00328 output.push_back(ii);
00329 }
00330 }
00331
00332 return output;
00333 }
00334
00335 size_t artdaq::SharedMemoryManager::BufferDataSize(int buffer)
00336 {
00337
00338 TraceLock lk(buffer_mutexes_[buffer], 17, "DataSizeBuffer" + std::to_string(buffer));
00339 auto buf = getBufferInfo_(buffer);
00340 touchBuffer_(buf);
00341 return buf->writePos;
00342 }
00343
00344
00345 void artdaq::SharedMemoryManager::ResetReadPos(int buffer)
00346 {
00347
00348 TraceLock lk(buffer_mutexes_[buffer], 18, "ResetReadPosBuffer" + std::to_string(buffer));
00349 auto buf = getBufferInfo_(buffer);
00350 touchBuffer_(buf);
00351 buf->readPos = 0;
00352 }
00353
00354 void artdaq::SharedMemoryManager::ResetWritePos(int buffer)
00355 {
00356
00357 TraceLock lk(buffer_mutexes_[buffer], 18, "ResetWritePosBuffer" + std::to_string(buffer));
00358 auto buf = getBufferInfo_(buffer);
00359 checkBuffer_(buf, BufferSemaphoreFlags::Writing);
00360 touchBuffer_(buf);
00361 buf->writePos = 0;
00362 }
00363
00364 void artdaq::SharedMemoryManager::IncrementReadPos(int buffer, size_t read)
00365 {
00366
00367 TraceLock lk(buffer_mutexes_[buffer], 19, "IncReadPosBuffer" + std::to_string(buffer));
00368 auto buf = getBufferInfo_(buffer);
00369 touchBuffer_(buf);
00370 TLOG_ARB(13, "SharedMemoryManager") << "IncrementReadPos: buffer= " << buffer << ", readPos=" << std::to_string(buf->readPos) << ", bytes read=" << std::to_string(read) << TLOG_ENDL;
00371 buf->readPos = buf->readPos + read;
00372 TLOG_ARB(13, "SharedMemoryManager") << "IncrementReadPos: buffer= " << buffer << ", New readPos is " << std::to_string(buf->readPos) << TLOG_ENDL;
00373 if (read == 0)
00374 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) + ")");
00375 }
00376
00377 void artdaq::SharedMemoryManager::IncrementWritePos(int buffer, size_t written)
00378 {
00379
00380 TraceLock lk(buffer_mutexes_[buffer], 20, "IncWritePosBuffer" + std::to_string(buffer));
00381 auto buf = getBufferInfo_(buffer);
00382 touchBuffer_(buf);
00383 TLOG_ARB(13, "SharedMemoryManager") << "IncrementWritePos: buffer= " << buffer << ", writePos=" << std::to_string(buf->writePos) << ", bytes written=" << std::to_string(written) << TLOG_ENDL;
00384 buf->writePos += written;
00385 TLOG_ARB(13, "SharedMemoryManager") << "IncrementWritePos: buffer= " << buffer << ", New writePos is " << std::to_string(buf->writePos) << TLOG_ENDL;
00386 if (written == 0) Detach(true, "LogicError", "Cannot increment Write pos by 0!");
00387 }
00388
00389 bool artdaq::SharedMemoryManager::MoreDataInBuffer(int buffer)
00390 {
00391
00392 TraceLock lk(buffer_mutexes_[buffer], 21, "MoreDataInBuffer" + std::to_string(buffer));
00393 auto buf = getBufferInfo_(buffer);
00394 TLOG_ARB(13, "SharedMemoryManager") << "MoreDataInBuffer: buffer= " << buffer << ", readPos=" << std::to_string(buf->readPos) << ", writePos=" << std::to_string(buf->writePos) << TLOG_ENDL;
00395 return buf->readPos < buf->writePos;
00396 }
00397
00398 bool artdaq::SharedMemoryManager::CheckBuffer(int buffer, BufferSemaphoreFlags flags)
00399 {
00400
00401 TraceLock lk(buffer_mutexes_[buffer], 22, "CheckBuffer" + std::to_string(buffer));
00402 return checkBuffer_(getBufferInfo_(buffer), flags, false);
00403 }
00404
00405 void artdaq::SharedMemoryManager::MarkBufferFull(int buffer, int destination)
00406 {
00407
00408 TraceLock lk(buffer_mutexes_[buffer], 23, "FillBuffer" + std::to_string(buffer));
00409 auto shmBuf = getBufferInfo_(buffer);
00410 touchBuffer_(shmBuf);
00411 if (shmBuf->sem_id == manager_id_)
00412 {
00413 if (shmBuf->sem != BufferSemaphoreFlags::Full)
00414 shmBuf->sem = BufferSemaphoreFlags::Full;
00415
00416 shmBuf->sem_id = destination;
00417 }
00418 }
00419
00420 void artdaq::SharedMemoryManager::MarkBufferEmpty(int buffer, bool force)
00421 {
00422 TLOG_ARB(13, "SharedMemoryManager") << "MarkBufferEmpty BEGIN" << TLOG_ENDL;
00423
00424 TraceLock lk(buffer_mutexes_[buffer], 24, "EmptyBuffer" + std::to_string(buffer));
00425 auto shmBuf = getBufferInfo_(buffer);
00426 if (!force)
00427 {
00428 checkBuffer_(shmBuf, BufferSemaphoreFlags::Reading, true);
00429 }
00430 touchBuffer_(shmBuf);
00431
00432 shmBuf->readPos = 0;
00433 shmBuf->sem = BufferSemaphoreFlags::Full;
00434
00435 if ((force && (manager_id_ == 0 || manager_id_ == shmBuf->sem_id)) || (!force && shm_ptr_->destructive_read_mode))
00436 {
00437 TLOG_ARB(13, "SharedMemoryManager") << "MarkBufferEmpty Resetting buffer to Empty state" << TLOG_ENDL;
00438 shmBuf->writePos = 0;
00439 shmBuf->sem = BufferSemaphoreFlags::Empty;
00440 if (shm_ptr_->reader_pos == static_cast<unsigned>(buffer) && !shm_ptr_->destructive_read_mode)
00441 {
00442 TLOG_ARB(13, "SharedMemoryManager") << "MarkBufferEmpty Broadcast mode; incrementing reader_pos" << TLOG_ENDL;
00443 shm_ptr_->reader_pos = (buffer + 1) % shm_ptr_->buffer_count;
00444 }
00445 }
00446 shmBuf->sem_id = -1;
00447 TLOG_ARB(13, "SharedMemoryManager") << "MarkBufferEmpty END" << TLOG_ENDL;
00448 }
00449
00450 bool artdaq::SharedMemoryManager::ResetBuffer(int buffer)
00451 {
00452
00453 TraceLock lk(buffer_mutexes_[buffer], 25, "ResetBuffer" + std::to_string(buffer));
00454 auto shmBuf = getBufferInfo_(buffer);
00455
00456
00457
00458
00459
00460
00461
00462
00463
00464
00465 if (TimeUtils::gettimeofday_us() - shmBuf->last_touch_time <= shm_ptr_->buffer_timeout_us) return false;
00466
00467 if (shmBuf->sem_id == manager_id_ && shmBuf->sem == BufferSemaphoreFlags::Writing)
00468 {
00469 return true;
00470 }
00471 if (!shm_ptr_->destructive_read_mode && shmBuf->sem == BufferSemaphoreFlags::Full)
00472 {
00473 TLOG_DEBUG("SharedMemoryManager") << "Resetting old broadcast mode buffer" << TLOG_ENDL;
00474 shmBuf->writePos = 0;
00475 shmBuf->sem = BufferSemaphoreFlags::Empty;
00476 shmBuf->sem_id = -1;
00477 if (shm_ptr_->reader_pos = buffer)shm_ptr_->reader_pos = (buffer + 1) % shm_ptr_->buffer_count;
00478 return true;
00479 }
00480
00481 if (shmBuf->sem_id != manager_id_ && shmBuf->sem == BufferSemaphoreFlags::Reading)
00482 {
00483 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;
00484 shmBuf->readPos = 0;
00485 shmBuf->sem = BufferSemaphoreFlags::Full;
00486 shmBuf->sem_id = -1;
00487 return true;
00488 }
00489 return false;
00490 }
00491
00492 size_t artdaq::SharedMemoryManager::Write(int buffer, void* data, size_t size)
00493 {
00494 TLOG_ARB(13, "SharedMemoryManager") << "Write BEGIN" << TLOG_ENDL;
00495
00496 TraceLock lk(buffer_mutexes_[buffer], 26, "WriteBuffer" + std::to_string(buffer));
00497 auto shmBuf = getBufferInfo_(buffer);
00498 checkBuffer_(shmBuf, BufferSemaphoreFlags::Writing);
00499 touchBuffer_(shmBuf);
00500 TLOG_ARB(13, "SharedMemoryManager") << "Buffer Write Pos is " << std::to_string(shmBuf->writePos) << ", write size is " << std::to_string(size) << TLOG_ENDL;
00501 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!");
00502
00503 auto pos = GetWritePos(buffer);
00504 memcpy(pos, data, size);
00505 shmBuf->writePos = shmBuf->writePos + size;
00506 if (shmBuf->sequence_id > last_seen_id_)
00507 {
00508 last_seen_id_ = shmBuf->sequence_id;
00509 }
00510 TLOG_ARB(13, "SharedMemoryManager") << "Write END" << TLOG_ENDL;
00511 return size;
00512 }
00513
00514 bool artdaq::SharedMemoryManager::Read(int buffer, void* data, size_t size)
00515 {
00516
00517 TraceLock lk(buffer_mutexes_[buffer], 27, "ReadBuffer" + std::to_string(buffer));
00518 auto shmBuf = getBufferInfo_(buffer);
00519 checkBuffer_(shmBuf, BufferSemaphoreFlags::Reading);
00520 touchBuffer_(shmBuf);
00521 if (shmBuf->readPos + size > shm_ptr_->buffer_size) Detach(true, "SharedMemoryRead", "Attempted to read more data than exists in Shared Memory!");
00522
00523 auto pos = GetReadPos(buffer);
00524 memcpy(data, pos, size);
00525 shmBuf->readPos += size;
00526 return checkBuffer_(shmBuf, BufferSemaphoreFlags::Reading, false);
00527 }
00528
00529 std::string artdaq::SharedMemoryManager::toString()
00530 {
00531 std::ostringstream ostr;
00532 ostr << "ShmStruct: " << std::endl
00533 << "Reader Position: " << shm_ptr_->reader_pos << std::endl
00534 << "Writer Position: " << shm_ptr_->writer_pos << std::endl
00535 << "Next ID Number: " << shm_ptr_->next_id << std::endl
00536 << "Buffer Count: " << shm_ptr_->buffer_count << std::endl
00537 << "Buffer Size: " << std::to_string(shm_ptr_->buffer_size) << " bytes" << std::endl
00538 << "Buffers Written: " << std::to_string(shm_ptr_->next_sequence_id) << std::endl
00539 << "Rank of Writer: " << shm_ptr_->rank << std::endl
00540 << "Ready Magic Bytes: 0x" << std::hex << shm_ptr_->ready_magic << std::endl << std::endl;
00541
00542 for (auto ii = 0; ii < shm_ptr_->buffer_count; ++ii)
00543 {
00544 auto buf = getBufferInfo_(ii);
00545 ostr << "ShmBuffer " << std::dec << ii << std::endl
00546 << "sequenceID: " << std::to_string(buf->sequence_id) << std::endl
00547 << "writePos: " << std::to_string(buf->writePos) << std::endl
00548 << "readPos: " << std::to_string(buf->readPos) << std::endl
00549 << "sem: " << FlagToString(buf->sem) << std::endl
00550 << "Owner: " << std::to_string(buf->sem_id.load()) << std::endl
00551 << "Last Touch Time: " << std::to_string(buf->last_touch_time / 1000000.0) << std::endl << std::endl;
00552 }
00553
00554 return ostr.str();
00555 }
00556
00557 void* artdaq::SharedMemoryManager::GetReadPos(int buffer)
00558 {
00559 auto buf = getBufferInfo_(buffer);
00560 return bufferStart_(buffer) + buf->readPos;
00561 }
00562 void* artdaq::SharedMemoryManager::GetWritePos(int buffer)
00563 {
00564 auto buf = getBufferInfo_(buffer);
00565 return bufferStart_(buffer) + buf->writePos;
00566 }
00567
00568 void* artdaq::SharedMemoryManager::GetBufferStart(int buffer)
00569 {
00570 return bufferStart_(buffer);
00571 }
00572
00573 uint8_t* artdaq::SharedMemoryManager::dataStart_() const
00574 {
00575 return reinterpret_cast<uint8_t*>(shm_ptr_ + 1) + shm_ptr_->buffer_count * sizeof(ShmBuffer);
00576 }
00577
00578 uint8_t* artdaq::SharedMemoryManager::bufferStart_(int buffer)
00579 {
00580 if (buffer >= shm_ptr_->buffer_count) Detach(true, "ArgumentOutOfRange", "The specified buffer does not exist!");
00581 return dataStart_() + buffer * shm_ptr_->buffer_size;
00582 }
00583
00584 artdaq::SharedMemoryManager::ShmBuffer* artdaq::SharedMemoryManager::getBufferInfo_(int buffer)
00585 {
00586 if (buffer >= shm_ptr_->buffer_count) Detach(true, "ArgumentOutOfRange", "The specified buffer does not exist!");
00587 return reinterpret_cast<ShmBuffer*>(reinterpret_cast<uint8_t*>(shm_ptr_ + 1) + buffer * sizeof(ShmBuffer));
00588 }
00589
00590 bool artdaq::SharedMemoryManager::checkBuffer_(ShmBuffer* buffer, BufferSemaphoreFlags flags, bool exceptions)
00591 {
00592 if (exceptions)
00593 {
00594 if (buffer->sem != flags) Detach(true, "StateAccessViolation", "Shared Memory buffer is not in the correct state! (expected " + FlagToString(flags) + ", actual " + FlagToString(buffer->sem) + ")");
00595 if (buffer->sem_id != manager_id_) Detach(true, "OwnerAccessViolation", "Shared Memory buffer is not owned by this manager instance!");
00596 }
00597 bool ret = (buffer->sem_id == manager_id_ || (buffer->sem_id == -1 && (flags == BufferSemaphoreFlags::Full || flags == BufferSemaphoreFlags::Empty))) && buffer->sem == flags;
00598
00599 if (!ret)
00600 {
00601 TLOG_WARNING("SharedMemoryManager") << "CheckBuffer detected issue with buffer " << std::to_string(buffer->sequence_id) << "!"
00602 << " ID: " << buffer->sem_id << " (" << manager_id_ << "), Flag: " << FlagToString(buffer->sem) << " (" << FlagToString(flags) << "). "
00603 << "ID -1 is okay if desired flag is \"Full\" or \"Empty\"." << TLOG_ENDL;
00604 }
00605
00606 return ret;
00607 }
00608
00609 void artdaq::SharedMemoryManager::touchBuffer_(ShmBuffer* buffer)
00610 {
00611 if (buffer->sem_id != manager_id_) return;
00612 TLOG_TRACE("SharedMemoryManager") << "touchBuffer_: Touching buffer with sequence_id " << std::to_string(buffer->sequence_id) << TLOG_ENDL;
00613 buffer->last_touch_time = TimeUtils::gettimeofday_us();
00614 }
00615
00616 void artdaq::SharedMemoryManager::Detach(bool throwException, std::string category, std::string message)
00617 {
00618 if (IsValid())
00619 {
00620 auto bufs = GetBuffersOwnedByManager();
00621 for (auto buf : bufs)
00622 {
00623 auto shmBuf = getBufferInfo_(buf);
00624 if (shmBuf->sem == BufferSemaphoreFlags::Writing)
00625 {
00626 shmBuf->sem = BufferSemaphoreFlags::Empty;
00627 }
00628 else if (shmBuf->sem == BufferSemaphoreFlags::Reading)
00629 {
00630 shmBuf->sem = BufferSemaphoreFlags::Full;
00631 }
00632 shmBuf->sem_id = -1;
00633 }
00634 }
00635
00636 if (shm_ptr_)
00637 {
00638 shmdt(shm_ptr_);
00639 shm_ptr_ = NULL;
00640 }
00641
00642 if (manager_id_ == 0 && shm_segment_id_ > -1)
00643 {
00644 shmctl(shm_segment_id_, IPC_RMID, NULL);
00645 }
00646
00647 if (category.size() > 0 && message.size() > 0)
00648 {
00649 TLOG_ERROR("SharedMemoryManager") << category << ": " << message << TLOG_ENDL;
00650
00651 if (throwException)
00652 {
00653 throw cet::exception(category) << message;
00654 }
00655 }
00656 }
00657
00658
00659
00660
00661
00662