//===- 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) { assert(OnShutdownComplete && "OnShutdownComplete must be set"); // Safe to call concurrently / redundantly. detachFromController(); { std::scoped_lock Lock(M); if (SI) { // SI exists: someone called shutdown already. If the shutdown is not yet // complete then just add OnShutdownComplete to the list of pending // callbacks for the in-progress shutdown, then return. // (If the shutdown is already complete then we'll run the handler // directly below). if (!SI->Complete) return SI->OnCompletes.push_back(std::move(OnShutdownComplete)); } else { // SI does not exist: We're the first to call shutdown. Create a // ShutdownInfo struct and add OnShutdownComplete to the list of pending // callbacks, then call shutdownNext below (outside the lock). SI = std::make_unique(); SI->OnCompletes.push_back(std::move(OnShutdownComplete)); std::swap(SI->ResourceMgrs, ResourceMgrs); } } // OnShutdownComplete is set (i.e. not moved into the list of pending // callbacks). This can only happen if shutdown is already complete. Call // OnComplete directly and return. if (OnShutdownComplete) return OnShutdownComplete(); // OnShutdownComplete is _not_ set (i.e. was moved into the list of pending // handlers), and we didn't return under the lock above, so we must be // responsible for the shutdown. Call shutdownNext. shutdownNext(Error::success()); } void Session::waitForShutdown() { std::promise P; auto F = P.get_future(); shutdown([P = std::move(P)]() mutable { P.set_value(); }); F.get(); } void Session::addResourceManager(std::unique_ptr RM) { std::scoped_lock Lock(M); assert(!SI && "addResourceManager called after shutdown"); ResourceMgrs.push_back(std::move(RM)); } void Session::setController(std::shared_ptr CA) { assert(CA && "Cannot attach null controller"); std::scoped_lock 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 TmpDispatcher; { std::scoped_lock Lock(M); TmpDispatcher = std::move(Dispatcher); } TmpDispatcher->shutdown(); std::vector OnCompletes; { std::scoped_lock Lock(M); SI->Complete = true; OnCompletes = std::move(SI->OnCompletes); } for (auto &OnShutdownComplete : OnCompletes) OnShutdownComplete(); } void Session::wrapperReturn(orc_rt_SessionRef S, uint64_t CallId, orc_rt_WrapperFunctionBuffer ResultBytes) { unwrap(S)->sendWrapperResult(CallId, WrapperFunctionBuffer(ResultBytes)); } } // namespace orc_rt