ATLAS Offline Software
Loading...
Searching...
No Matches
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 <ranges>
18#include <algorithm>
19#include <filesystem>
20#include <fstream>
21#include <mutex>
22#include <regex>
23#include <tbb/concurrent_unordered_map.h>
24#include <unordered_set>
25
26//
27// method implementations
28//
29
30namespace asg
31{
32#ifdef XAOD_STANDALONE
33
34 namespace
35 {
36 tbb::concurrent_unordered_map<std::string, std::function<std::unique_ptr<AsgComponent>(const std::string& name)>> s_factories;
37 tbb::concurrent_unordered_map<std::string,std::string> s_typeModuleMap;
38
39 struct ModuleData final
40 {
41 std::atomic<bool> loaded{false};
42 std::mutex mutex;
43 };
44 tbb::concurrent_unordered_map<std::string,ModuleData> s_modules;
45 }
46
47
48
49 StatusCode registerComponentFactory (const std::string& type, const std::function<std::unique_ptr<AsgComponent>(const std::string& name)>& factory)
50 {
51 using namespace msgComponentConfig;
52 if (!s_factories.emplace (type, factory).second)
53 {
54 ATH_MSG_ERROR ("attempt to register a factory for type " << type << " that already has a factory");
55 return StatusCode::FAILURE;
56 }
57 return StatusCode::SUCCESS;
58 }
59
60
61
62 const std::function<std::unique_ptr<AsgComponent>(const std::string& name)> *getComponentFactory (const std::string& type)
63 {
64 using namespace msgComponentConfig;
65 if (auto iter = s_factories.find (type); iter != s_factories.end())
66 return &iter->second;
67 static std::once_flag flag;
68 std::call_once (flag, [&] () {
69 const char *path = gSystem->Getenv ("LD_LIBRARY_PATH");
70 if (!path) return;
71 std::regex pathRegex ("\\.asgcomponents$");
72 for (auto&& part : std::views::split(std::string_view(path), ':'))
73 {
74 std::string_view p(&*part.begin(), std::ranges::distance(part));
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}
#define ATH_MSG_ERROR(x)
#define ATH_MSG_FATAL(x)
#define ATH_MSG_WARNING(x)
#define ATH_MSG_DEBUG(x)
#define ANA_MSG_DEBUG(xmsg)
Macro printing debug messages.
::StatusCode StatusCode
StatusCode definition for legacy code.
path
python interpreter configuration --------------------------------------—
Definition athena.py:128
bool flag
Definition master.py:29
void sort(typename DataModel_detail::iterator< DVL > beg, typename DataModel_detail::iterator< DVL > end)
Specialization of sort for DataVector/List.