From 3977f4b4976bc30c9d3c8d6d388fd3c5e042e75a Mon Sep 17 00:00:00 2001
From: Markus FRANK <Markus.Frank@cern.ch>
Date: Fri, 19 Mar 2021 10:30:55 +0100
Subject: [PATCH] Protect Detector and geometry for parallel/multithreaded
 construction

---
 DDCore/src/DetectorImp.cpp             | 31 ++++++++++++++++++++++++--
 DDCore/src/plugins/StandardPlugins.cpp |  5 +++--
 UtilityApps/src/display.cpp            |  8 ++++---
 3 files changed, 37 insertions(+), 7 deletions(-)

diff --git a/DDCore/src/DetectorImp.cpp b/DDCore/src/DetectorImp.cpp
index b744bd69c..74e12ba12 100644
--- a/DDCore/src/DetectorImp.cpp
+++ b/DDCore/src/DetectorImp.cpp
@@ -100,11 +100,34 @@ namespace {
       return 0;
     }
   };
-  static Instances& detector_instances()    {
+  
+  Instances& detector_instances()    {
     static Instances s_inst;
     return s_inst;
   }
 
+  pair<mutex, map<DetectorImp*, TGeoManager*> >& detector_lock()   {
+    static pair<mutex, map<DetectorImp*, TGeoManager*> > s_inst;
+    return s_inst;
+  }
+  
+  void lock_detector(DetectorImp* imp, TGeoManager* mgr)   {
+    auto& lock = detector_lock();
+    lock.first.lock();
+    lock.second[imp] = mgr;
+  }
+  TGeoManager* unlock_detector(DetectorImp* imp)   {
+    TGeoManager* mgr = nullptr;
+    auto& lock = detector_lock();
+    auto i = lock.second.find(imp);
+    if ( i != lock.second.end() )   {
+      mgr = (*i).second;
+      lock.second.erase(i);
+    }
+    lock.first.unlock();
+    return mgr;
+  }
+  
   void description_unexpected()    {
     try  {
       throw;
@@ -198,8 +221,9 @@ DetectorImp::DetectorImp(const string& name)
   SetName(name.c_str());
   SetTitle("DD4hep detector description object");
   set_terminate( description_unexpected );
+  lock_detector( this, gGeoManager );
+  gGeoManager = nullptr;
   InstanceCount::increment(this);
-  //if ( gGeoManager ) delete gGeoManager;
   m_manager = new TGeoManager(name.c_str(), "Detector Geometry");
   {
     m_manager->AddNavigator();
@@ -234,6 +258,7 @@ DetectorImp::DetectorImp(const string& name)
 
 /// Standard destructor
 DetectorImp::~DetectorImp() {
+  lock_detector( this, gGeoManager );
   if ( m_manager )  {
     lock_guard<recursive_mutex> lock(detector_instances().lock);
     if ( m_manager == gGeoManager ) gGeoManager = 0;
@@ -250,6 +275,7 @@ DetectorImp::~DetectorImp() {
   m_extensions.clear();
   m_detectorTypes.clear();
   InstanceCount::decrement(this);
+  gGeoManager = unlock_detector(this);
 }
 
 /// ROOT I/O call
@@ -719,6 +745,7 @@ void DetectorImp::endDocument(bool close_geometry)    {
   patcher.patchShapes();
   mapDetectorTypes();
   m_state = READY;
+  gGeoManager = unlock_detector(this);
 }
 
 /// Initialize the geometry and set the bounding box of the world volume
diff --git a/DDCore/src/plugins/StandardPlugins.cpp b/DDCore/src/plugins/StandardPlugins.cpp
index 3b22c1b48..4eb52cb0f 100644
--- a/DDCore/src/plugins/StandardPlugins.cpp
+++ b/DDCore/src/plugins/StandardPlugins.cpp
@@ -135,12 +135,13 @@ static long display(Detector& description, int argc, char** argv) {
       detector = argv[++i];
     else  {
       cout <<
-        "Usage: -plugin <name> -arg [-arg]                                                   \n"
+        "Usage: -plugin DD4hep_GeometryDisplay  -arg [-arg]                                \n\n"
         "     -detector <string> Top level DetElement path. Default: '/world'                \n"
         "     -option   <string> ROOT Draw option.    Default: 'ogl'                         \n"
         "     -level    <number> Visualization level  [TGeoManager::SetVisLevel]  Default: 4 \n"
         "     -visopt   <number> Visualization option [TGeoManager::SetVisOption] Default: 1 \n"       
-        "\tArguments given: " << arguments(argc,argv) << endl << flush;
+        "     -help              Print this help output  \n"       
+        "     Arguments given: " << arguments(argc,argv) << endl << flush;
       ::exit(EINVAL);
     }
   }
diff --git a/UtilityApps/src/display.cpp b/UtilityApps/src/display.cpp
index f4fa3643a..53c2f7a05 100644
--- a/UtilityApps/src/display.cpp
+++ b/UtilityApps/src/display.cpp
@@ -18,11 +18,12 @@
 int main(int argc,char** argv)  {
   std::vector<const char*> av;
   std::string level, visopt, opt, detector;
-  bool dry = false;
+  bool dry = false, help = false;
   for(int i=0; i<argc; ++i)  {
     if ( i==1 && argv[i][0] != '-' ) av.emplace_back("-input");
-    if      ( strncmp(argv[i],"-load-only",4) == 0 ) dry = true, av.emplace_back(argv[i]);
-    else if ( strncmp(argv[i],"-dry-run",4)   == 0 ) dry = true, av.emplace_back(argv[i]);
+    if      ( strncmp(argv[i],"-load-only",4) == 0 ) dry  = true, av.emplace_back(argv[i]);
+    else if ( strncmp(argv[i],"-dry-run",4)   == 0 ) dry  = true, av.emplace_back(argv[i]);
+    else if ( strncmp(argv[i],"-help",4)      == 0 ) help = true, av.emplace_back(argv[i]);
     else if ( strncmp(argv[i],"-visopt",4)    == 0 ) visopt   = argv[++i];
     else if ( strncmp(argv[i],"-level", 4)    == 0 ) level    = argv[++i];
     else if ( strncmp(argv[i],"-option",4)    == 0 ) opt      = argv[++i];
@@ -33,6 +34,7 @@ int main(int argc,char** argv)  {
     av.emplace_back("-interactive");
     av.emplace_back("-plugin");
     av.emplace_back("DD4hep_GeometryDisplay");
+    if ( help              ) av.emplace_back("-help");
     if ( !opt.empty()      ) av.emplace_back("-opt"),      av.emplace_back(opt.c_str());
     if ( !level.empty()    ) av.emplace_back("-level"),    av.emplace_back(level.c_str());
     if ( !visopt.empty()   ) av.emplace_back("-visopt"),   av.emplace_back(visopt.c_str());
-- 
GitLab