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