diff --git a/openmp/libomptarget/include/device.h b/openmp/libomptarget/include/device.h --- a/openmp/libomptarget/include/device.h +++ b/openmp/libomptarget/include/device.h @@ -22,6 +22,7 @@ #include #include #include +#include #include "ExclusiveAccess.h" #include "omptarget.h" @@ -530,6 +531,33 @@ /// Flag to indicate if we use events to ensure the atomicity of /// map clauses or not. Can be modified with an environment variable. const bool UseEventsForAtomicTransfers; + + // Work around for plugins that call dlopen on shared libraries that call + // tgt_register_lib during their initialisation. Stash the pointers in a + // vector until the plugins are all initialised and then register them. + + bool maybeDelayRegisterLib(__tgt_bin_desc *Desc) { + if (!RTLsLoaded) { + // Only reachable from libomptarget constructor + DelayedBinDesc.push_back(Desc); + return true; + } else { + return false; + } + } + + void registerDelayedLibraries() { + // Only called from libomptarget constructor, i.e. from one thread + for (auto *Desc : DelayedBinDesc) { + __tgt_register_lib(Desc); + } + DelayedBinDesc.clear(); + RTLsLoaded = true; + } + +private: + std::atomic_bool RTLsLoaded = false; + llvm::SmallVector<__tgt_bin_desc *> DelayedBinDesc; }; extern PluginManager *PM; diff --git a/openmp/libomptarget/src/interface.cpp b/openmp/libomptarget/src/interface.cpp --- a/openmp/libomptarget/src/interface.cpp +++ b/openmp/libomptarget/src/interface.cpp @@ -35,7 +35,9 @@ /// adds a target shared library to the target execution image EXTERN void __tgt_register_lib(__tgt_bin_desc *Desc) { TIMESCOPE(); - std::call_once(PM->RTLs.InitFlag, &RTLsTy::loadRTLs, &PM->RTLs); + if (PM->maybeDelayRegisterLib(Desc)) { + return; + } for (auto &RTL : PM->RTLs.AllRTLs) { if (RTL.register_lib) { if ((*RTL.register_lib)(Desc) != OFFLOAD_SUCCESS) { diff --git a/openmp/libomptarget/src/rtl.cpp b/openmp/libomptarget/src/rtl.cpp --- a/openmp/libomptarget/src/rtl.cpp +++ b/openmp/libomptarget/src/rtl.cpp @@ -39,11 +39,16 @@ /* Remote target */ "libomptarget.rtl.rpc", }; -PluginManager *PM; +PluginManager *PM = nullptr; static char *ProfileTraceFile = nullptr; __attribute__((constructor(101))) void init() { + if (PM != nullptr) { + // In case one of the plugins chooses to call back into this constructor + return; + } + DP("Init target library!\n"); bool UseEventsForAtomicTransfers = true; @@ -64,11 +69,15 @@ // TODO: add a configuration option for time granularity if (ProfileTraceFile) timeTraceProfilerInitialize(500 /* us */, "libomptarget"); + + PM->RTLs.loadRTLs(); + PM->registerDelayedLibraries(); } __attribute__((destructor(101))) void deinit() { DP("Deinit target library!\n"); delete PM; + PM = nullptr; if (ProfileTraceFile) { // TODO: add env var for file output