ControllerAccess provides an abstract interface for bidirectional RPC between the executor (running JIT'd code) and the controller (containing the llvm::orc::ExecutionSession). ControllerAccess implementations are expected to implement IPC / RPC using a concrete communication method (shared memory, pipes, sockets, native system IPC, etc). Calls from executor to controller are made via callController, with "handler tags" (addresses in the executor) specifying the target handler in the controller. A handler must be associated in the controller with the given tag for the call to succeed. This ensures that only registered entry points in the controller can be used, and avoids leaking controller addresses into the executor. Calls in both directions are to "wrapper functions" that take a buffer of bytes as input and return a buffer of bytes as output. In the ORC runtime these must be `orc_rt_WrapperFunction`s (see Session::handleWrapperCall). The interpretation of the byte buffers is up to the wrapper functions: the ORC runtime imposes no restrictions on how the bytes are to be interpreted. ControllerAccess objects may be detached from the Session prior to Session shutdown, in which case no further calls may be made in either direction, and any pending results (from calls made that haven't returned yet) should return errors. If the ControllerAccess class is still attached at Session shutdown time it will be detached as part of the shutdown process. The ControllerAccess::disconnect method must support concurrent entry on multiple threads, and all callers must block until they can guarantee that no further calls will be received or accepted.
107 lines
2.8 KiB
C++
107 lines
2.8 KiB
C++
//===- Session.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
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// Contains the implementation of the Session class and related APIs.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "orc-rt/Session.h"
|
|
|
|
namespace orc_rt {
|
|
|
|
Session::ControllerAccess::~ControllerAccess() = default;
|
|
|
|
Session::~Session() { waitForShutdown(); }
|
|
|
|
void Session::shutdown(OnShutdownCompleteFn OnShutdownComplete) {
|
|
// Safe to call concurrently / redundantly.
|
|
detachFromController();
|
|
|
|
{
|
|
std::scoped_lock<std::mutex> Lock(M);
|
|
if (SI) {
|
|
SI->OnCompletes.push_back(std::move(OnShutdownComplete));
|
|
return;
|
|
}
|
|
|
|
SI = std::make_unique<ShutdownInfo>();
|
|
SI->OnCompletes.push_back(std::move(OnShutdownComplete));
|
|
std::swap(SI->ResourceMgrs, ResourceMgrs);
|
|
}
|
|
|
|
shutdownNext(Error::success());
|
|
}
|
|
|
|
void Session::waitForShutdown() {
|
|
shutdown([]() {});
|
|
std::unique_lock<std::mutex> Lock(M);
|
|
SI->CompleteCV.wait(Lock, [&]() { return SI->Complete; });
|
|
}
|
|
|
|
void Session::addResourceManager(std::unique_ptr<ResourceManager> RM) {
|
|
std::scoped_lock<std::mutex> Lock(M);
|
|
assert(!SI && "addResourceManager called after shutdown");
|
|
ResourceMgrs.push_back(std::move(RM));
|
|
}
|
|
|
|
void Session::setController(std::shared_ptr<ControllerAccess> CA) {
|
|
assert(CA && "Cannot attach null controller");
|
|
std::scoped_lock<std::mutex> Lock(M);
|
|
assert(!this->CA && "Cannot re-attach controller");
|
|
assert(!SI && "Cannot attach controller after shutdown");
|
|
this->CA = std::move(CA);
|
|
}
|
|
|
|
void Session::detachFromController() {
|
|
if (auto TmpCA = CA) {
|
|
TmpCA->doDisconnect();
|
|
CA = nullptr;
|
|
}
|
|
}
|
|
|
|
void Session::shutdownNext(Error Err) {
|
|
if (Err)
|
|
reportError(std::move(Err));
|
|
|
|
if (SI->ResourceMgrs.empty())
|
|
return shutdownComplete();
|
|
|
|
// Get the next ResourceManager to shut down.
|
|
auto NextRM = std::move(SI->ResourceMgrs.back());
|
|
SI->ResourceMgrs.pop_back();
|
|
NextRM->shutdown([this](Error Err) { shutdownNext(std::move(Err)); });
|
|
}
|
|
|
|
void Session::shutdownComplete() {
|
|
|
|
std::unique_ptr<TaskDispatcher> TmpDispatcher;
|
|
{
|
|
std::lock_guard<std::mutex> Lock(M);
|
|
TmpDispatcher = std::move(Dispatcher);
|
|
}
|
|
|
|
TmpDispatcher->shutdown();
|
|
|
|
for (auto &OnShutdownComplete : SI->OnCompletes)
|
|
OnShutdownComplete();
|
|
|
|
{
|
|
std::lock_guard<std::mutex> Lock(M);
|
|
SI->Complete = true;
|
|
}
|
|
|
|
SI->CompleteCV.notify_all();
|
|
}
|
|
|
|
void Session::wrapperReturn(orc_rt_SessionRef S, uint64_t CallId,
|
|
orc_rt_WrapperFunctionBuffer ResultBytes) {
|
|
unwrap(S)->sendWrapperResult(CallId, ResultBytes);
|
|
}
|
|
|
|
} // namespace orc_rt
|