Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2023-10-25 10:04:21

0001 #include <memory>
0002 
0003 #include "SimG4Core/Application/interface/OscarMTMasterThread.h"
0004 #include "FWCore/Utilities/interface/Exception.h"
0005 #include "FWCore/Framework/interface/ConsumesCollector.h"
0006 
0007 #include "SimG4Core/Application/interface/RunManagerMT.h"
0008 #include "SimG4Core/Geometry/interface/CustomUIsession.h"
0009 
0010 #include "G4PhysicalVolumeStore.hh"
0011 
0012 OscarMTMasterThread::OscarMTMasterThread(const edm::ParameterSet& iConfig)
0013     : m_pGeoFromDD4hep(iConfig.getParameter<bool>("g4GeometryDD4hepSource")),
0014       m_masterThreadState(ThreadState::NotExist) {
0015   // Lock the mutex
0016   std::unique_lock<std::mutex> lk(m_threadMutex);
0017 
0018   edm::LogVerbatim("SimG4CoreApplication")
0019       << "OscarMTMasterThread: creating master thread DD4hep: " << m_pGeoFromDD4hep;
0020 
0021   // Create Geant4 master thread
0022   m_masterThread = std::thread([&]() {
0023     /////////////////
0024     // Initialization
0025     std::unique_ptr<CustomUIsession> uiSession;
0026 
0027     // Lock the mutex (i.e. wait until the creating thread has called cv.wait()
0028     std::unique_lock<std::mutex> lk2(m_threadMutex);
0029 
0030     edm::LogVerbatim("SimG4CoreApplication") << "OscarMTMasterThread: initializing RunManagerMT";
0031 
0032     //UIsession manager for message handling
0033     uiSession = std::make_unique<CustomUIsession>();
0034 
0035     // Create the master run manager, and share it to the CMSSW thread
0036     m_runManagerMaster = std::make_shared<RunManagerMT>(iConfig);
0037 
0038     /////////////
0039     // State loop
0040     bool isG4Alive = false;
0041     while (true) {
0042       // Signal main thread that it can proceed
0043       m_mainCanProceed = true;
0044       edm::LogVerbatim("OscarMTMasterThread") << "Master thread: State loop, notify main thread";
0045       m_notifyMainCv.notify_one();
0046 
0047       // Wait until the main thread sends signal
0048       m_masterCanProceed = false;
0049       edm::LogVerbatim("OscarMTMasterThread") << "Master thread: State loop, starting wait";
0050       m_notifyMasterCv.wait(lk2, [&] { return m_masterCanProceed; });
0051       //m_notifyMasterCv.wait(lk2, [&] { return false; });
0052 
0053       // Act according to the state
0054       edm::LogVerbatim("OscarMTMasterThread")
0055           << "Master thread: Woke up, state is " << static_cast<int>(m_masterThreadState);
0056       if (m_masterThreadState == ThreadState::BeginRun) {
0057         // Initialize Geant4
0058         edm::LogVerbatim("OscarMTMasterThread") << "Master thread: Initializing Geant4";
0059         m_runManagerMaster->initG4(m_pDDD, m_pDD4hep, m_pTable);
0060         isG4Alive = true;
0061       } else if (m_masterThreadState == ThreadState::EndRun) {
0062         // Stop Geant4
0063         edm::LogVerbatim("OscarMTMasterThread") << "Master thread: Stopping Geant4";
0064         m_runManagerMaster->stopG4();
0065         isG4Alive = false;
0066       } else if (m_masterThreadState == ThreadState::Destruct) {
0067         edm::LogVerbatim("OscarMTMasterThread") << "Master thread: Breaking out of state loop";
0068         if (isG4Alive)
0069           throw cms::Exception("LogicError") << "OscarMTMasterThread: Geant4 is still alive, master thread "
0070                                              << "state must be set to EndRun before Destruct";
0071         break;
0072       } else {
0073         throw cms::Exception("LogicError")
0074             << "OscarMTMasterThread: Illegal master thread state " << static_cast<int>(m_masterThreadState);
0075       }
0076     }
0077 
0078     //////////
0079     // Cleanup
0080     edm::LogVerbatim("SimG4CoreApplication") << "OscarMTMasterThread: start RunManagerMT destruction";
0081 
0082     // must be done in this thread, segfault otherwise
0083     m_runManagerMaster.reset();
0084     G4PhysicalVolumeStore::Clean();
0085 
0086     edm::LogVerbatim("SimG4CoreApplication") << "OscarMTMasterThread: physics and geometry are cleaned";
0087     lk2.unlock();
0088     edm::LogVerbatim("SimG4CoreApplication") << "OscarMTMasterThread: Master thread is finished";
0089   });
0090 
0091   // Start waiting a signal from the condition variable (releases the lock temporarily)
0092   // First for initialization
0093   m_mainCanProceed = false;
0094   LogDebug("OscarMTMasterThread") << "Main thread: Signal master for initialization";
0095   m_notifyMainCv.wait(lk, [&]() { return m_mainCanProceed; });
0096 
0097   lk.unlock();
0098   edm::LogVerbatim("SimG4CoreApplication") << "OscarMTMasterThread: Master thread is constructed";
0099 }
0100 
0101 OscarMTMasterThread::~OscarMTMasterThread() {
0102   if (!m_stopped) {
0103     stopThread();
0104   }
0105 }
0106 
0107 void OscarMTMasterThread::callConsumes(edm::ConsumesCollector&& iC) const {
0108   if (m_hasToken) {
0109     return;
0110   }
0111   if (m_pGeoFromDD4hep) {
0112     m_DD4hep = iC.esConsumes<cms::DDCompactView, IdealGeometryRecord, edm::Transition::BeginRun>();
0113   } else {
0114     m_DDD = iC.esConsumes<DDCompactView, IdealGeometryRecord, edm::Transition::BeginRun>();
0115   }
0116   m_PDT = iC.esConsumes<HepPDT::ParticleDataTable, PDTRecord, edm::Transition::BeginRun>();
0117   m_hasToken = true;
0118 }
0119 
0120 void OscarMTMasterThread::beginRun(const edm::EventSetup& iSetup) const {
0121   std::lock_guard<std::mutex> lk(m_protectMutex);
0122   std::unique_lock<std::mutex> lk2(m_threadMutex);
0123   edm::LogVerbatim("SimG4CoreApplication") << "OscarMTMasterThread::beginRun";
0124 
0125   if (m_firstRun) {
0126     if (m_pGeoFromDD4hep) {
0127       m_pDD4hep = &(*iSetup.getTransientHandle(m_DD4hep));
0128     } else {
0129       m_pDDD = &(*iSetup.getTransientHandle(m_DDD));
0130     }
0131     m_pTable = &iSetup.getData(m_PDT);
0132     m_firstRun = false;
0133   }
0134   m_masterThreadState = ThreadState::BeginRun;
0135   m_masterCanProceed = true;
0136   m_mainCanProceed = false;
0137   edm::LogVerbatim("SimG4CoreApplication") << "OscarMTMasterThread: Signal master for BeginRun";
0138   m_notifyMasterCv.notify_one();
0139   m_notifyMainCv.wait(lk2, [&]() { return m_mainCanProceed; });
0140 
0141   lk2.unlock();
0142   edm::LogVerbatim("SimG4CoreApplication") << "OscarMTMasterThread: finish BeginRun";
0143 }
0144 
0145 void OscarMTMasterThread::endRun() const {
0146   std::lock_guard<std::mutex> lk(m_protectMutex);
0147   std::unique_lock<std::mutex> lk2(m_threadMutex);
0148 
0149   m_masterThreadState = ThreadState::EndRun;
0150   m_mainCanProceed = false;
0151   m_masterCanProceed = true;
0152   edm::LogVerbatim("SimG4CoreApplication") << "OscarMTMasterThread: Signal master for EndRun";
0153   m_notifyMasterCv.notify_one();
0154   m_notifyMainCv.wait(lk2, [&]() { return m_mainCanProceed; });
0155   lk2.unlock();
0156   edm::LogVerbatim("SimG4CoreApplication") << "OscarMTMasterThread: finish EndRun";
0157 }
0158 
0159 void OscarMTMasterThread::stopThread() {
0160   if (m_stopped) {
0161     return;
0162   }
0163   edm::LogVerbatim("SimG4CoreApplication") << "OscarMTMasterThread::stopTread: stop main thread";
0164   std::unique_lock<std::mutex> lk2(m_threadMutex);
0165   m_masterThreadState = ThreadState::Destruct;
0166   m_masterCanProceed = true;
0167   edm::LogVerbatim("SimG4CoreApplication") << "OscarMTMasterThread::stopTread: notify";
0168   m_notifyMasterCv.notify_one();
0169   lk2.unlock();
0170   m_masterThread.join();
0171   edm::LogVerbatim("SimG4CoreApplication") << "OscarMTMasterThread::stopTread: is done";
0172   m_stopped = true;
0173 }