00001 #define TRACE_NAME "SharedMemoryManager"
00002 #include <cstring>
00003 #include <sys/shm.h>
00004 #include "tracemf.h"
00005 #include "cetlib_except/exception.h"
00006 #include "artdaq-core/Core/SharedMemoryManager.hh"
00007 #include "artdaq-core/Utilities/TraceLock.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() noexcept
00026 {
00027 TLOG(5) << "~SharedMemoryManager called" << TLOG_ENDL;
00028 Detach();
00029 TLOG(5) << "~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(TLVL_DEBUG) << "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(TLVL_DEBUG) << "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(TLVL_DEBUG)
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(TLVL_DEBUG)
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(TLVL_ERROR) << "Owner encountered already-initialized Shared Memory!" << TLOG_ENDL;
00075 exit(-2);
00076 }
00077 TLOG(TLVL_DEBUG) << "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 getBufferInfo_(ii)->last_touch_time = TimeUtils::gettimeofday_us();
00094 }
00095
00096 shm_ptr_->ready_magic = 0xCAFE1111;
00097 }
00098 else
00099 {
00100 TLOG(TLVL_DEBUG) << "Waiting for owner to initalize Shared Memory" << TLOG_ENDL;
00101 while (shm_ptr_->ready_magic != 0xCAFE1111) { usleep(1000); }
00102 TLOG(TLVL_DEBUG) << "Getting ID from Shared Memory" << TLOG_ENDL;
00103 GetNewId();
00104 shm_ptr_->lowest_seq_id_read = 0;
00105 TLOG(TLVL_DEBUG) << "Getting Shared Memory Size parameters" << TLOG_ENDL;
00106 }
00107
00108 TLOG(TLVL_DEBUG) << "Initialization Complete: "
00109 << "key: 0x" << std::hex << shm_key_
00110 << ", manager ID: " << manager_id_
00111 << ", Buffer size: " << std::to_string(shm_ptr_->buffer_size)
00112 << ", Buffer count: " << std::to_string(shm_ptr_->buffer_count) << TLOG_ENDL;
00113 return;
00114 }
00115 else
00116 {
00117 TLOG(TLVL_ERROR) << "Failed to attach to shared memory segment "
00118 << shm_segment_id_ << TLOG_ENDL;
00119 }
00120 }
00121 else
00122 {
00123 TLOG(TLVL_ERROR) << "Failed to connect to shared memory segment"
00124 << ", errno = " << strerror(errno) << ". Please check "
00125 << "if a stale shared memory segment needs to "
00126 << "be cleaned up. (ipcs, ipcrm -m <segId>)" << TLOG_ENDL;
00127 }
00128 return;
00129 }
00130
00131 int artdaq::SharedMemoryManager::GetBufferForReading()
00132 {
00133 TLOG(13) << "GetBufferForReading BEGIN" << TLOG_ENDL;
00134
00135
00136 TraceLock lk(search_mutex_, 11, "GetBufferForReadingSearch");
00137 auto rp = shm_ptr_->reader_pos.load();
00138
00139 TLOG(13) << "GetBufferForReading lock acquired, scanning buffers" << TLOG_ENDL;
00140 bool retry = true;
00141 int buffer_num = -1;
00142 while (retry)
00143 {
00144 ShmBuffer* buffer_ptr = nullptr;
00145 uint64_t seqID = -1;
00146 for (auto ii = 0; ii < shm_ptr_->buffer_count; ++ii)
00147 {
00148 auto buffer = (ii + rp) % shm_ptr_->buffer_count;
00149
00150
00151 TLOG(14) << "GetBufferForReading Checking if buffer " << buffer << " is stale" << TLOG_ENDL;
00152 ResetBuffer(buffer);
00153
00154 auto buf = getBufferInfo_(buffer);
00155 TLOG(14) << "GetBufferForReading: Buffer " << buffer << ": sem=" << FlagToString(buf->sem) << " (expected " << FlagToString(BufferSemaphoreFlags::Full) << "), sem_id=" << buf->sem_id << " )" << TLOG_ENDL;
00156 if (buf->sem == BufferSemaphoreFlags::Full && (buf->sem_id == -1 || buf->sem_id == manager_id_) && buf->sequence_id > last_seen_id_)
00157 {
00158 if (buf->sequence_id < seqID)
00159 {
00160 buffer_ptr = buf;
00161 seqID = buf->sequence_id;
00162 buffer_num = buffer;
00163 }
00164 }
00165 }
00166
00167 if (!buffer_ptr || (buffer_ptr && buffer_ptr->sem_id != -1 && buffer_ptr->sem_id != manager_id_))
00168 {
00169 continue;
00170 }
00171
00172 if (buffer_num >= 0)
00173 {
00174 TLOG(13) << "GetBufferForReading Found buffer " << buffer_num << TLOG_ENDL;
00175 buffer_ptr->sem_id = manager_id_;
00176 buffer_ptr->sem = BufferSemaphoreFlags::Reading;
00177 if (buffer_ptr->sem_id != manager_id_) { continue; }
00178 buffer_ptr->readPos = 0;
00179 touchBuffer_(buffer_ptr);
00180 if (buffer_ptr->sem_id != manager_id_) { continue; }
00181 if (shm_ptr_->destructive_read_mode && shm_ptr_->lowest_seq_id_read == last_seen_id_)
00182 {
00183 shm_ptr_->lowest_seq_id_read = seqID;
00184 }
00185 last_seen_id_ = seqID;
00186 if (shm_ptr_->destructive_read_mode) shm_ptr_->reader_pos = (buffer_num + 1) % shm_ptr_->buffer_count;
00187 }
00188 retry = false;
00189 }
00190
00191 TLOG(13) << "GetBufferForReading returning -1 because no buffers are ready" << TLOG_ENDL;
00192 return buffer_num;
00193 }
00194
00195 int artdaq::SharedMemoryManager::GetBufferForWriting(bool overwrite)
00196 {
00197 TLOG(14) << "GetBufferForWriting BEGIN" << TLOG_ENDL;
00198
00199 TraceLock lk(search_mutex_, 12, "GetBufferForWritingSearch");
00200 auto wp = shm_ptr_->writer_pos.load();
00201
00202
00203 for (auto ii = 0; ii < shm_ptr_->buffer_count; ++ii)
00204 {
00205 auto buffer = (ii + wp) % shm_ptr_->buffer_count;
00206
00207 ResetBuffer(buffer);
00208
00209 auto buf = getBufferInfo_(buffer);
00210 if (buf->sem == BufferSemaphoreFlags::Empty)
00211 {
00212 buf->sem_id = manager_id_;
00213 buf->sem = BufferSemaphoreFlags::Writing;
00214 if (buf->sem_id != manager_id_) continue;
00215 buf->sequence_id = ++shm_ptr_->next_sequence_id;
00216 buf->writePos = 0;
00217 shm_ptr_->writer_pos = (buffer + 1) % shm_ptr_->buffer_count;
00218 touchBuffer_(buf);
00219 TLOG(14) << "GetBufferForWriting returning " << buffer << TLOG_ENDL;
00220 return buffer;
00221 }
00222 }
00223
00224 if (overwrite)
00225 {
00226
00227 for (auto ii = 0; ii < shm_ptr_->buffer_count; ++ii)
00228 {
00229 auto buffer = (ii + wp) % shm_ptr_->buffer_count;
00230
00231 ResetBuffer(buffer);
00232
00233 auto buf = getBufferInfo_(buffer);
00234 if (buf->sem == BufferSemaphoreFlags::Full)
00235 {
00236 buf->sem_id = manager_id_;
00237 buf->sem = BufferSemaphoreFlags::Writing;
00238 if (buf->sem_id != manager_id_) continue;
00239 buf->sequence_id = ++shm_ptr_->next_sequence_id;
00240 buf->writePos = 0;
00241 shm_ptr_->writer_pos = (buffer + 1) % shm_ptr_->buffer_count;
00242 touchBuffer_(buf);
00243 TLOG(14) << "GetBufferForWriting returning " << buffer << TLOG_ENDL;
00244 return buffer;
00245 }
00246 }
00247
00248
00249 for (auto ii = 0; ii < shm_ptr_->buffer_count; ++ii)
00250 {
00251 auto buffer = (ii + wp) % shm_ptr_->buffer_count;
00252
00253 ResetBuffer(buffer);
00254
00255 auto buf = getBufferInfo_(buffer);
00256 if (buf->sem == BufferSemaphoreFlags::Reading)
00257 {
00258 buf->sem_id = manager_id_;
00259 buf->sem = BufferSemaphoreFlags::Writing;
00260 if (buf->sem_id != manager_id_) continue;
00261 buf->sequence_id = ++shm_ptr_->next_sequence_id;
00262 buf->writePos = 0;
00263 shm_ptr_->writer_pos = (buffer + 1) % shm_ptr_->buffer_count;
00264 TLOG(14) << "GetBufferForWriting returning " << buffer << TLOG_ENDL;
00265 touchBuffer_(buf);
00266 return buffer;
00267 }
00268 }
00269 }
00270
00271 TLOG(14) << "GetBufferForWriting Returning -1 because no buffers are ready" << TLOG_ENDL;
00272 return -1;
00273 }
00274
00275 size_t artdaq::SharedMemoryManager::ReadReadyCount()
00276 {
00277 if (!IsValid()) return 0;
00278 TLOG(23) << "ReadReadyCount BEGIN" << TLOG_ENDL;
00279
00280 TraceLock lk(search_mutex_, 14, "ReadReadyCountSearch");
00281 size_t count = 0;
00282 for (auto ii = 0; ii < shm_ptr_->buffer_count; ++ii)
00283 {
00284 TLOG(24) << "ReadReadyCount: Checking if buffer " << ii << " is stale." << TLOG_ENDL;
00285 ResetBuffer(ii);
00286 auto buf = getBufferInfo_(ii);
00287 TLOG(24) << "ReadReadyCount: Buffer " << ii << ": sem=" << FlagToString(buf->sem) << " (expected " << FlagToString(BufferSemaphoreFlags::Full) << "), sem_id=" << buf->sem_id << " )" << TLOG_ENDL;
00288 if (buf->sem == BufferSemaphoreFlags::Full && (buf->sem_id == -1 || buf->sem_id == manager_id_) && buf->sequence_id > last_seen_id_)
00289 {
00290 TLOG(24) << "ReadReadyCount: Buffer " << ii << " is either unowned or owned by this manager, and is marked full." << TLOG_ENDL;
00291 ++count;
00292 }
00293 }
00294
00295 TLOG(23) << TLOG_ENDL;
00296 return count;
00297 }
00298
00299 size_t artdaq::SharedMemoryManager::WriteReadyCount(bool overwrite)
00300 {
00301 if (!IsValid()) return 0;
00302
00303 TraceLock lk(search_mutex_, 15, "WriteReadyCountSearch");
00304 size_t count = 0;
00305 for (auto ii = 0; ii < shm_ptr_->buffer_count; ++ii)
00306 {
00307 ResetBuffer(ii);
00308 auto buf = getBufferInfo_(ii);
00309 if ((buf->sem == BufferSemaphoreFlags::Empty && buf->sem_id == -1)
00310 || (overwrite && buf->sem != BufferSemaphoreFlags::Writing))
00311 {
00312 ++count;
00313 }
00314 }
00315 return count;
00316 }
00317
00318 std::deque<int> artdaq::SharedMemoryManager::GetBuffersOwnedByManager()
00319 {
00320
00321 std::deque<int> output;
00322 if (!IsValid()) return output;
00323 TraceLock lk(search_mutex_, 16, "GetOwnedSearch");
00324 for (auto ii = 0; ii < shm_ptr_->buffer_count; ++ii)
00325 {
00326 auto buf = getBufferInfo_(ii);
00327 if (buf->sem_id == manager_id_)
00328 {
00329 output.push_back(ii);
00330 }
00331 }
00332
00333 return output;
00334 }
00335
00336 size_t artdaq::SharedMemoryManager::BufferDataSize(int buffer)
00337 {
00338
00339 TraceLock lk(buffer_mutexes_[buffer], 17, "DataSizeBuffer" + std::to_string(buffer));
00340 auto buf = getBufferInfo_(buffer);
00341 touchBuffer_(buf);
00342 return buf->writePos;
00343 }
00344
00345
00346 void artdaq::SharedMemoryManager::ResetReadPos(int buffer)
00347 {
00348
00349 TraceLock lk(buffer_mutexes_[buffer], 18, "ResetReadPosBuffer" + std::to_string(buffer));
00350 auto buf = getBufferInfo_(buffer);
00351 touchBuffer_(buf);
00352 buf->readPos = 0;
00353 }
00354
00355 void artdaq::SharedMemoryManager::ResetWritePos(int buffer)
00356 {
00357
00358 TraceLock lk(buffer_mutexes_[buffer], 18, "ResetWritePosBuffer" + std::to_string(buffer));
00359 auto buf = getBufferInfo_(buffer);
00360 checkBuffer_(buf, BufferSemaphoreFlags::Writing);
00361 touchBuffer_(buf);
00362 buf->writePos = 0;
00363 }
00364
00365 void artdaq::SharedMemoryManager::IncrementReadPos(int buffer, size_t read)
00366 {
00367
00368 TraceLock lk(buffer_mutexes_[buffer], 19, "IncReadPosBuffer" + std::to_string(buffer));
00369 auto buf = getBufferInfo_(buffer);
00370 touchBuffer_(buf);
00371 TLOG(15) << "IncrementReadPos: buffer= " << buffer << ", readPos=" << std::to_string(buf->readPos) << ", bytes read=" << std::to_string(read) << TLOG_ENDL;
00372 buf->readPos = buf->readPos + read;
00373 TLOG(15) << "IncrementReadPos: buffer= " << buffer << ", New readPos is " << std::to_string(buf->readPos) << TLOG_ENDL;
00374 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) + ")");
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(16) << "IncrementWritePos: buffer= " << buffer << ", writePos=" << std::to_string(buf->writePos) << ", bytes written=" << std::to_string(written) << TLOG_ENDL;
00384 buf->writePos += written;
00385 TLOG(16) << "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(17) << "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(18) << "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(18) << "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(18) << "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(18) << "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 size_t delta = TimeUtils::gettimeofday_us() - shmBuf->last_touch_time;
00466 if (delta > 0xFFFFFFFF) {
00467 TLOG(TLVL_TRACE) << "Buffer has touch time in the future, setting it to current time and ignoring..." << TLOG_ENDL;
00468 shmBuf->last_touch_time = TimeUtils::gettimeofday_us();
00469 return false;
00470 }
00471 if (delta <= shm_ptr_->buffer_timeout_us || shmBuf->sem == BufferSemaphoreFlags::Empty) return false;
00472 TLOG(TLVL_TRACE) << "Buffer " << buffer << " is stale, time=" << TimeUtils::gettimeofday_us() << ", last touch=" << shmBuf->last_touch_time << ", d=" << delta << ", timeout=" << shm_ptr_->buffer_timeout_us << TLOG_ENDL;
00473
00474 if (shmBuf->sem_id == manager_id_ && shmBuf->sem == BufferSemaphoreFlags::Writing)
00475 {
00476 return true;
00477 }
00478 if (!shm_ptr_->destructive_read_mode && shmBuf->sem == BufferSemaphoreFlags::Full)
00479 {
00480 TLOG(TLVL_DEBUG) << "Resetting old broadcast mode buffer" << TLOG_ENDL;
00481 shmBuf->writePos = 0;
00482 shmBuf->sem = BufferSemaphoreFlags::Empty;
00483 shmBuf->sem_id = -1;
00484 if (shm_ptr_->reader_pos == static_cast<unsigned>(buffer)) shm_ptr_->reader_pos = (buffer + 1) % shm_ptr_->buffer_count;
00485 return true;
00486 }
00487
00488 if (shmBuf->sem_id != manager_id_ && shmBuf->sem == BufferSemaphoreFlags::Reading)
00489 {
00490 TLOG(TLVL_WARNING) << "Stale Read buffer ( " << delta << " / " << shm_ptr_->buffer_timeout_us << " us ) detected! Resetting..." << TLOG_ENDL;
00491 shmBuf->readPos = 0;
00492 shmBuf->sem = BufferSemaphoreFlags::Full;
00493 shmBuf->sem_id = -1;
00494 return true;
00495 }
00496 return false;
00497 }
00498
00499 size_t artdaq::SharedMemoryManager::Write(int buffer, void* data, size_t size)
00500 {
00501 TLOG(19) << "Write BEGIN" << TLOG_ENDL;
00502
00503 TraceLock lk(buffer_mutexes_[buffer], 26, "WriteBuffer" + std::to_string(buffer));
00504 auto shmBuf = getBufferInfo_(buffer);
00505 checkBuffer_(shmBuf, BufferSemaphoreFlags::Writing);
00506 touchBuffer_(shmBuf);
00507 TLOG(19) << "Buffer Write Pos is " << std::to_string(shmBuf->writePos) << ", write size is " << std::to_string(size) << TLOG_ENDL;
00508 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!");
00509
00510 auto pos = GetWritePos(buffer);
00511 memcpy(pos, data, size);
00512 shmBuf->writePos = shmBuf->writePos + size;
00513 if (shmBuf->sequence_id > last_seen_id_)
00514 {
00515 last_seen_id_ = shmBuf->sequence_id;
00516 }
00517 TLOG(19) << "Write END" << TLOG_ENDL;
00518 return size;
00519 }
00520
00521 bool artdaq::SharedMemoryManager::Read(int buffer, void* data, size_t size)
00522 {
00523
00524 TraceLock lk(buffer_mutexes_[buffer], 27, "ReadBuffer" + std::to_string(buffer));
00525 auto shmBuf = getBufferInfo_(buffer);
00526 checkBuffer_(shmBuf, BufferSemaphoreFlags::Reading);
00527 touchBuffer_(shmBuf);
00528 if (shmBuf->readPos + size > shm_ptr_->buffer_size) Detach(true, "SharedMemoryRead", "Attempted to read more data than exists in Shared Memory!");
00529
00530 auto pos = GetReadPos(buffer);
00531 memcpy(data, pos, size);
00532 shmBuf->readPos += size;
00533 touchBuffer_(shmBuf);
00534 return checkBuffer_(shmBuf, BufferSemaphoreFlags::Reading, false);
00535 }
00536
00537 std::string artdaq::SharedMemoryManager::toString()
00538 {
00539 std::ostringstream ostr;
00540 ostr << "ShmStruct: " << std::endl
00541 << "Reader Position: " << shm_ptr_->reader_pos << std::endl
00542 << "Writer Position: " << shm_ptr_->writer_pos << std::endl
00543 << "Next ID Number: " << shm_ptr_->next_id << std::endl
00544 << "Buffer Count: " << shm_ptr_->buffer_count << std::endl
00545 << "Buffer Size: " << std::to_string(shm_ptr_->buffer_size) << " bytes" << std::endl
00546 << "Buffers Written: " << std::to_string(shm_ptr_->next_sequence_id) << std::endl
00547 << "Rank of Writer: " << shm_ptr_->rank << std::endl
00548 << "Ready Magic Bytes: 0x" << std::hex << shm_ptr_->ready_magic << std::endl << std::endl;
00549
00550 for (auto ii = 0; ii < shm_ptr_->buffer_count; ++ii)
00551 {
00552 auto buf = getBufferInfo_(ii);
00553 ostr << "ShmBuffer " << std::dec << ii << std::endl
00554 << "sequenceID: " << std::to_string(buf->sequence_id) << std::endl
00555 << "writePos: " << std::to_string(buf->writePos) << std::endl
00556 << "readPos: " << std::to_string(buf->readPos) << std::endl
00557 << "sem: " << FlagToString(buf->sem) << std::endl
00558 << "Owner: " << std::to_string(buf->sem_id.load()) << std::endl
00559 << "Last Touch Time: " << std::to_string(buf->last_touch_time / 1000000.0) << std::endl << std::endl;
00560 }
00561
00562 return ostr.str();
00563 }
00564
00565 void* artdaq::SharedMemoryManager::GetReadPos(int buffer)
00566 {
00567 auto buf = getBufferInfo_(buffer);
00568 return bufferStart_(buffer) + buf->readPos;
00569 }
00570 void* artdaq::SharedMemoryManager::GetWritePos(int buffer)
00571 {
00572 auto buf = getBufferInfo_(buffer);
00573 return bufferStart_(buffer) + buf->writePos;
00574 }
00575
00576 void* artdaq::SharedMemoryManager::GetBufferStart(int buffer)
00577 {
00578 return bufferStart_(buffer);
00579 }
00580
00581 uint8_t* artdaq::SharedMemoryManager::dataStart_() const
00582 {
00583 return reinterpret_cast<uint8_t*>(shm_ptr_ + 1) + shm_ptr_->buffer_count * sizeof(ShmBuffer);
00584 }
00585
00586 uint8_t* artdaq::SharedMemoryManager::bufferStart_(int buffer)
00587 {
00588 if (buffer >= shm_ptr_->buffer_count) Detach(true, "ArgumentOutOfRange", "The specified buffer does not exist!");
00589 return dataStart_() + buffer * shm_ptr_->buffer_size;
00590 }
00591
00592 artdaq::SharedMemoryManager::ShmBuffer* artdaq::SharedMemoryManager::getBufferInfo_(int buffer)
00593 {
00594 if (buffer >= shm_ptr_->buffer_count) Detach(true, "ArgumentOutOfRange", "The specified buffer does not exist!");
00595 return reinterpret_cast<ShmBuffer*>(reinterpret_cast<uint8_t*>(shm_ptr_ + 1) + buffer * sizeof(ShmBuffer));
00596 }
00597
00598 bool artdaq::SharedMemoryManager::checkBuffer_(ShmBuffer* buffer, BufferSemaphoreFlags flags, bool exceptions)
00599 {
00600 if (exceptions)
00601 {
00602 if (buffer->sem != flags) Detach(true, "StateAccessViolation", "Shared Memory buffer is not in the correct state! (expected " + FlagToString(flags) + ", actual " + FlagToString(buffer->sem) + ")");
00603 if (buffer->sem_id != manager_id_) Detach(true, "OwnerAccessViolation", "Shared Memory buffer is not owned by this manager instance!");
00604 }
00605 bool ret = (buffer->sem_id == manager_id_ || (buffer->sem_id == -1 && (flags == BufferSemaphoreFlags::Full || flags == BufferSemaphoreFlags::Empty))) && buffer->sem == flags;
00606
00607 if (!ret)
00608 {
00609 TLOG(TLVL_WARNING) << "CheckBuffer detected issue with buffer " << std::to_string(buffer->sequence_id) << "!"
00610 << " ID: " << buffer->sem_id << " (" << manager_id_ << "), Flag: " << FlagToString(buffer->sem) << " (" << FlagToString(flags) << "). "
00611 << "ID -1 is okay if desired flag is \"Full\" or \"Empty\"." << TLOG_ENDL;
00612 }
00613
00614 return ret;
00615 }
00616
00617 void artdaq::SharedMemoryManager::touchBuffer_(ShmBuffer* buffer)
00618 {
00619 if (buffer->sem_id != manager_id_) return;
00620 TLOG(TLVL_TRACE) << "touchBuffer_: Touching buffer with sequence_id " << std::to_string(buffer->sequence_id) << TLOG_ENDL;
00621 buffer->last_touch_time = TimeUtils::gettimeofday_us();
00622 }
00623
00624 void artdaq::SharedMemoryManager::Detach(bool throwException, std::string category, std::string message)
00625 {
00626 if (IsValid())
00627 {
00628 auto bufs = GetBuffersOwnedByManager();
00629 for (auto buf : bufs)
00630 {
00631 auto shmBuf = getBufferInfo_(buf);
00632 if (shmBuf->sem == BufferSemaphoreFlags::Writing)
00633 {
00634 shmBuf->sem = BufferSemaphoreFlags::Empty;
00635 }
00636 else if (shmBuf->sem == BufferSemaphoreFlags::Reading)
00637 {
00638 shmBuf->sem = BufferSemaphoreFlags::Full;
00639 }
00640 shmBuf->sem_id = -1;
00641 }
00642 }
00643
00644 if (shm_ptr_)
00645 {
00646 shmdt(shm_ptr_);
00647 shm_ptr_ = NULL;
00648 }
00649
00650 if (manager_id_ == 0 && shm_segment_id_ > -1)
00651 {
00652 shmctl(shm_segment_id_, IPC_RMID, NULL);
00653 }
00654
00655 if (category.size() > 0 && message.size() > 0)
00656 {
00657 TLOG(TLVL_ERROR) << category << ": " << message << TLOG_ENDL;
00658
00659 if (throwException)
00660 {
00661 throw cet::exception(category) << message;
00662 }
00663 }
00664 }
00665
00666
00667
00668
00669
00670