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 @@ -508,4 +508,10 @@ extern PluginManager *PM; +/// Allocate memory and initialize the plugin manager. +void initLibomptarget(bool IncrementCount = true); + +/// Deallocate the plugin manager. +void deinitLibomptarget(); + #endif 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 @@ -25,6 +25,12 @@ /// adds requires flags EXTERN void __tgt_register_requires(int64_t Flags) { TIMESCOPE(); + + // Before we load any libraries we need to make sure that Libomptarget has + // been initialized. This funciton may be called many times and is not + // responsible for deinitialization so don't increase the user count. + initLibomptarget(/* IncrementCount */ false); + PM->RTLs.registerRequires(Flags); } @@ -32,6 +38,11 @@ /// adds a target shared library to the target execution image EXTERN void __tgt_register_lib(__tgt_bin_desc *Desc) { TIMESCOPE(); + + // Before we load any libraries we need to make sure that Libomptarget has + // been initialized. + initLibomptarget(); + std::call_once(PM->RTLs.InitFlag, &RTLsTy::loadRTLs, &PM->RTLs); for (auto &RTL : PM->RTLs.AllRTLs) { if (RTL.register_lib) { @@ -59,6 +70,9 @@ } } } + + // Uninitialize libomptarget once all the libraries have been unloaded. + deinitLibomptarget(); } /// creates host-to-target data mapping, stores it in the diff --git a/openmp/libomptarget/src/omptarget.cpp b/openmp/libomptarget/src/omptarget.cpp --- a/openmp/libomptarget/src/omptarget.cpp +++ b/openmp/libomptarget/src/omptarget.cpp @@ -268,9 +268,9 @@ } static bool isOffloadDisabled() { - if (PM->TargetOffloadPolicy == tgt_default) + if (PM && PM->TargetOffloadPolicy == tgt_default) handleDefaultTargetOffload(); - return PM->TargetOffloadPolicy == tgt_disabled; + return !PM || PM->TargetOffloadPolicy == tgt_disabled; } // If offload is enabled, ensure that device DeviceID has been initialized, 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 @@ -17,6 +17,7 @@ #include "llvm/Object/OffloadBinary.h" #include +#include #include #include #include @@ -34,13 +35,32 @@ /* Remote target */ "libomptarget.rtl.rpc.so", }; -PluginManager *PM; +PluginManager *PM = nullptr; + +// The number of libraries that have been registered by the user. +std::atomic LibraryUsers; #if OMPTARGET_PROFILE_ENABLED static char *ProfileTraceFile = nullptr; #endif -__attribute__((constructor(101))) void init() { +void initLibomptarget(bool IncrementCount) { + // The target library is initialized by the first user to need it. Make sure + // someone has initialized it before we return. + if (LibraryUsers) { + if (IncrementCount) + LibraryUsers++; + + if (PM) + return; + + std::mutex Mtx; + std::unique_lock Lock(Mtx); + std::condition_variable CV; + CV.wait(Lock, []() { return PM; }); + return; + } + DP("Init target library!\n"); bool UseEventsForAtomicTransfers = true; @@ -65,7 +85,11 @@ #endif } -__attribute__((destructor(101))) void deinit() { +void deinitLibomptarget() { + // The target library is uninitialized by the last user. + if (--LibraryUsers) + return; + DP("Deinit target library!\n"); for (auto *R : PM->RTLs.UsedRTLs) {