File indexing completed on 2024-11-09 02:40:43
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014 #include <filesystem>
0015 #include <fstream>
0016 #include <functional>
0017 #include <set>
0018
0019
0020 #include "TInterpreter.h"
0021 #include "TVirtualMutex.h"
0022
0023
0024 #include "FWCore/PluginManager/interface/CacheParser.h"
0025 #include "FWCore/PluginManager/interface/PluginFactoryBase.h"
0026 #include "FWCore/PluginManager/interface/PluginFactoryManager.h"
0027 #include "FWCore/PluginManager/interface/PluginManager.h"
0028 #include "FWCore/PluginManager/interface/standard.h"
0029 #include "FWCore/Utilities/interface/Exception.h"
0030 #include "FWCore/Utilities/interface/thread_safety_macros.h"
0031
0032 #include "PauseMaxMemoryPreloadSentry.h"
0033
0034 namespace edmplugin {
0035
0036
0037
0038
0039
0040
0041
0042
0043 static bool readCacheFile(const std::filesystem::path& cacheFile,
0044 const std::filesystem::path& dir,
0045 PluginManager::CategoryToInfos& categoryToInfos) {
0046 if (exists(cacheFile)) {
0047 std::ifstream file(cacheFile.string().c_str());
0048 if (not file) {
0049 throw cms::Exception("PluginMangerCacheProblem")
0050 << "Unable to open the cache file '" << cacheFile.string() << "'. Please check permissions on file";
0051 }
0052 edm::PauseMaxMemoryPreloadSentry pauseSentry;
0053 CacheParser::read(file, dir, categoryToInfos);
0054 return true;
0055 }
0056 return false;
0057 }
0058
0059
0060
0061 PluginManager::PluginManager(const PluginManager::Config& iConfig) : searchPath_(iConfig.searchPath()) {
0062 using std::placeholders::_1;
0063 const std::filesystem::path& kCacheFile(standard::cachefileName());
0064
0065
0066
0067 const std::filesystem::path& kPoisonedCacheFile(standard::poisonedCachefileName());
0068
0069 PluginFactoryManager* pfm = PluginFactoryManager::get();
0070 pfm->newFactory_.connect(std::bind(std::mem_fn(&PluginManager::newFactory), this, _1));
0071
0072
0073
0074
0075 for (PluginFactoryManager::const_iterator i = pfm->begin(), e = pfm->end(); i != e; ++i) {
0076 categoryToInfos_[(*i)->category()] = (*i)->available();
0077 }
0078
0079
0080
0081
0082 bool foundAtLeastOneCacheFile = false;
0083 std::set<std::string> alreadySeen;
0084 for (SearchPath::const_iterator itPath = searchPath_.begin(), itEnd = searchPath_.end(); itPath != itEnd;
0085 ++itPath) {
0086
0087 if (alreadySeen.find(*itPath) != alreadySeen.end()) {
0088 continue;
0089 }
0090 alreadySeen.insert(*itPath);
0091 std::filesystem::path dir(*itPath);
0092 if (exists(dir)) {
0093 if (not is_directory(dir)) {
0094 throw cms::Exception("PluginManagerBadPath")
0095 << "The path '" << dir.string() << "' for the PluginManager is not a directory";
0096 }
0097 std::filesystem::path cacheFile = dir / kCacheFile;
0098
0099 if (readCacheFile(cacheFile, dir, categoryToInfos_)) {
0100 foundAtLeastOneCacheFile = true;
0101 }
0102
0103
0104
0105 std::filesystem::path poisonedCacheFile = dir / kPoisonedCacheFile;
0106 readCacheFile(poisonedCacheFile, dir / "poisoned", categoryToInfos_);
0107 }
0108 }
0109 if (not foundAtLeastOneCacheFile and iConfig.mustHaveCache()) {
0110 auto ex = cms::Exception("PluginManagerNoCacheFile")
0111 << "No cache files named '" << standard::cachefileName() << "' were found in the directories \n";
0112 for (auto const& seen : alreadySeen) {
0113 ex << " '" << seen << "'\n";
0114 }
0115 throw ex;
0116 }
0117 if (iConfig.mustHaveCache() and categoryToInfos_.empty()) {
0118 throw cms::Exception("PluginManagerCacheFilesEmpty") << "Cache files were found but all were empty.";
0119 }
0120
0121 loadingLibraryNamed_() = "<loaded by another plugin system>";
0122 }
0123
0124
0125
0126
0127
0128
0129 PluginManager::~PluginManager() {}
0130
0131
0132
0133
0134
0135
0136
0137
0138
0139
0140
0141
0142
0143
0144
0145
0146 void PluginManager::newFactory(const PluginFactoryBase*) {}
0147
0148
0149
0150 namespace {
0151 struct PICompare {
0152 bool operator()(const PluginInfo& iLHS, const PluginInfo& iRHS) const { return iLHS.name_ < iRHS.name_; }
0153 };
0154 }
0155
0156 const std::filesystem::path& PluginManager::loadableFor(const std::string& iCategory, const std::string& iPlugin) {
0157 bool throwIfFail = true;
0158 return loadableFor_(iCategory, iPlugin, throwIfFail);
0159 }
0160
0161 const std::filesystem::path& PluginManager::loadableFor_(const std::string& iCategory,
0162 const std::string& iPlugin,
0163 bool& ioThrowIfFailElseSucceedStatus) {
0164 const bool throwIfFail = ioThrowIfFailElseSucceedStatus;
0165 ioThrowIfFailElseSucceedStatus = true;
0166 CategoryToInfos::iterator itFound = categoryToInfos_.find(iCategory);
0167 if (itFound == categoryToInfos_.end()) {
0168 if (throwIfFail) {
0169 throw cms::Exception("PluginNotFound") << "Unable to find plugin '" << iPlugin << "' because the category '"
0170 << iCategory << "' has no known plugins";
0171 } else {
0172 ioThrowIfFailElseSucceedStatus = false;
0173 static const std::filesystem::path s_path;
0174 return s_path;
0175 }
0176 }
0177
0178 PluginInfo i;
0179 i.name_ = iPlugin;
0180 typedef std::vector<PluginInfo>::iterator PIItr;
0181 std::pair<PIItr, PIItr> range = std::equal_range(itFound->second.begin(), itFound->second.end(), i, PICompare());
0182
0183 if (range.first == range.second) {
0184 if (throwIfFail) {
0185 throw cms::Exception("PluginNotFound") << "Unable to find plugin '" << iPlugin << "' in category '" << iCategory
0186 << "'. Please check spelling of name.";
0187 } else {
0188 ioThrowIfFailElseSucceedStatus = false;
0189 static const std::filesystem::path s_path;
0190 return s_path;
0191 }
0192 }
0193
0194 if (range.second - range.first > 1) {
0195
0196 if (range.first->loadable_.parent_path() == (range.first + 1)->loadable_.parent_path()) {
0197
0198 throw cms::Exception("MultiplePlugins")
0199 << "The plugin '" << iPlugin
0200 << "' is found in multiple files \n"
0201 " '"
0202 << range.first->loadable_.filename() << "'\n '" << (range.first + 1)->loadable_.filename()
0203 << "'\n"
0204 "in directory '"
0205 << range.first->loadable_.parent_path().string()
0206 << "'.\n"
0207 "The code must be changed so the plugin only appears in one plugin file. "
0208 "You will need to remove the macro which registers the plugin so it only appears in"
0209 " one of these files.\n"
0210 " If none of these files register such a plugin, "
0211 "then the problem originates in a library to which all these files link.\n"
0212 "The plugin registration must be removed from that library since plugins are not allowed in regular "
0213 "libraries.";
0214 }
0215 }
0216
0217 return range.first->loadable_;
0218 }
0219
0220 namespace {
0221 class Sentry {
0222 public:
0223 Sentry(std::string& iPath, const std::string& iNewPath) : path_(iPath), oldPath_(iPath) { path_ = iNewPath; }
0224 ~Sentry() { path_ = oldPath_; }
0225
0226 private:
0227 std::string& path_;
0228 std::string oldPath_;
0229 };
0230 }
0231
0232 const SharedLibrary& PluginManager::load(const std::string& iCategory, const std::string& iPlugin) {
0233 askedToLoadCategoryWithPlugin_(iCategory, iPlugin);
0234 const std::filesystem::path& p = loadableFor(iCategory, iPlugin);
0235
0236
0237 auto itLoaded = loadables_.find(p);
0238 if (itLoaded == loadables_.end()) {
0239
0240 std::lock_guard<std::recursive_mutex> guard(pluginLoadMutex());
0241
0242 itLoaded = loadables_.find(p);
0243 if (itLoaded == loadables_.end()) {
0244
0245 goingToLoad_(p);
0246 Sentry s(loadingLibraryNamed_(), p.string());
0247
0248 std::shared_ptr<SharedLibrary> ptr;
0249 {
0250
0251
0252 R__LOCKGUARD2(gInterpreterMutex);
0253 try {
0254 ptr = std::make_shared<SharedLibrary>(p);
0255 } catch (cms::Exception& e) {
0256 e.addContext("While attempting to load plugin " + iPlugin);
0257 throw;
0258 }
0259 }
0260 loadables_.emplace(p, ptr);
0261 justLoaded_(*ptr);
0262 return *ptr;
0263 }
0264 }
0265 return *(itLoaded->second);
0266 }
0267
0268 const SharedLibrary* PluginManager::tryToLoad(const std::string& iCategory, const std::string& iPlugin) {
0269 askedToLoadCategoryWithPlugin_(iCategory, iPlugin);
0270 bool ioThrowIfFailElseSucceedStatus = false;
0271 const std::filesystem::path& p = loadableFor_(iCategory, iPlugin, ioThrowIfFailElseSucceedStatus);
0272
0273 if (not ioThrowIfFailElseSucceedStatus) {
0274 return nullptr;
0275 }
0276
0277
0278 auto itLoaded = loadables_.find(p);
0279 if (itLoaded == loadables_.end()) {
0280
0281 std::lock_guard<std::recursive_mutex> guard(pluginLoadMutex());
0282
0283 itLoaded = loadables_.find(p);
0284 if (itLoaded == loadables_.end()) {
0285
0286 goingToLoad_(p);
0287 Sentry s(loadingLibraryNamed_(), p.string());
0288
0289 std::shared_ptr<SharedLibrary> ptr;
0290 {
0291
0292
0293 R__LOCKGUARD(gInterpreterMutex);
0294 try {
0295 ptr = std::make_shared<SharedLibrary>(p);
0296 } catch (cms::Exception& e) {
0297 e.addContext("While attempting to load plugin " + iPlugin);
0298 throw;
0299 }
0300 }
0301 loadables_[p] = ptr;
0302 justLoaded_(*ptr);
0303 return ptr.get();
0304 }
0305 }
0306 return (itLoaded->second).get();
0307 }
0308
0309
0310
0311
0312 PluginManager* PluginManager::get() {
0313 PluginManager* manager = singleton();
0314 if (nullptr == manager) {
0315 throw cms::Exception("PluginManagerNotConfigured")
0316 << "PluginManager::get() was called before PluginManager::configure.";
0317 }
0318 return manager;
0319 }
0320
0321 PluginManager& PluginManager::configure(const Config& iConfig) {
0322 PluginManager*& s = singleton();
0323 if (nullptr != s) {
0324 throw cms::Exception("PluginManagerReconfigured");
0325 }
0326
0327 const Config& realConfig = iConfig;
0328 if (realConfig.searchPath().empty()) {
0329 throw cms::Exception("PluginManagerEmptySearchPath");
0330 }
0331 s = new PluginManager(realConfig);
0332 return *s;
0333 }
0334
0335 const std::string& PluginManager::staticallyLinkedLoadingFileName() {
0336 static const std::string s_name("static");
0337 return s_name;
0338 }
0339
0340 std::string& PluginManager::loadingLibraryNamed_() {
0341
0342
0343 CMS_THREAD_SAFE static std::string s_name(staticallyLinkedLoadingFileName());
0344 return s_name;
0345 }
0346
0347 PluginManager*& PluginManager::singleton() {
0348 CMS_THREAD_SAFE static PluginManager* s_singleton = nullptr;
0349 return s_singleton;
0350 }
0351
0352 bool PluginManager::isAvailable() { return nullptr != singleton(); }
0353
0354 }