ATLAS Offline Software
AsgComponentFactories.cxx
Go to the documentation of this file.
1 /*
2  Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
3 */
4 
6 
7 
8 //
9 // includes
10 //
11 
13 
14 #include <AsgTools/IAsgTool.h>
16 #include <TSystem.h>
17 #include <boost/algorithm/string.hpp>
18 #include <filesystem>
19 #include <fstream>
20 #include <mutex>
21 #include <regex>
22 #include <tbb/concurrent_unordered_map.h>
23 #include <unordered_set>
24 
25 //
26 // method implementations
27 //
28 
29 namespace asg
30 {
31 #ifdef XAOD_STANDALONE
32 
33  namespace
34  {
35  tbb::concurrent_unordered_map<std::string, std::function<std::unique_ptr<AsgComponent>(const std::string& name)>> s_factories;
36  tbb::concurrent_unordered_map<std::string,std::string> s_typeModuleMap;
37 
38  struct ModuleData final
39  {
40  std::atomic<bool> loaded{false};
42  };
43  tbb::concurrent_unordered_map<std::string,ModuleData> s_modules;
44  }
45 
46 
47 
48  StatusCode registerComponentFactory (const std::string& type, const std::function<std::unique_ptr<AsgComponent>(const std::string& name)>& factory)
49  {
50  using namespace msgComponentConfig;
51  if (!s_factories.emplace (type, factory).second)
52  {
53  ATH_MSG_ERROR ("attempt to register a factory for type " << type << " that already has a factory");
54  return StatusCode::FAILURE;
55  }
56  return StatusCode::SUCCESS;
57  }
58 
59 
60 
61  const std::function<std::unique_ptr<AsgComponent>(const std::string& name)> *getComponentFactory (const std::string& type)
62  {
63  using namespace msgComponentConfig;
64  if (auto iter = s_factories.find (type); iter != s_factories.end())
65  return &iter->second;
66  static std::once_flag flag;
67  std::call_once (flag, [&] () {
68  const char *path = gSystem->Getenv ("LD_LIBRARY_PATH");
69  if (!path) return;
70  std::vector<std::string> paths;
71  boost::split (paths, path, boost::is_any_of (":"));
72  std::regex pathRegex ("\\.asgcomponents$");
73  for (const auto& p : paths)
74  {
75  if (p.empty()) continue;
76  std::error_code ec;
77  if (!std::filesystem::exists(p, ec))
78  {
79  ANA_MSG_DEBUG ("skipping non-existent directory for component factory maps: " << p);
80  continue;
81  }
82  ANA_MSG_DEBUG ("checking for component factory map in " << p);
83  // find all files that end in ".asgcomponents"
84  for (auto const& entry : std::filesystem::directory_iterator(p))
85  {
86  if (std::regex_search (entry.path().filename().string(), pathRegex))
87  loadComponentFactoryMap (entry.path());
88  }
89  }
90  });
91  if (auto iter = s_typeModuleMap.find (type); iter != s_typeModuleMap.end())
92  {
93  ATH_MSG_DEBUG ("loading component factory module for type " << type << " from " << iter->second);
94  loadComponentFactoryModule (iter->second);
95  } else
96  {
97  ATH_MSG_DEBUG ("no component factory module known for type " << type);
98  return nullptr;
99  }
100  if (auto iter = s_factories.find (type); iter != s_factories.end())
101  return &iter->second;
102  else
103  {
104  ATH_MSG_WARNING ("no component factory found for type " << type << " even after loading its module");
105  return nullptr;
106  }
107  }
108 
109 
110 
111  std::vector<std::string> getLoadedComponentFactoryTypes ()
112  {
113  using namespace msgComponentConfig;
114  ATH_MSG_DEBUG ("getting component factory types");
115  std::vector<std::string> result;
116  result.reserve (s_factories.size());
117  for (const auto& pair : s_factories)
118  result.push_back (pair.first);
119  std::sort (result.begin(), result.end());
120  return result;
121  }
122 
123 
124 
125  void loadComponentFactoryModule (const std::string& moduleName, const std::string& modulePath)
126  {
127  using namespace msgComponentConfig;
128  ATH_MSG_DEBUG ("loading component factory module " << moduleName);
129 
130  auto [iter, inserted] = s_modules.emplace(std::piecewise_construct, std::forward_as_tuple(moduleName), std::forward_as_tuple());
131  if (iter->second.loaded == true)
132  {
133  ATH_MSG_DEBUG ("component factory module " << moduleName << " already loaded");
134  return;
135  }
136  std::scoped_lock lock(iter->second.mutex);
137  if (iter->second.loaded == true)
138  {
139  ATH_MSG_DEBUG ("component factory module " << moduleName << " already loaded");
140  return;
141  }
142 
143  // Load the module and register its factories
144  std::string path;
145  if (!modulePath.empty())
146  path = modulePath + "/" + moduleName;
147  else
148  path = gSystem->DynamicPathName (moduleName.c_str());
149  ANA_MSG_DEBUG ("loading component factory module from " << path);
150  if (gSystem->Load (path.c_str()) < 0)
151  {
152  ATH_MSG_FATAL ("failed to preload component factory module " << moduleName);
153  std::terminate();
154  }
155  iter->second.loaded = true;
156  }
157 
158 
159 
160  void loadComponentFactoryMap (const std::string& path)
161  {
162  using namespace msgComponentConfig;
163  ATH_MSG_DEBUG ("loading component factory map from " << path);
164 
165  std::ifstream inputStream (path);
166  if (!inputStream)
167  {
168  ATH_MSG_FATAL ("failed to open component factory map file " << path);
169  std::abort();
170  }
171  std::unordered_set<std::string> foundModules;
172  std::unordered_set<std::string> skippedModules;
173  std::string moduleName, typeName;
174  while (inputStream >> moduleName >> typeName)
175  {
176  // If the module is already known from another component factory
177  // map, we skip it. This is for a niche case in which we drop a
178  // component factory map in our local version that exists in the
179  // release.
180  if (auto iter = s_modules.find(moduleName); iter != s_modules.end())
181  {
182  if (skippedModules.emplace(moduleName).second)
183  ANA_MSG_DEBUG ("skipping information on " << moduleName << " from " << path << " because it has already been described in another file");
184  continue;
185  }
186  foundModules.insert(moduleName);
187  ATH_MSG_DEBUG ("registering component factory type " << typeName << " from module " << moduleName);
188  auto [iter, success] = s_typeModuleMap.emplace (typeName, moduleName);
189  if (!success)
190  {
191  if (iter->second != moduleName)
192  {
193  ATH_MSG_FATAL ("conflicting component factory module for type " << typeName
194  << ": already registered from " << iter->second
195  << ", but trying to register from " << moduleName);
196  std::abort();
197  } else
198  {
199  ATH_MSG_DEBUG ("component factory type " << typeName << " registered twice for module " << moduleName);
200  }
201  }
202  }
203  for (const auto& moduleName : foundModules)
204  s_modules.emplace(std::piecewise_construct, std::forward_as_tuple(moduleName), std::forward_as_tuple());
205  }
206 
207 #endif
208 }
createLinkingScheme.iter
iter
Definition: createLinkingScheme.py:62
ATH_MSG_FATAL
#define ATH_MSG_FATAL(x)
Definition: AthMsgStreamMacros.h:34
get_generator_info.result
result
Definition: get_generator_info.py:21
athena.path
path
python interpreter configuration --------------------------------------—
Definition: athena.py:128
BeamSpot::mutex
std::mutex mutex
Definition: InDetBeamSpotVertex.cxx:18
asg
Definition: DataHandleTestTool.h:28
python.RatesEmulationExample.lock
lock
Definition: RatesEmulationExample.py:148
python.CaloAddPedShiftConfig.type
type
Definition: CaloAddPedShiftConfig.py:42
PrepareReferenceFile.regex
regex
Definition: PrepareReferenceFile.py:43
python.utils.AtlRunQueryDQUtils.p
p
Definition: AtlRunQueryDQUtils.py:209
ATH_MSG_ERROR
#define ATH_MSG_ERROR(x)
Definition: AthMsgStreamMacros.h:33
EL::StatusCode
::StatusCode StatusCode
StatusCode definition for legacy code.
Definition: PhysicsAnalysis/D3PDTools/EventLoop/EventLoop/StatusCode.h:22
ATH_MSG_DEBUG
#define ATH_MSG_DEBUG(x)
Definition: AthMsgStreamMacros.h:29
master.flag
bool flag
Definition: master.py:29
IAsgTool.h
columnar::final
CM final
Definition: ColumnAccessor.h:106
GetAllXsec.entry
list entry
Definition: GetAllXsec.py:132
name
std::string name
Definition: Control/AthContainers/Root/debug.cxx:240
std::sort
void sort(typename std::reverse_iterator< DataModel_detail::iterator< DVL > > beg, typename std::reverse_iterator< DataModel_detail::iterator< DVL > > end, const Compare &comp)
Specialization of sort for DataVector/List.
Definition: DVL_algorithms.h:623
ATH_MSG_WARNING
#define ATH_MSG_WARNING(x)
Definition: AthMsgStreamMacros.h:32
LArHVGainsPredictor.error_code
error_code
Definition: LArHVGainsPredictor.py:228
ReadCalibFromCool.typeName
typeName
Definition: ReadCalibFromCool.py:477
python.dummyaccess.exists
def exists(filename)
Definition: dummyaccess.py:9
AsgComponentFactories.h
Trk::split
@ split
Definition: LayerMaterialProperties.h:38
MessageCheckAsgTools.h
test_athena_ntuple_dumper.paths
paths
Definition: test_athena_ntuple_dumper.py:7
ANA_MSG_DEBUG
#define ANA_MSG_DEBUG(xmsg)
Macro printing debug messages.
Definition: Control/AthToolSupport/AsgMessaging/AsgMessaging/MessageCheck.h:288