$treeview $search $mathjax $extrastylesheet
artdaq_core
v3_06_01
$projectbrief
|
$projectbrief
|
$searchbox |
00001 #define TRACE_NAME "SharedMemoryManager" 00002 #include <sys/ipc.h> 00003 #include <sys/shm.h> 00004 #include <cstring> 00005 #include <list> 00006 #include <unordered_map> 00007 #ifndef SHM_DEST // Lynn reports that this is missing on Mac OS X?!? 00008 #define SHM_DEST 01000 00009 #endif 00010 #include <csignal> 00011 #include "artdaq-core/Core/SharedMemoryManager.hh" 00012 #include "artdaq-core/Utilities/TraceLock.hh" 00013 #include "cetlib_except/exception.h" 00014 #include "tracemf.h" 00015 00016 #define TLVL_DETACH 11 00017 #define TLVL_BUFFER 40 00018 #define TLVL_BUFLCK 41 00019 00020 static std::list<artdaq::SharedMemoryManager const*> instances = std::list<artdaq::SharedMemoryManager const*>(); 00021 00022 static std::unordered_map<int, struct sigaction> old_actions = std::unordered_map<int, struct sigaction>(); 00023 static bool sighandler_init = false; 00024 static std::mutex sighandler_mutex; 00025 00026 static void signal_handler(int signum) 00027 { 00028 // Messagefacility may already be gone at this point, TRACE ONLY! 00029 TRACE_STREAMER(TLVL_ERROR, &("SharedMemoryManager")[0], 0, 0, 0) << "A signal of type " << signum << " was caught by SharedMemoryManager. Detaching all Shared Memory segments, then proceeding with default handlers!"; 00030 for (auto ii : instances) 00031 { 00032 if (ii != nullptr) 00033 { 00034 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast) 00035 const_cast<artdaq::SharedMemoryManager*>(ii)->Detach(false, "", "", false /* don't force destruct segment, allows reconnection (applicable for 00036 restart and/or multiple art processes (i.e. dispatcher)) */ 00037 ); 00038 } 00039 ii = nullptr; 00040 } 00041 00042 sigset_t set; 00043 pthread_sigmask(SIG_UNBLOCK, nullptr, &set); 00044 pthread_sigmask(SIG_UNBLOCK, &set, nullptr); 00045 00046 TRACE_STREAMER(TLVL_ERROR, &("SharedMemoryManager")[0], 0, 0, 0) << "Calling default signal handler"; 00047 if (signum != SIGUSR2) 00048 { 00049 sigaction(signum, &old_actions[signum], nullptr); 00050 kill(getpid(), signum); // Only send signal to self 00051 } 00052 else 00053 { 00054 // Send Interrupt signal if parsing SIGUSR2 (i.e. user-defined exception that should tear down ARTDAQ) 00055 sigaction(SIGINT, &old_actions[SIGINT], nullptr); 00056 kill(getpid(), SIGINT); // Only send signal to self 00057 } 00058 } 00059 00060 artdaq::SharedMemoryManager::SharedMemoryManager(uint32_t shm_key, size_t buffer_count, size_t buffer_size, uint64_t buffer_timeout_us, bool destructive_read_mode) 00061 : shm_segment_id_(-1) 00062 , shm_ptr_(nullptr) 00063 , shm_key_(shm_key) 00064 , manager_id_(-1) 00065 , last_seen_id_(0) 00066 { 00067 requested_shm_parameters_.buffer_count = buffer_count; 00068 requested_shm_parameters_.buffer_size = buffer_size; 00069 requested_shm_parameters_.buffer_timeout_us = buffer_timeout_us; 00070 requested_shm_parameters_.destructive_read_mode = destructive_read_mode; 00071 00072 instances.push_back(this); 00073 Attach(); 00074 00075 std::lock_guard<std::mutex> lk(sighandler_mutex); 00076 00077 if (!sighandler_init) //&& manager_id_ == 0) // ELF 3/22/18: Taking out manager_id_==0 requirement as I think kill(getpid()) is enough protection 00078 { 00079 sighandler_init = true; 00080 std::vector<int> signals = {SIGINT, SIGILL, SIGABRT, SIGFPE, SIGSEGV, SIGPIPE, SIGALRM, SIGTERM, SIGUSR2, SIGHUP}; // SIGQUIT is used by art in normal operation 00081 for (auto signal : signals) 00082 { 00083 struct sigaction old_action; 00084 sigaction(signal, nullptr, &old_action); 00085 00086 //If the old handler wasn't SIG_IGN (it's a handler that just 00087 // "ignore" the signal) 00088 if (old_action.sa_handler != SIG_IGN) // NOLINT(cppcoreguidelines-pro-type-cstyle-cast) 00089 { 00090 struct sigaction action; 00091 action.sa_handler = signal_handler; 00092 sigemptyset(&action.sa_mask); 00093 for (auto sigblk : signals) 00094 { 00095 sigaddset(&action.sa_mask, sigblk); 00096 } 00097 action.sa_flags = 0; 00098 00099 //Replace the signal handler of SIGINT with the one described by new_action 00100 sigaction(signal, &action, nullptr); 00101 } 00102 old_actions[signal] = old_action; 00103 } 00104 } 00105 } 00106 00107 // The clang-tidy warning comes from Detach, which can throw an exception if called with first parameter = true (defaults to false) 00108 artdaq::SharedMemoryManager::~SharedMemoryManager() noexcept // NOLINT(bugprone-exception-escape) 00109 { 00110 TLOG(TLVL_DEBUG) << "~SharedMemoryManager called"; 00111 { 00112 static std::mutex destructor_mutex; 00113 std::lock_guard<std::mutex> lk(destructor_mutex); 00114 for (auto it = instances.begin(); it != instances.end(); ++it) 00115 { 00116 if (*it == this) 00117 { 00118 it = instances.erase(it); 00119 break; 00120 } 00121 } 00122 } 00123 Detach(); 00124 { 00125 std::lock_guard<std::mutex> lk(sighandler_mutex); 00126 00127 // Restore signal handlers 00128 if (sighandler_init && instances.empty()) 00129 { 00130 sighandler_init = false; 00131 for (auto signal : old_actions) 00132 { 00133 sigaction(signal.first, &signal.second, nullptr); 00134 } 00135 old_actions.clear(); 00136 } 00137 } 00138 TLOG(TLVL_DEBUG) << "~SharedMemoryManager done"; 00139 } 00140 00141 bool artdaq::SharedMemoryManager::Attach(size_t timeout_usec) 00142 { 00143 if (IsValid()) 00144 { 00145 if (manager_id_ == 0) 00146 { 00147 return true; 00148 } 00149 Detach(); 00150 } 00151 00152 size_t timeout_us = timeout_usec > 0 ? timeout_usec : 1000000; 00153 auto start_time = std::chrono::steady_clock::now(); 00154 last_seen_id_ = 0; 00155 size_t shmSize = requested_shm_parameters_.buffer_count * (requested_shm_parameters_.buffer_size + sizeof(ShmBuffer)) + sizeof(ShmStruct); 00156 00157 // 19-Feb-2019, KAB: separating out the determination of whether a given process owns the shared 00158 // memory (indicated by manager_id_ == 0) and whether or not the shared memory already exists. 00159 if (requested_shm_parameters_.buffer_count > 0 && requested_shm_parameters_.buffer_size > 0 && manager_id_ <= 0) 00160 { 00161 manager_id_ = 0; 00162 } 00163 00164 shm_segment_id_ = shmget(shm_key_, shmSize, 0666); 00165 if (shm_segment_id_ == -1) 00166 { 00167 if (manager_id_ == 0) 00168 { 00169 TLOG(TLVL_DEBUG) << "Creating shared memory segment with key 0x" << std::hex << shm_key_ << " and size " << std::dec << shmSize; 00170 shm_segment_id_ = shmget(shm_key_, shmSize, IPC_CREAT | 0666); 00171 00172 if (shm_segment_id_ == -1) 00173 { 00174 TLOG(TLVL_ERROR) << "Error creating shared memory segment with key 0x" << std::hex << shm_key_ << ", errno=" << std::dec << errno << " (" << strerror(errno) << ")"; 00175 } 00176 } 00177 else 00178 { 00179 while (shm_segment_id_ == -1 && TimeUtils::GetElapsedTimeMicroseconds(start_time) < timeout_us) 00180 { 00181 shm_segment_id_ = shmget(shm_key_, shmSize, 0666); 00182 } 00183 } 00184 } 00185 TLOG(TLVL_DEBUG) << "shm_key == 0x" << std::hex << shm_key_ << ", shm_segment_id == " << std::dec << shm_segment_id_; 00186 00187 if (shm_segment_id_ > -1) 00188 { 00189 TLOG(TLVL_DEBUG) 00190 << "Attached to shared memory segment with ID = " << shm_segment_id_ 00191 << " and size " << shmSize 00192 << " bytes"; 00193 shm_ptr_ = static_cast<ShmStruct*>(shmat(shm_segment_id_, nullptr, 0)); 00194 TLOG(TLVL_DEBUG) 00195 << "Attached to shared memory segment at address " 00196 << std::hex << static_cast<void*>(shm_ptr_) << std::dec; 00197 if ((shm_ptr_ != nullptr) && shm_ptr_ != reinterpret_cast<void*>(-1)) // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast) 00198 { 00199 if (manager_id_ == 0) 00200 { 00201 if (shm_ptr_->ready_magic == 0xCAFE1111) 00202 { 00203 TLOG(TLVL_WARNING) << "Owner encountered already-initialized Shared Memory! " 00204 << "Once the system is shut down, you can use one of the following commands " 00205 << "to clean up this shared memory: 'ipcrm -M 0x" << std::hex << shm_key_ 00206 << "' or 'ipcrm -m " << std::dec << shm_segment_id_ << "'."; 00207 //exit(-2); 00208 } 00209 TLOG(TLVL_DEBUG) << "Owner initializing Shared Memory"; 00210 shm_ptr_->next_id = 1; 00211 shm_ptr_->next_sequence_id = 0; 00212 shm_ptr_->reader_pos = 0; 00213 shm_ptr_->writer_pos = 0; 00214 shm_ptr_->buffer_size = requested_shm_parameters_.buffer_size; 00215 shm_ptr_->buffer_count = requested_shm_parameters_.buffer_count; 00216 shm_ptr_->buffer_timeout_us = requested_shm_parameters_.buffer_timeout_us; 00217 shm_ptr_->destructive_read_mode = requested_shm_parameters_.destructive_read_mode; 00218 00219 buffer_ptrs_ = std::vector<ShmBuffer*>(shm_ptr_->buffer_count); 00220 for (int ii = 0; ii < static_cast<int>(requested_shm_parameters_.buffer_count); ++ii) 00221 { 00222 buffer_ptrs_[ii] = reinterpret_cast<ShmBuffer*>(reinterpret_cast<uint8_t*>(shm_ptr_ + 1) + ii * sizeof(ShmBuffer)); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast,cppcoreguidelines-pro-bounds-pointer-arithmetic) 00223 if (getBufferInfo_(ii) == nullptr) 00224 { 00225 return false; 00226 } 00227 getBufferInfo_(ii)->writePos = 0; 00228 getBufferInfo_(ii)->readPos = 0; 00229 getBufferInfo_(ii)->sem = BufferSemaphoreFlags::Empty; 00230 getBufferInfo_(ii)->sem_id = -1; 00231 getBufferInfo_(ii)->last_touch_time = TimeUtils::gettimeofday_us(); 00232 } 00233 00234 shm_ptr_->ready_magic = 0xCAFE1111; 00235 } 00236 else 00237 { 00238 TLOG(TLVL_DEBUG) << "Waiting for owner to initalize Shared Memory"; 00239 while (shm_ptr_->ready_magic != 0xCAFE1111) { usleep(1000); } 00240 TLOG(TLVL_DEBUG) << "Getting ID from Shared Memory"; 00241 GetNewId(); 00242 shm_ptr_->lowest_seq_id_read = 0; 00243 TLOG(TLVL_DEBUG) << "Getting Shared Memory Size parameters"; 00244 00245 requested_shm_parameters_.buffer_count = shm_ptr_->buffer_count; 00246 buffer_ptrs_ = std::vector<ShmBuffer*>(shm_ptr_->buffer_count); 00247 for (int ii = 0; ii < shm_ptr_->buffer_count; ++ii) 00248 { 00249 buffer_ptrs_[ii] = reinterpret_cast<ShmBuffer*>(reinterpret_cast<uint8_t*>(shm_ptr_ + 1) + ii * sizeof(ShmBuffer)); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast,cppcoreguidelines-pro-bounds-pointer-arithmetic) 00250 } 00251 } 00252 00253 //last_seen_id_ = shm_ptr_->next_sequence_id; 00254 buffer_mutexes_ = std::vector<std::mutex>(shm_ptr_->buffer_count); 00255 00256 TLOG(TLVL_DEBUG) << "Initialization Complete: " 00257 << "key: 0x" << std::hex << shm_key_ 00258 << ", manager ID: " << std::dec << manager_id_ 00259 << ", Buffer size: " << shm_ptr_->buffer_size 00260 << ", Buffer count: " << shm_ptr_->buffer_count; 00261 return true; 00262 } 00263 00264 TLOG(TLVL_ERROR) << "Failed to attach to shared memory segment " 00265 << shm_segment_id_; 00266 return false; 00267 } 00268 00269 TLOG(TLVL_ERROR) << "Failed to connect to shared memory segment with key 0x" << std::hex << shm_key_ 00270 << ", errno=" << std::dec << errno << " (" << strerror(errno) << ")" 00271 << ". Please check " 00272 << "if a stale shared memory segment needs to " 00273 << "be cleaned up. (ipcs, ipcrm -m <segId>)"; 00274 return false; 00275 } 00276 00277 int artdaq::SharedMemoryManager::GetBufferForReading() 00278 { 00279 TLOG(13) << "GetBufferForReading BEGIN"; 00280 00281 std::lock_guard<std::mutex> lk(search_mutex_); 00282 //TraceLock lk(search_mutex_, 11, "GetBufferForReadingSearch"); 00283 auto rp = shm_ptr_->reader_pos.load(); 00284 00285 TLOG(13) << "GetBufferForReading lock acquired, scanning " << shm_ptr_->buffer_count << " buffers"; 00286 00287 for (int retry = 0; retry < 5; retry++) 00288 { 00289 BufferSemaphoreFlags sem; 00290 int16_t sem_id; 00291 int buffer_num = -1; 00292 ShmBuffer* buffer_ptr = nullptr; 00293 uint64_t seqID = -1; 00294 00295 for (auto ii = 0; ii < shm_ptr_->buffer_count; ++ii) 00296 { 00297 auto buffer = (ii + rp) % shm_ptr_->buffer_count; 00298 00299 TLOG(14) << "GetBufferForReading Checking if buffer " << buffer << " is stale. Shm destructive_read_mode=" << shm_ptr_->destructive_read_mode; 00300 ResetBuffer(buffer); 00301 00302 auto buf = getBufferInfo_(buffer); 00303 if (buf == nullptr) 00304 { 00305 continue; 00306 } 00307 00308 sem = buf->sem.load(); 00309 sem_id = buf->sem_id.load(); 00310 00311 TLOG(14) << "GetBufferForReading: Buffer " << buffer << ": sem=" << FlagToString(sem) 00312 << " (expected " << FlagToString(BufferSemaphoreFlags::Full) << "), sem_id=" << sem_id << ", seq_id=" << buf->sequence_id << " )"; 00313 if (sem == BufferSemaphoreFlags::Full && (sem_id == -1 || sem_id == manager_id_) && (shm_ptr_->destructive_read_mode || buf->sequence_id > last_seen_id_)) 00314 { 00315 if (buf->sequence_id < seqID) 00316 { 00317 buffer_ptr = buf; 00318 seqID = buf->sequence_id; 00319 buffer_num = buffer; 00320 touchBuffer_(buf); 00321 if (shm_ptr_->destructive_read_mode || seqID == last_seen_id_ + 1) 00322 { 00323 break; 00324 } 00325 } 00326 } 00327 } 00328 00329 if (buffer_ptr != nullptr) 00330 { 00331 sem = buffer_ptr->sem.load(); 00332 sem_id = buffer_ptr->sem_id.load(); 00333 } 00334 00335 if ((buffer_ptr == nullptr) || (sem_id != -1 && sem_id != manager_id_) || sem != BufferSemaphoreFlags::Full) 00336 { 00337 continue; 00338 } 00339 00340 if (buffer_num >= 0) 00341 { 00342 TLOG(13) << "GetBufferForReading Found buffer " << buffer_num; 00343 touchBuffer_(buffer_ptr); 00344 if (!buffer_ptr->sem_id.compare_exchange_strong(sem_id, manager_id_)) 00345 { 00346 continue; 00347 } 00348 if (!buffer_ptr->sem.compare_exchange_strong(sem, BufferSemaphoreFlags::Reading)) 00349 { 00350 continue; 00351 } 00352 if (!checkBuffer_(buffer_ptr, BufferSemaphoreFlags::Reading, false)) 00353 { 00354 TLOG(13) << "GetBufferForReading: Failed to acquire buffer " << buffer_num << " (someone else changed manager ID while I was changing sem)"; 00355 continue; 00356 } 00357 buffer_ptr->readPos = 0; 00358 touchBuffer_(buffer_ptr); 00359 if (!checkBuffer_(buffer_ptr, BufferSemaphoreFlags::Reading, false)) 00360 { 00361 TLOG(13) << "GetBufferForReading: Failed to acquire buffer " << buffer_num << " (someone else changed manager ID while I was touching buffer SHOULD NOT HAPPEN!)"; 00362 continue; 00363 } 00364 if (shm_ptr_->destructive_read_mode && shm_ptr_->lowest_seq_id_read == last_seen_id_) 00365 { 00366 shm_ptr_->lowest_seq_id_read = seqID; 00367 } 00368 last_seen_id_ = seqID; 00369 if (shm_ptr_->destructive_read_mode) 00370 { 00371 shm_ptr_->reader_pos = (buffer_num + 1) % shm_ptr_->buffer_count; 00372 } 00373 00374 TLOG(13) << "GetBufferForReading returning " << buffer_num; 00375 return buffer_num; 00376 } 00377 retry = 5; 00378 } 00379 00380 TLOG(13) << "GetBufferForReading returning -1 because no buffers are ready"; 00381 return -1; 00382 } 00383 00384 int artdaq::SharedMemoryManager::GetBufferForWriting(bool overwrite) 00385 { 00386 TLOG(14) << "GetBufferForWriting BEGIN, overwrite=" << (overwrite ? "true" : "false"); 00387 00388 std::lock_guard<std::mutex> lk(search_mutex_); 00389 //TraceLock lk(search_mutex_, 12, "GetBufferForWritingSearch"); 00390 auto wp = shm_ptr_->writer_pos.load(); 00391 00392 TLOG(13) << "GetBufferForWriting lock acquired, scanning " << shm_ptr_->buffer_count << " buffers"; 00393 00394 // First, only look for "Empty" buffers 00395 for (auto ii = 0; ii < shm_ptr_->buffer_count; ++ii) 00396 { 00397 auto buffer = (ii + wp) % shm_ptr_->buffer_count; 00398 00399 ResetBuffer(buffer); 00400 00401 auto buf = getBufferInfo_(buffer); 00402 if (buf == nullptr) 00403 { 00404 continue; 00405 } 00406 00407 auto sem = buf->sem.load(); 00408 auto sem_id = buf->sem_id.load(); 00409 00410 if (sem == BufferSemaphoreFlags::Empty && sem_id == -1) 00411 { 00412 touchBuffer_(buf); 00413 if (!buf->sem_id.compare_exchange_strong(sem_id, manager_id_)) 00414 { 00415 continue; 00416 } 00417 if (!buf->sem.compare_exchange_strong(sem, BufferSemaphoreFlags::Writing)) 00418 { 00419 continue; 00420 } 00421 if (!checkBuffer_(buf, BufferSemaphoreFlags::Writing, false)) 00422 { 00423 continue; 00424 } 00425 shm_ptr_->writer_pos = (buffer + 1) % shm_ptr_->buffer_count; 00426 buf->sequence_id = ++shm_ptr_->next_sequence_id; 00427 buf->writePos = 0; 00428 if (!checkBuffer_(buf, BufferSemaphoreFlags::Writing, false)) 00429 { 00430 continue; 00431 } 00432 touchBuffer_(buf); 00433 TLOG(14) << "GetBufferForWriting returning " << buffer; 00434 return buffer; 00435 } 00436 } 00437 00438 if (overwrite) 00439 { 00440 // Then, look for "Full" buffers 00441 for (auto ii = 0; ii < shm_ptr_->buffer_count; ++ii) 00442 { 00443 auto buffer = (ii + wp) % shm_ptr_->buffer_count; 00444 00445 ResetBuffer(buffer); 00446 00447 auto buf = getBufferInfo_(buffer); 00448 if (buf == nullptr) 00449 { 00450 continue; 00451 } 00452 00453 auto sem = buf->sem.load(); 00454 auto sem_id = buf->sem_id.load(); 00455 00456 if (sem == BufferSemaphoreFlags::Full) 00457 { 00458 touchBuffer_(buf); 00459 if (!buf->sem_id.compare_exchange_strong(sem_id, manager_id_)) 00460 { 00461 continue; 00462 } 00463 if (!buf->sem.compare_exchange_strong(sem, BufferSemaphoreFlags::Writing)) 00464 { 00465 continue; 00466 } 00467 if (!checkBuffer_(buf, BufferSemaphoreFlags::Writing, false)) 00468 { 00469 continue; 00470 } 00471 shm_ptr_->writer_pos = (buffer + 1) % shm_ptr_->buffer_count; 00472 buf->sequence_id = ++shm_ptr_->next_sequence_id; 00473 buf->writePos = 0; 00474 if (!checkBuffer_(buf, BufferSemaphoreFlags::Writing, false)) 00475 { 00476 continue; 00477 } 00478 touchBuffer_(buf); 00479 TLOG(14) << "GetBufferForWriting returning " << buffer; 00480 return buffer; 00481 } 00482 } 00483 00484 // Finally, if we still haven't found a buffer, we have to clobber a reader... 00485 for (auto ii = 0; ii < shm_ptr_->buffer_count; ++ii) 00486 { 00487 auto buffer = (ii + wp) % shm_ptr_->buffer_count; 00488 00489 ResetBuffer(buffer); 00490 00491 auto buf = getBufferInfo_(buffer); 00492 if (buf == nullptr) 00493 { 00494 continue; 00495 } 00496 00497 auto sem = buf->sem.load(); 00498 auto sem_id = buf->sem_id.load(); 00499 00500 if (sem == BufferSemaphoreFlags::Reading) 00501 { 00502 touchBuffer_(buf); 00503 if (!buf->sem_id.compare_exchange_strong(sem_id, manager_id_)) 00504 { 00505 continue; 00506 } 00507 if (!buf->sem.compare_exchange_strong(sem, BufferSemaphoreFlags::Writing)) 00508 { 00509 continue; 00510 } 00511 if (!checkBuffer_(buf, BufferSemaphoreFlags::Writing, false)) 00512 { 00513 continue; 00514 } 00515 shm_ptr_->writer_pos = (buffer + 1) % shm_ptr_->buffer_count; 00516 buf->sequence_id = ++shm_ptr_->next_sequence_id; 00517 buf->writePos = 0; 00518 if (!checkBuffer_(buf, BufferSemaphoreFlags::Writing, false)) 00519 { 00520 continue; 00521 } 00522 touchBuffer_(buf); 00523 TLOG(14) << "GetBufferForWriting returning " << buffer; 00524 return buffer; 00525 } 00526 } 00527 } 00528 TLOG(14) << "GetBufferForWriting Returning -1 because no buffers are ready"; 00529 return -1; 00530 } 00531 00532 size_t artdaq::SharedMemoryManager::ReadReadyCount() 00533 { 00534 if (!IsValid()) 00535 { 00536 return 0; 00537 } 00538 TLOG(23) << "0x" << std::hex << shm_key_ << " ReadReadyCount BEGIN" << std::dec; 00539 std::unique_lock<std::mutex> lk(search_mutex_); 00540 TLOG(23) << "ReadReadyCount lock acquired, scanning " << shm_ptr_->buffer_count << " buffers"; 00541 //TraceLock lk(search_mutex_, 14, "ReadReadyCountSearch"); 00542 size_t count = 0; 00543 for (auto ii = 0; ii < shm_ptr_->buffer_count; ++ii) 00544 { 00545 #ifndef __OPTIMIZE__ 00546 TLOG(24) << "0x" << std::hex << shm_key_ << std::dec << " ReadReadyCount: Checking if buffer " << ii << " is stale."; 00547 #endif 00548 ResetBuffer(ii); 00549 auto buf = getBufferInfo_(ii); 00550 if (buf == nullptr) 00551 { 00552 continue; 00553 } 00554 00555 #ifndef __OPTIMIZE__ 00556 TLOG(25) << "0x" << std::hex << shm_key_ << std::dec << " ReadReadyCount: Buffer " << ii << ": sem=" << FlagToString(buf->sem) << " (expected " << FlagToString(BufferSemaphoreFlags::Full) << "), sem_id=" << buf->sem_id << " )"; 00557 #endif 00558 if (buf->sem == BufferSemaphoreFlags::Full && (buf->sem_id == -1 || buf->sem_id == manager_id_) && (shm_ptr_->destructive_read_mode || buf->sequence_id > last_seen_id_)) 00559 { 00560 #ifndef __OPTIMIZE__ 00561 TLOG(26) << "0x" << std::hex << shm_key_ << std::dec << " ReadReadyCount: Buffer " << ii << " is either unowned or owned by this manager, and is marked full."; 00562 #endif 00563 touchBuffer_(buf); 00564 ++count; 00565 } 00566 } 00567 return count; 00568 } 00569 00570 size_t artdaq::SharedMemoryManager::WriteReadyCount(bool overwrite) 00571 { 00572 if (!IsValid()) 00573 { 00574 return 0; 00575 } 00576 TLOG(28) << "0x" << std::hex << shm_key_ << " ReadReadyCount BEGIN" << std::dec; 00577 std::unique_lock<std::mutex> lk(search_mutex_); 00578 //TraceLock lk(search_mutex_, 15, "WriteReadyCountSearch"); 00579 TLOG(28) << "WriteReadyCount(" << overwrite << ") lock acquired, scanning " << shm_ptr_->buffer_count << " buffers"; 00580 size_t count = 0; 00581 for (auto ii = 0; ii < shm_ptr_->buffer_count; ++ii) 00582 { 00583 // ELF, 3/19/2019: This TRACE call is a major performance hit with many buffers 00584 #ifndef __OPTIMIZE__ 00585 TLOG(29) << "0x" << std::hex << shm_key_ << std::dec << " WriteReadyCount: Checking if buffer " << ii << " is stale."; 00586 #endif 00587 ResetBuffer(ii); 00588 auto buf = getBufferInfo_(ii); 00589 if (buf == nullptr) 00590 { 00591 continue; 00592 } 00593 if ((buf->sem == BufferSemaphoreFlags::Empty && buf->sem_id == -1) || (overwrite && buf->sem != BufferSemaphoreFlags::Writing)) 00594 { 00595 #ifndef __OPTIMIZE__ 00596 TLOG(29) << "0x" << std::hex << shm_key_ << std::dec << " WriteReadyCount: Buffer " << ii << " is either empty or is available for overwrite."; 00597 #endif 00598 ++count; 00599 } 00600 } 00601 return count; 00602 } 00603 00604 bool artdaq::SharedMemoryManager::ReadyForRead() 00605 { 00606 if (!IsValid()) 00607 { 00608 return false; 00609 } 00610 TLOG(23) << "0x" << std::hex << shm_key_ << " ReadyForRead BEGIN" << std::dec; 00611 std::unique_lock<std::mutex> lk(search_mutex_); 00612 //TraceLock lk(search_mutex_, 14, "ReadyForReadSearch"); 00613 00614 auto rp = shm_ptr_->reader_pos.load(); 00615 00616 TLOG(23) << "ReadyForRead lock acquired, scanning " << shm_ptr_->buffer_count << " buffers"; 00617 00618 for (auto ii = 0; ii < shm_ptr_->buffer_count; ++ii) 00619 { 00620 auto buffer = (rp + ii) % shm_ptr_->buffer_count; 00621 00622 #ifndef __OPTIMIZE__ 00623 TLOG(24) << "0x" << std::hex << shm_key_ << std::dec << " ReadyForRead: Checking if buffer " << buffer << " is stale."; 00624 #endif 00625 ResetBuffer(buffer); 00626 auto buf = getBufferInfo_(buffer); 00627 if (buf == nullptr) 00628 { 00629 continue; 00630 } 00631 00632 #ifndef __OPTIMIZE__ 00633 TLOG(25) << "0x" << std::hex << shm_key_ << std::dec << " ReadyForRead: Buffer " << buffer << ": sem=" << FlagToString(buf->sem) << " (expected " << FlagToString(BufferSemaphoreFlags::Full) << "), sem_id=" << buf->sem_id << " )" 00634 << " seq_id=" << buf->sequence_id << " >? " << last_seen_id_; 00635 #endif 00636 00637 if (buf->sem == BufferSemaphoreFlags::Full && (buf->sem_id == -1 || buf->sem_id == manager_id_) && (shm_ptr_->destructive_read_mode || buf->sequence_id > last_seen_id_)) 00638 { 00639 TLOG(26) << "0x" << std::hex << shm_key_ << std::dec << " ReadyForRead: Buffer " << buffer << " is either unowned or owned by this manager, and is marked full."; 00640 touchBuffer_(buf); 00641 return true; 00642 } 00643 } 00644 return false; 00645 } 00646 00647 bool artdaq::SharedMemoryManager::ReadyForWrite(bool overwrite) 00648 { 00649 if (!IsValid()) 00650 { 00651 return false; 00652 } 00653 TLOG(28) << "0x" << std::hex << shm_key_ << " ReadyForWrite BEGIN" << std::dec; 00654 00655 std::lock_guard<std::mutex> lk(search_mutex_); 00656 //TraceLock lk(search_mutex_, 15, "ReadyForWriteSearch"); 00657 00658 auto wp = shm_ptr_->writer_pos.load(); 00659 00660 TLOG(28) << "ReadyForWrite lock acquired, scanning " << shm_ptr_->buffer_count << " buffers"; 00661 00662 for (auto ii = 0; ii < shm_ptr_->buffer_count; ++ii) 00663 { 00664 auto buffer = (wp + ii) % shm_ptr_->buffer_count; 00665 TLOG(29) << "0x" << std::hex << shm_key_ << std::dec << " ReadyForWrite: Checking if buffer " << buffer << " is stale."; 00666 ResetBuffer(buffer); 00667 auto buf = getBufferInfo_(buffer); 00668 if (buf == nullptr) 00669 { 00670 continue; 00671 } 00672 if ((buf->sem == BufferSemaphoreFlags::Empty && buf->sem_id == -1) || (overwrite && buf->sem != BufferSemaphoreFlags::Writing)) 00673 { 00674 TLOG(29) << "0x" << std::hex << shm_key_ 00675 << std::dec 00676 << " WriteReadyCount: Buffer " << ii << " is either empty or available for overwrite."; 00677 return true; 00678 } 00679 } 00680 return false; 00681 } 00682 00683 std::deque<int> artdaq::SharedMemoryManager::GetBuffersOwnedByManager(bool locked) 00684 { 00685 std::deque<int> output; 00686 if (!IsValid()) 00687 { 00688 return output; 00689 } 00690 TLOG(TLVL_BUFFER) << "GetBuffersOwnedByManager BEGIN. Locked? " << locked; 00691 if (locked) 00692 { 00693 TLOG(TLVL_BUFLCK) << "GetBuffersOwnedByManager obtaining search_mutex"; 00694 std::lock_guard<std::mutex> lk(search_mutex_); 00695 TLOG(TLVL_BUFLCK) << "GetBuffersOwnedByManager obtained search_mutex"; 00696 //TraceLock lk(search_mutex_, 16, "GetOwnedSearch"); 00697 for (auto ii = 0; ii < shm_ptr_->buffer_count; ++ii) 00698 { 00699 auto buf = getBufferInfo_(ii); 00700 if (buf == nullptr) 00701 { 00702 continue; 00703 } 00704 if (buf->sem_id == manager_id_) 00705 { 00706 output.push_back(ii); 00707 } 00708 } 00709 } 00710 else 00711 { 00712 for (auto ii = 0; ii < shm_ptr_->buffer_count; ++ii) 00713 { 00714 auto buf = getBufferInfo_(ii); 00715 if (buf == nullptr) 00716 { 00717 continue; 00718 } 00719 if (buf->sem_id == manager_id_) 00720 { 00721 output.push_back(ii); 00722 } 00723 } 00724 } 00725 00726 TLOG(TLVL_BUFFER) << "GetBuffersOwnedByManager: own " << output.size() << " / " << shm_ptr_->buffer_count << " buffers."; 00727 return output; 00728 } 00729 00730 size_t artdaq::SharedMemoryManager::BufferDataSize(int buffer) 00731 { 00732 TLOG(TLVL_BUFFER) << "BufferDataSize(" << buffer << ") called."; 00733 00734 if (buffer >= shm_ptr_->buffer_count) 00735 { 00736 Detach(true, "ArgumentOutOfRange", "The specified buffer does not exist!"); 00737 } 00738 00739 TLOG(TLVL_BUFLCK) << "BufferDataSize obtaining buffer_mutex for buffer " << buffer; 00740 std::lock_guard<std::mutex> lk(buffer_mutexes_[buffer]); 00741 TLOG(TLVL_BUFLCK) << "BufferDataSize obtained buffer_mutex for buffer " << buffer; 00742 //TraceLock lk(buffer_mutexes_[buffer], 17, "DataSizeBuffer" + std::to_string(buffer)); 00743 00744 auto buf = getBufferInfo_(buffer); 00745 if (buf == nullptr) 00746 { 00747 return 0; 00748 } 00749 touchBuffer_(buf); 00750 00751 TLOG(TLVL_BUFFER) << "BufferDataSize: buffer " << buffer << ", size=" << buf->writePos; 00752 return buf->writePos; 00753 } 00754 00755 void artdaq::SharedMemoryManager::ResetReadPos(int buffer) 00756 { 00757 TLOG(15) << "ResetReadPos(" << buffer << ") called."; 00758 00759 if (buffer >= shm_ptr_->buffer_count) 00760 { 00761 Detach(true, "ArgumentOutOfRange", "The specified buffer does not exist!"); 00762 } 00763 00764 TLOG(TLVL_BUFLCK) << "ResetReadPos obtaining buffer_mutex for buffer " << buffer; 00765 std::lock_guard<std::mutex> lk(buffer_mutexes_[buffer]); 00766 TLOG(TLVL_BUFLCK) << "ResetReadPos obtained buffer_mutex for buffer " << buffer; 00767 00768 //TraceLock lk(buffer_mutexes_[buffer], 18, "ResetReadPosBuffer" + std::to_string(buffer)); 00769 auto buf = getBufferInfo_(buffer); 00770 if ((buf == nullptr) || buf->sem_id != manager_id_) 00771 { 00772 return; 00773 } 00774 touchBuffer_(buf); 00775 buf->readPos = 0; 00776 00777 TLOG(15) << "ResetReadPos(" << buffer << ") ended."; 00778 } 00779 00780 void artdaq::SharedMemoryManager::ResetWritePos(int buffer) 00781 { 00782 TLOG(16) << "ResetWritePos(" << buffer << ") called."; 00783 00784 if (buffer >= shm_ptr_->buffer_count) 00785 { 00786 Detach(true, "ArgumentOutOfRange", "The specified buffer does not exist!"); 00787 } 00788 00789 TLOG(TLVL_BUFLCK) << "ResetWritePos obtaining buffer_mutex for buffer " << buffer; 00790 std::lock_guard<std::mutex> lk(buffer_mutexes_[buffer]); 00791 TLOG(TLVL_BUFLCK) << "ResetWritePos obtained buffer_mutex for buffer " << buffer; 00792 00793 //TraceLock lk(buffer_mutexes_[buffer], 18, "ResetWritePosBuffer" + std::to_string(buffer)); 00794 auto buf = getBufferInfo_(buffer); 00795 if (buf == nullptr) 00796 { 00797 return; 00798 } 00799 checkBuffer_(buf, BufferSemaphoreFlags::Writing); 00800 touchBuffer_(buf); 00801 buf->writePos = 0; 00802 00803 TLOG(16) << "ResetWritePos(" << buffer << ") ended."; 00804 } 00805 00806 void artdaq::SharedMemoryManager::IncrementReadPos(int buffer, size_t read) 00807 { 00808 TLOG(15) << "IncrementReadPos called: buffer= " << buffer << ", bytes to read=" << read; 00809 00810 if (buffer >= shm_ptr_->buffer_count) 00811 { 00812 Detach(true, "ArgumentOutOfRange", "The specified buffer does not exist!"); 00813 } 00814 00815 TLOG(TLVL_BUFLCK) << "IncrementReadPos obtaining buffer_mutex for buffer " << buffer; 00816 std::lock_guard<std::mutex> lk(buffer_mutexes_[buffer]); 00817 TLOG(TLVL_BUFLCK) << "IncrementReadPos obtained buffer_mutex for buffer " << buffer; 00818 //TraceLock lk(buffer_mutexes_[buffer], 19, "IncReadPosBuffer" + std::to_string(buffer)); 00819 auto buf = getBufferInfo_(buffer); 00820 if ((buf == nullptr) || buf->sem_id != manager_id_) 00821 { 00822 return; 00823 } 00824 touchBuffer_(buf); 00825 TLOG(15) << "IncrementReadPos: buffer= " << buffer << ", readPos=" << buf->readPos << ", bytes read=" << read; 00826 buf->readPos = buf->readPos + read; 00827 TLOG(15) << "IncrementReadPos: buffer= " << buffer << ", New readPos is " << buf->readPos; 00828 if (read == 0) 00829 { 00830 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) + ")"); 00831 } 00832 } 00833 00834 bool artdaq::SharedMemoryManager::IncrementWritePos(int buffer, size_t written) 00835 { 00836 TLOG(16) << "IncrementWritePos called: buffer= " << buffer << ", bytes written=" << written; 00837 00838 if (buffer >= shm_ptr_->buffer_count) 00839 { 00840 Detach(true, "ArgumentOutOfRange", "The specified buffer does not exist!"); 00841 } 00842 00843 TLOG(TLVL_BUFLCK) << "IncrementWritePos obtaining buffer_mutex for buffer " << buffer; 00844 std::lock_guard<std::mutex> lk(buffer_mutexes_[buffer]); 00845 TLOG(TLVL_BUFLCK) << "IncrementWritePos obtained buffer_mutex for buffer " << buffer; 00846 //TraceLock lk(buffer_mutexes_[buffer], 20, "IncWritePosBuffer" + std::to_string(buffer)); 00847 auto buf = getBufferInfo_(buffer); 00848 if (buf == nullptr) 00849 { 00850 return false; 00851 } 00852 checkBuffer_(buf, BufferSemaphoreFlags::Writing); 00853 touchBuffer_(buf); 00854 if (buf->writePos + written > shm_ptr_->buffer_size) 00855 { 00856 TLOG(TLVL_ERROR) << "Requested write size is larger than the buffer size! (sz=" << std::hex << shm_ptr_->buffer_size << ", cur + req=" << std::dec << buf->writePos + written << ")"; 00857 return false; 00858 } 00859 TLOG(16) << "IncrementWritePos: buffer= " << buffer << ", writePos=" << buf->writePos << ", bytes written=" << written; 00860 buf->writePos += written; 00861 TLOG(16) << "IncrementWritePos: buffer= " << buffer << ", New writePos is " << buf->writePos; 00862 if (written == 0) 00863 { 00864 Detach(true, "LogicError", "Cannot increment Write pos by 0!"); 00865 } 00866 00867 return true; 00868 } 00869 00870 bool artdaq::SharedMemoryManager::MoreDataInBuffer(int buffer) 00871 { 00872 TLOG(17) << "MoreDataInBuffer(" << buffer << ") called."; 00873 00874 if (buffer >= shm_ptr_->buffer_count) 00875 { 00876 Detach(true, "ArgumentOutOfRange", "The specified buffer does not exist!"); 00877 } 00878 00879 TLOG(TLVL_BUFLCK) << "MoreDataInBuffer obtaining buffer_mutex for buffer " << buffer; 00880 std::lock_guard<std::mutex> lk(buffer_mutexes_[buffer]); 00881 TLOG(TLVL_BUFLCK) << "MoreDataInBuffer obtained buffer_mutex for buffer " << buffer; 00882 //TraceLock lk(buffer_mutexes_[buffer], 21, "MoreDataInBuffer" + std::to_string(buffer)); 00883 auto buf = getBufferInfo_(buffer); 00884 if (buf == nullptr) 00885 { 00886 return false; 00887 } 00888 TLOG(17) << "MoreDataInBuffer: buffer= " << buffer << ", readPos=" << std::to_string(buf->readPos) << ", writePos=" << buf->writePos; 00889 return buf->readPos < buf->writePos; 00890 } 00891 00892 bool artdaq::SharedMemoryManager::CheckBuffer(int buffer, BufferSemaphoreFlags flags) 00893 { 00894 if (buffer >= shm_ptr_->buffer_count) 00895 { 00896 Detach(true, "ArgumentOutOfRange", "The specified buffer does not exist!"); 00897 } 00898 00899 TLOG(TLVL_BUFLCK) << "CheckBuffer obtaining buffer_mutex for buffer " << buffer; 00900 std::lock_guard<std::mutex> lk(buffer_mutexes_[buffer]); 00901 TLOG(TLVL_BUFLCK) << "CheckBuffer obtained buffer_mutex for buffer " << buffer; 00902 //TraceLock lk(buffer_mutexes_[buffer], 22, "CheckBuffer" + std::to_string(buffer)); 00903 return checkBuffer_(getBufferInfo_(buffer), flags, false); 00904 } 00905 00906 void artdaq::SharedMemoryManager::MarkBufferFull(int buffer, int destination) 00907 { 00908 if (buffer >= shm_ptr_->buffer_count) 00909 { 00910 Detach(true, "ArgumentOutOfRange", "The specified buffer does not exist!"); 00911 } 00912 00913 TLOG(TLVL_BUFLCK) << "MarkBufferFull obtaining buffer_mutex for buffer " << buffer; 00914 std::lock_guard<std::mutex> lk(buffer_mutexes_[buffer]); 00915 TLOG(TLVL_BUFLCK) << "MarkBufferFull obtained buffer_mutex for buffer " << buffer; 00916 00917 //TraceLock lk(buffer_mutexes_[buffer], 23, "FillBuffer" + std::to_string(buffer)); 00918 auto shmBuf = getBufferInfo_(buffer); 00919 if (shmBuf == nullptr) 00920 { 00921 return; 00922 } 00923 touchBuffer_(shmBuf); 00924 if (shmBuf->sem_id == manager_id_) 00925 { 00926 if (shmBuf->sem != BufferSemaphoreFlags::Full) 00927 { 00928 shmBuf->sem = BufferSemaphoreFlags::Full; 00929 } 00930 00931 shmBuf->sem_id = destination; 00932 } 00933 } 00934 00935 void artdaq::SharedMemoryManager::MarkBufferEmpty(int buffer, bool force) 00936 { 00937 TLOG(18) << "MarkBufferEmpty BEGIN, buffer=" << buffer << ", force=" << force << ", manager_id_=" << manager_id_; 00938 if (buffer >= shm_ptr_->buffer_count) 00939 { 00940 Detach(true, "ArgumentOutOfRange", "The specified buffer does not exist!"); 00941 } 00942 std::lock_guard<std::mutex> lk(buffer_mutexes_[buffer]); 00943 //TraceLock lk(buffer_mutexes_[buffer], 24, "EmptyBuffer" + std::to_string(buffer)); 00944 auto shmBuf = getBufferInfo_(buffer); 00945 if (shmBuf == nullptr) 00946 { 00947 return; 00948 } 00949 if (!force) 00950 { 00951 checkBuffer_(shmBuf, BufferSemaphoreFlags::Reading, true); 00952 } 00953 touchBuffer_(shmBuf); 00954 00955 shmBuf->readPos = 0; 00956 shmBuf->sem = BufferSemaphoreFlags::Full; 00957 00958 if ((force && (manager_id_ == 0 || manager_id_ == shmBuf->sem_id)) || (!force && shm_ptr_->destructive_read_mode)) 00959 { 00960 TLOG(18) << "MarkBufferEmpty Resetting buffer " << buffer << " to Empty state"; 00961 shmBuf->writePos = 0; 00962 shmBuf->sem = BufferSemaphoreFlags::Empty; 00963 if (shm_ptr_->reader_pos == static_cast<unsigned>(buffer) && !shm_ptr_->destructive_read_mode) 00964 { 00965 TLOG(18) << "MarkBufferEmpty Broadcast mode; incrementing reader_pos from " << shm_ptr_->reader_pos << " to " << (buffer + 1) % shm_ptr_->buffer_count; 00966 shm_ptr_->reader_pos = (buffer + 1) % shm_ptr_->buffer_count; 00967 } 00968 } 00969 shmBuf->sem_id = -1; 00970 TLOG(18) << "MarkBufferEmpty END, buffer=" << buffer << ", force=" << force; 00971 ; 00972 } 00973 00974 bool artdaq::SharedMemoryManager::ResetBuffer(int buffer) 00975 { 00976 if (buffer >= shm_ptr_->buffer_count) 00977 { 00978 Detach(true, "ArgumentOutOfRange", "The specified buffer does not exist!"); 00979 } 00980 00981 // ELF, 3/19/2019: These TRACE calls are a major performance hit with many buffers. 00982 //TLOG(TLVL_BUFLCK) << "ResetBuffer: obtaining buffer_mutex lock for buffer " << buffer; 00983 std::lock_guard<std::mutex> lk(buffer_mutexes_[buffer]); 00984 //TLOG(TLVL_BUFLCK) << "ResetBuffer: obtained buffer_mutex lock for buffer " << buffer; 00985 00986 //TraceLock lk(buffer_mutexes_[buffer], 25, "ResetBuffer" + std::to_string(buffer)); 00987 auto shmBuf = getBufferInfo_(buffer); 00988 if (shmBuf == nullptr) 00989 { 00990 return false; 00991 } 00992 /* 00993 if (shmBuf->sequence_id < shm_ptr_->lowest_seq_id_read - size() && shmBuf->sem == BufferSemaphoreFlags::Full) 00994 { 00995 TLOG(TLVL_DEBUG) << "Buffer " << buffer << " has been passed by all readers, marking Empty" ; 00996 shmBuf->writePos = 0; 00997 shmBuf->sem = BufferSemaphoreFlags::Empty; 00998 shmBuf->sem_id = -1; 00999 return true; 01000 }*/ 01001 01002 size_t delta = TimeUtils::gettimeofday_us() - shmBuf->last_touch_time; 01003 if (delta > 0xFFFFFFFF) 01004 { 01005 TLOG(TLVL_TRACE) << "Buffer has touch time in the future, setting it to current time and ignoring..."; 01006 shmBuf->last_touch_time = TimeUtils::gettimeofday_us(); 01007 return false; 01008 } 01009 if (shm_ptr_->buffer_timeout_us == 0 || delta <= shm_ptr_->buffer_timeout_us || shmBuf->sem == BufferSemaphoreFlags::Empty) 01010 { 01011 return false; 01012 } 01013 TLOG(27) << "Buffer " << buffer << " at " << static_cast<void*>(shmBuf) << " is stale, time=" << TimeUtils::gettimeofday_us() << ", last touch=" << shmBuf->last_touch_time << ", d=" << delta << ", timeout=" << shm_ptr_->buffer_timeout_us; 01014 01015 if (shmBuf->sem_id == manager_id_ && shmBuf->sem == BufferSemaphoreFlags::Writing) 01016 { 01017 return true; 01018 } 01019 01020 if (!shm_ptr_->destructive_read_mode && shmBuf->sem == BufferSemaphoreFlags::Full && manager_id_ == 0) 01021 { 01022 TLOG(TLVL_DEBUG) << "Resetting old broadcast mode buffer " << buffer << " (seqid=" << shmBuf->sequence_id << "). State: Full-->Empty"; 01023 shmBuf->writePos = 0; 01024 shmBuf->sem = BufferSemaphoreFlags::Empty; 01025 shmBuf->sem_id = -1; 01026 if (shm_ptr_->reader_pos == static_cast<unsigned>(buffer)) 01027 { 01028 shm_ptr_->reader_pos = (buffer + 1) % shm_ptr_->buffer_count; 01029 } 01030 return true; 01031 } 01032 01033 if (shmBuf->sem_id != manager_id_ && shmBuf->sem == BufferSemaphoreFlags::Reading) 01034 { 01035 // Ron wants to re-check for potential interleave of buffer state updates 01036 size_t delta = TimeUtils::gettimeofday_us() - shmBuf->last_touch_time; 01037 if (delta <= shm_ptr_->buffer_timeout_us) 01038 { 01039 return false; 01040 } 01041 TLOG(TLVL_WARNING) << "Stale Read buffer " << buffer << " at " << static_cast<void*>(shmBuf) 01042 << " ( " << delta << " / " << shm_ptr_->buffer_timeout_us << " us ) detected! (seqid=" 01043 << shmBuf->sequence_id << ") Resetting... Reading-->Full"; 01044 shmBuf->readPos = 0; 01045 shmBuf->sem = BufferSemaphoreFlags::Full; 01046 shmBuf->sem_id = -1; 01047 return true; 01048 } 01049 return false; 01050 } 01051 01052 bool artdaq::SharedMemoryManager::IsEndOfData() const 01053 { 01054 if (!IsValid()) 01055 { 01056 return true; 01057 } 01058 01059 struct shmid_ds info; 01060 auto sts = shmctl(shm_segment_id_, IPC_STAT, &info); 01061 if (sts < 0) 01062 { 01063 TLOG(TLVL_TRACE) << "Error accessing Shared Memory info: " << errno << " (" << strerror(errno) << ")."; 01064 return true; 01065 } 01066 01067 if ((info.shm_perm.mode & SHM_DEST) != 0) 01068 { 01069 TLOG(TLVL_INFO) << "Shared Memory marked for destruction. Probably an end-of-data condition!"; 01070 return true; 01071 } 01072 01073 return false; 01074 } 01075 01076 uint16_t artdaq::SharedMemoryManager::GetAttachedCount() const 01077 { 01078 if (!IsValid()) 01079 { 01080 return 0; 01081 } 01082 01083 struct shmid_ds info; 01084 auto sts = shmctl(shm_segment_id_, IPC_STAT, &info); 01085 if (sts < 0) 01086 { 01087 TLOG(TLVL_TRACE) << "Error accessing Shared Memory info: " << errno << " (" << strerror(errno) << ")."; 01088 return 0; 01089 } 01090 01091 return info.shm_nattch; 01092 } 01093 01094 size_t artdaq::SharedMemoryManager::Write(int buffer, void* data, size_t size) 01095 { 01096 TLOG(19) << "Write BEGIN"; 01097 if (buffer >= shm_ptr_->buffer_count) 01098 { 01099 Detach(true, "ArgumentOutOfRange", "The specified buffer does not exist!"); 01100 } 01101 std::lock_guard<std::mutex> lk(buffer_mutexes_[buffer]); 01102 //TraceLock lk(buffer_mutexes_[buffer], 26, "WriteBuffer" + std::to_string(buffer)); 01103 auto shmBuf = getBufferInfo_(buffer); 01104 if (shmBuf == nullptr) 01105 { 01106 return -1; 01107 } 01108 checkBuffer_(shmBuf, BufferSemaphoreFlags::Writing); 01109 touchBuffer_(shmBuf); 01110 TLOG(19) << "Buffer Write Pos is " << shmBuf->writePos << ", write size is " << size; 01111 if (shmBuf->writePos + size > shm_ptr_->buffer_size) 01112 { 01113 TLOG(TLVL_ERROR) << "Attempted to write more data than fits into Shared Memory, bufferSize=" << shm_ptr_->buffer_size 01114 << ",writePos=" << shmBuf->writePos << ",writeSize=" << size; 01115 Detach(true, "SharedMemoryWrite", "Attempted to write more data than fits into Shared Memory! \nRe-run with a larger buffer size!"); 01116 } 01117 01118 auto pos = GetWritePos(buffer); 01119 memcpy(pos, data, size); 01120 touchBuffer_(shmBuf); 01121 shmBuf->writePos = shmBuf->writePos + size; 01122 01123 auto last_seen = last_seen_id_.load(); 01124 while (last_seen < shmBuf->sequence_id && !last_seen_id_.compare_exchange_weak(last_seen, shmBuf->sequence_id)) {} 01125 01126 TLOG(19) << "Write END"; 01127 return size; 01128 } 01129 01130 bool artdaq::SharedMemoryManager::Read(int buffer, void* data, size_t size) 01131 { 01132 if (buffer >= shm_ptr_->buffer_count) 01133 { 01134 Detach(true, "ArgumentOutOfRange", "The specified buffer does not exist!"); 01135 } 01136 std::lock_guard<std::mutex> lk(buffer_mutexes_[buffer]); 01137 //TraceLock lk(buffer_mutexes_[buffer], 27, "ReadBuffer" + std::to_string(buffer)); 01138 auto shmBuf = getBufferInfo_(buffer); 01139 if (shmBuf == nullptr) 01140 { 01141 return false; 01142 } 01143 checkBuffer_(shmBuf, BufferSemaphoreFlags::Reading); 01144 touchBuffer_(shmBuf); 01145 if (shmBuf->readPos + size > shm_ptr_->buffer_size) 01146 { 01147 TLOG(TLVL_ERROR) << "Attempted to read more data than fits into Shared Memory, bufferSize=" << shm_ptr_->buffer_size 01148 << ",readPos=" << shmBuf->readPos << ",readSize=" << size; 01149 Detach(true, "SharedMemoryRead", "Attempted to read more data than exists in Shared Memory!"); 01150 } 01151 01152 auto pos = GetReadPos(buffer); 01153 TLOG(TLVL_TRACE) << "Before memcpy in Read(), size is " << size; 01154 memcpy(data, pos, size); 01155 TLOG(TLVL_TRACE) << "After memcpy in Read()"; 01156 auto sts = checkBuffer_(shmBuf, BufferSemaphoreFlags::Reading, false); 01157 if (sts) 01158 { 01159 shmBuf->readPos += size; 01160 touchBuffer_(shmBuf); 01161 return true; 01162 } 01163 return false; 01164 } 01165 01166 std::string artdaq::SharedMemoryManager::toString() 01167 { 01168 std::ostringstream ostr; 01169 ostr << "ShmStruct: " << std::endl 01170 << "Reader Position: " << shm_ptr_->reader_pos << std::endl 01171 << "Writer Position: " << shm_ptr_->writer_pos << std::endl 01172 << "Next ID Number: " << shm_ptr_->next_id << std::endl 01173 << "Buffer Count: " << shm_ptr_->buffer_count << std::endl 01174 << "Buffer Size: " << std::to_string(shm_ptr_->buffer_size) << " bytes" << std::endl 01175 << "Buffers Written: " << std::to_string(shm_ptr_->next_sequence_id) << std::endl 01176 << "Rank of Writer: " << shm_ptr_->rank << std::endl 01177 << "Ready Magic Bytes: 0x" << std::hex << shm_ptr_->ready_magic << std::dec << std::endl 01178 << std::endl; 01179 01180 for (auto ii = 0; ii < shm_ptr_->buffer_count; ++ii) 01181 { 01182 auto buf = getBufferInfo_(ii); 01183 if (buf == nullptr) 01184 { 01185 continue; 01186 } 01187 01188 ostr << "ShmBuffer " << std::dec << ii << std::endl 01189 << "sequenceID: " << std::to_string(buf->sequence_id) << std::endl 01190 << "writePos: " << std::to_string(buf->writePos) << std::endl 01191 << "readPos: " << std::to_string(buf->readPos) << std::endl 01192 << "sem: " << FlagToString(buf->sem) << std::endl 01193 << "Owner: " << std::to_string(buf->sem_id.load()) << std::endl 01194 << "Last Touch Time: " << std::to_string(buf->last_touch_time / 1000000.0) << std::endl 01195 << std::endl; 01196 } 01197 01198 return ostr.str(); 01199 } 01200 01201 void* artdaq::SharedMemoryManager::GetReadPos(int buffer) 01202 { 01203 auto buf = getBufferInfo_(buffer); 01204 if (buf == nullptr) 01205 { 01206 return nullptr; 01207 } 01208 return bufferStart_(buffer) + buf->readPos; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) 01209 } 01210 void* artdaq::SharedMemoryManager::GetWritePos(int buffer) 01211 { 01212 auto buf = getBufferInfo_(buffer); 01213 if (buf == nullptr) 01214 { 01215 return nullptr; 01216 } 01217 return bufferStart_(buffer) + buf->writePos; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) 01218 } 01219 01220 void* artdaq::SharedMemoryManager::GetBufferStart(int buffer) 01221 { 01222 return bufferStart_(buffer); 01223 } 01224 01225 std::vector<std::pair<int, artdaq::SharedMemoryManager::BufferSemaphoreFlags>> artdaq::SharedMemoryManager::GetBufferReport() 01226 { 01227 auto output = std::vector<std::pair<int, BufferSemaphoreFlags>>(size()); 01228 for (size_t ii = 0; ii < size(); ++ii) 01229 { 01230 auto buf = getBufferInfo_(ii); 01231 output[ii] = std::make_pair(buf->sem_id.load(), buf->sem.load()); 01232 } 01233 return output; 01234 } 01235 01236 bool artdaq::SharedMemoryManager::checkBuffer_(ShmBuffer* buffer, BufferSemaphoreFlags flags, bool exceptions) 01237 { 01238 if (buffer == nullptr) 01239 { 01240 if (exceptions) 01241 { 01242 Detach(true, "BufferNotThereException", "Request to check buffer that does not exist!"); 01243 } 01244 return false; 01245 } 01246 TLOG(TLVL_TRACE) << "checkBuffer_: Checking that buffer " << buffer->sequence_id << " has sem_id " << manager_id_ << " (Current: " << buffer->sem_id << ") and is in state " << FlagToString(flags) << " (current: " << FlagToString(buffer->sem) << ")"; 01247 if (exceptions) 01248 { 01249 if (buffer->sem != flags) 01250 { 01251 Detach(true, "StateAccessViolation", "Shared Memory buffer is not in the correct state! (expected " + FlagToString(flags) + ", actual " + FlagToString(buffer->sem) + ")"); 01252 } 01253 if (buffer->sem_id != manager_id_) 01254 { 01255 Detach(true, "OwnerAccessViolation", "Shared Memory buffer is not owned by this manager instance! (Expected: " + std::to_string(manager_id_) + ", Actual: " + std::to_string(buffer->sem_id) + ")"); 01256 } 01257 } 01258 bool ret = (buffer->sem_id == manager_id_ || (buffer->sem_id == -1 && (flags == BufferSemaphoreFlags::Full || flags == BufferSemaphoreFlags::Empty))) && buffer->sem == flags; 01259 01260 if (!ret) 01261 { 01262 TLOG(TLVL_WARNING) << "CheckBuffer detected issue with buffer " << buffer->sequence_id << "!" 01263 << " ID: " << buffer->sem_id << " (Expected " << manager_id_ << "), Flag: " << FlagToString(buffer->sem) << " (Expected " << FlagToString(flags) << "). " 01264 << R"(ID -1 is okay if expected flag is "Full" or "Empty".)"; 01265 } 01266 01267 return ret; 01268 } 01269 01270 void artdaq::SharedMemoryManager::touchBuffer_(ShmBuffer* buffer) 01271 { 01272 if ((buffer == nullptr) || (buffer->sem_id != -1 && buffer->sem_id != manager_id_)) 01273 { 01274 return; 01275 } 01276 TLOG(TLVL_TRACE) << "touchBuffer_: Touching buffer at " << static_cast<void*>(buffer) << " with sequence_id " << buffer->sequence_id; 01277 buffer->last_touch_time = TimeUtils::gettimeofday_us(); 01278 } 01279 01280 void artdaq::SharedMemoryManager::Detach(bool throwException, const std::string& category, const std::string& message, bool force) 01281 { 01282 TLOG(TLVL_DETACH) << "Detach BEGIN: throwException: " << std::boolalpha << throwException << ", force: " << force; 01283 if (IsValid()) 01284 { 01285 TLOG(TLVL_DETACH) << "Detach: Resetting owned buffers"; 01286 auto bufs = GetBuffersOwnedByManager(false); 01287 for (auto buf : bufs) 01288 { 01289 auto shmBuf = getBufferInfo_(buf); 01290 if (shmBuf == nullptr) 01291 { 01292 continue; 01293 } 01294 if (shmBuf->sem == BufferSemaphoreFlags::Writing) 01295 { 01296 shmBuf->sem = BufferSemaphoreFlags::Empty; 01297 } 01298 else if (shmBuf->sem == BufferSemaphoreFlags::Reading) 01299 { 01300 shmBuf->sem = BufferSemaphoreFlags::Full; 01301 } 01302 shmBuf->sem_id = -1; 01303 } 01304 } 01305 01306 if (shm_ptr_ != nullptr) 01307 { 01308 TLOG(TLVL_DETACH) << "Detach: Detaching shared memory"; 01309 shmdt(shm_ptr_); 01310 shm_ptr_ = nullptr; 01311 } 01312 01313 if ((force || manager_id_ == 0) && shm_segment_id_ > -1) 01314 { 01315 TLOG(TLVL_DETACH) << "Detach: Marking Shared memory for removal"; 01316 shmctl(shm_segment_id_, IPC_RMID, nullptr); 01317 shm_segment_id_ = -1; 01318 } 01319 01320 // Reset manager_id_ 01321 manager_id_ = -1; 01322 01323 if (!category.empty() && !message.empty()) 01324 { 01325 TLOG(TLVL_ERROR) << category << ": " << message; 01326 01327 if (throwException) 01328 { 01329 throw cet::exception(category) << message; // NOLINT(cert-err60-cpp) 01330 } 01331 } 01332 } 01333 01334 // Local Variables: 01335 // mode: c++ 01336 // End: