//===- NativeDylibManager.cpp ---------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // NativeDylibManager and related APIs. // //===----------------------------------------------------------------------===// #include "orc-rt/NativeDylibManager.h" #include "orc-rt/Session.h" #include #if defined(__APPLE__) || defined(__linux__) #include "Unix/NativeDylibAPIs.inc" #else #error "Target OS dylib APIs unsupported" #endif namespace orc_rt { Expected> NativeDylibManager::Create(Session &S, SimpleSymbolTable &ST, const char *InstanceName, SimpleSymbolTable::MutatorFn AddInterface) { std::unique_ptr Instance(new NativeDylibManager(S)); SimpleSymbolTable NDMST; if (auto Err = AddInterface(NDMST)) return Err; std::pair InstanceSym[] = { {InstanceName, static_cast(Instance.get())}}; if (auto Err = NDMST.addUnique(InstanceSym)) return std::move(Err); if (auto Err = ST.addUnique(NDMST)) return std::move(Err); return std::move(Instance); } void NativeDylibManager::load(OnLoadCompleteFn &&OnComplete, std::string Path) { if (auto H = hostOSLoadLibrary(Path)) { { std::scoped_lock Lock(M); auto &LI = LoadInfos[*H]; if (LI.Ordinal == 0) // new entry. LI.Ordinal = LoadInfos.size(); ++LI.RefCount; } OnComplete(std::move(H)); } else OnComplete(H.takeError()); } void NativeDylibManager::unload(OnUnloadCompleteFn &&OnComplete, void *Handle) { std::unique_lock Lock(M); auto LIItr = LoadInfos.find(Handle); if (LIItr == LoadInfos.end()) { Lock.unlock(); std::ostringstream ErrMsg; ErrMsg << "error: attempt to unload unrecognized handle " << Handle; OnComplete(make_error(ErrMsg.str())); return; } auto &LI = LIItr->second; if (LI.RefCount == 0) { Lock.unlock(); std::ostringstream ErrMsg; ErrMsg << "error: cannot close handle " << Handle << ", refcount is already zero"; OnComplete(make_error(ErrMsg.str())); return; } --LI.RefCount; Lock.unlock(); OnComplete(hostOSUnloadLibrary(Handle)); } void NativeDylibManager::lookup(OnLookupCompleteFn &&OnLookupComplete, void *Handle, std::vector Names) { { std::unique_lock Lock(M); auto LIItr = LoadInfos.find(Handle); if (LIItr == LoadInfos.end()) { Lock.unlock(); std::ostringstream ErrMsg; ErrMsg << "error: cannot perform lookup on unrecognized handle " << Handle; OnLookupComplete(make_error(ErrMsg.str())); return; } if (LIItr->second.RefCount == 0) { Lock.unlock(); std::ostringstream ErrMsg; ErrMsg << "error: cannot perform lookup on closed handle " << Handle; OnLookupComplete(make_error(ErrMsg.str())); return; } } OnLookupComplete(hostOSLibraryLookup(Handle, Names)); } void NativeDylibManager::onDetach(Service::OnCompleteFn OnComplete, bool ShutdownRequested) { // Detach is a noop for now. If/when we add bloom-filter support this will be // a good time to update filters. OnComplete(); } void NativeDylibManager::onShutdown(Service::OnCompleteFn OnComplete) { // Unload in reverse load order (LIFO). std::vector ToUnload; ToUnload.reserve(LoadInfos.size()); for (auto &[Handle, Info] : LoadInfos) ToUnload.push_back(Handle); std::sort(ToUnload.begin(), ToUnload.end(), [this](void *LHS, void *RHS) { assert(LoadInfos.count(LHS)); assert(LoadInfos.count(RHS)); return LoadInfos[LHS].Ordinal < LoadInfos[RHS].Ordinal; }); while (!ToUnload.empty()) { void *H = ToUnload.back(); ToUnload.pop_back(); size_t UnloadCount = LoadInfos[H].RefCount; for (size_t I = 0; I != UnloadCount; ++I) if (auto Err = hostOSUnloadLibrary(H)) S.reportError(std::move(Err)); } OnComplete(); } } // namespace orc_rt