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