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