blob: c5d71e9b4b083f1887f833f6af3b4c7d91f8e59b [file]
//===- 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 <algorithm>
#include <sstream>
#if defined(__APPLE__) || defined(__linux__)
#include "Unix/NativeDylibAPIs.inc"
#else
#error "Target OS dylib APIs unsupported"
#endif
namespace orc_rt {
Expected<std::unique_ptr<NativeDylibManager>>
NativeDylibManager::Create(Session &S, SimpleSymbolTable &ST,
const char *InstanceName,
SimpleSymbolTable::MutatorFn AddInterface) {
std::unique_ptr<NativeDylibManager> Instance(new NativeDylibManager(S));
SimpleSymbolTable NDMST;
if (auto Err = AddInterface(NDMST))
return Err;
std::pair<const char *, const void *> InstanceSym[] = {
{InstanceName, static_cast<const void *>(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<std::mutex> 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<std::mutex> 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<StringError>(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<StringError>(ErrMsg.str()));
return;
}
--LI.RefCount;
Lock.unlock();
OnComplete(hostOSUnloadLibrary(Handle));
}
void NativeDylibManager::lookup(OnLookupCompleteFn &&OnLookupComplete,
void *Handle, std::vector<std::string> Names) {
{
std::unique_lock<std::mutex> 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<StringError>(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<StringError>(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<void *> 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