blob: afd3d39dbb53a6dd21c458e82d57285ca4677364 [file] [log] [blame]
//===---- SimpleRemoteEPCServer.h - EPC over abstract channel ---*- C++ -*-===//
//
// 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
//
//===----------------------------------------------------------------------===//
//
// EPC over simple abstract channel.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_EXECUTIONENGINE_ORC_TARGETPROCESS_SIMPLEREMOTEEPCSERVER_H
#define LLVM_EXECUTIONENGINE_ORC_TARGETPROCESS_SIMPLEREMOTEEPCSERVER_H
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/FunctionExtras.h"
#include "llvm/Config/llvm-config.h"
#include "llvm/ExecutionEngine/Orc/Shared/SimpleRemoteEPCUtils.h"
#include "llvm/ExecutionEngine/Orc/Shared/TargetProcessControlTypes.h"
#include "llvm/ExecutionEngine/Orc/Shared/WrapperFunctionUtils.h"
#include "llvm/ExecutionEngine/Orc/TargetProcess/ExecutorBootstrapService.h"
#include "llvm/ExecutionEngine/Orc/TargetProcess/SimpleExecutorDylibManager.h"
#include "llvm/Support/DynamicLibrary.h"
#include "llvm/Support/Error.h"
#include <condition_variable>
#include <future>
#include <memory>
#include <mutex>
namespace llvm {
namespace orc {
/// A simple EPC server implementation.
class SimpleRemoteEPCServer : public SimpleRemoteEPCTransportClient {
public:
using ReportErrorFunction = unique_function<void(Error)>;
/// Dispatches calls to runWrapper.
class Dispatcher {
public:
virtual ~Dispatcher();
virtual void dispatch(unique_function<void()> Work) = 0;
virtual void shutdown() = 0;
};
#if LLVM_ENABLE_THREADS
class ThreadDispatcher : public Dispatcher {
public:
void dispatch(unique_function<void()> Work) override;
void shutdown() override;
private:
std::mutex DispatchMutex;
bool Running = true;
size_t Outstanding = 0;
std::condition_variable OutstandingCV;
};
#endif
class Setup {
friend class SimpleRemoteEPCServer;
public:
SimpleRemoteEPCServer &server() { return S; }
StringMap<ExecutorAddr> &bootstrapSymbols() { return BootstrapSymbols; }
std::vector<std::unique_ptr<ExecutorBootstrapService>> &services() {
return Services;
}
void setDispatcher(std::unique_ptr<Dispatcher> D) { S.D = std::move(D); }
void setErrorReporter(unique_function<void(Error)> ReportError) {
S.ReportError = std::move(ReportError);
}
private:
Setup(SimpleRemoteEPCServer &S) : S(S) {}
SimpleRemoteEPCServer &S;
StringMap<ExecutorAddr> BootstrapSymbols;
std::vector<std::unique_ptr<ExecutorBootstrapService>> Services;
};
static StringMap<ExecutorAddr> defaultBootstrapSymbols();
template <typename TransportT, typename... TransportTCtorArgTs>
static Expected<std::unique_ptr<SimpleRemoteEPCServer>>
Create(unique_function<Error(Setup &S)> SetupFunction,
TransportTCtorArgTs &&...TransportTCtorArgs) {
auto Server = std::make_unique<SimpleRemoteEPCServer>();
Setup S(*Server);
if (auto Err = SetupFunction(S))
return std::move(Err);
// Set ReportError up-front so that it can be used if construction
// process fails.
if (!Server->ReportError)
Server->ReportError = [](Error Err) {
logAllUnhandledErrors(std::move(Err), errs(), "SimpleRemoteEPCServer ");
};
// Attempt to create transport.
auto T = TransportT::Create(
*Server, std::forward<TransportTCtorArgTs>(TransportTCtorArgs)...);
if (!T)
return T.takeError();
Server->T = std::move(*T);
if (auto Err = Server->T->start())
return std::move(Err);
// If transport creation succeeds then start up services.
Server->Services = std::move(S.services());
Server->Services.push_back(
std::make_unique<rt_bootstrap::SimpleExecutorDylibManager>());
for (auto &Service : Server->Services)
Service->addBootstrapSymbols(S.bootstrapSymbols());
if (auto Err = Server->sendSetupMessage(std::move(S.BootstrapSymbols)))
return std::move(Err);
return std::move(Server);
}
/// Set an error reporter for this server.
void setErrorReporter(ReportErrorFunction ReportError) {
this->ReportError = std::move(ReportError);
}
/// Call to handle an incoming message.
///
/// Returns 'Disconnect' if the message is a 'detach' message from the remote
/// otherwise returns 'Continue'. If the server has moved to an error state,
/// returns an error, which should be reported and treated as a 'Disconnect'.
Expected<HandleMessageAction>
handleMessage(SimpleRemoteEPCOpcode OpC, uint64_t SeqNo, ExecutorAddr TagAddr,
SimpleRemoteEPCArgBytesVector ArgBytes) override;
Error waitForDisconnect();
void handleDisconnect(Error Err) override;
private:
Error sendMessage(SimpleRemoteEPCOpcode OpC, uint64_t SeqNo,
ExecutorAddr TagAddr, ArrayRef<char> ArgBytes);
Error sendSetupMessage(StringMap<ExecutorAddr> BootstrapSymbols);
Error handleResult(uint64_t SeqNo, ExecutorAddr TagAddr,
SimpleRemoteEPCArgBytesVector ArgBytes);
void handleCallWrapper(uint64_t RemoteSeqNo, ExecutorAddr TagAddr,
SimpleRemoteEPCArgBytesVector ArgBytes);
shared::WrapperFunctionResult
doJITDispatch(const void *FnTag, const char *ArgData, size_t ArgSize);
static shared::CWrapperFunctionResult jitDispatchEntry(void *DispatchCtx,
const void *FnTag,
const char *ArgData,
size_t ArgSize);
uint64_t getNextSeqNo() { return NextSeqNo++; }
void releaseSeqNo(uint64_t) {}
using PendingJITDispatchResultsMap =
DenseMap<uint64_t, std::promise<shared::WrapperFunctionResult> *>;
std::mutex ServerStateMutex;
std::condition_variable ShutdownCV;
enum { ServerRunning, ServerShuttingDown, ServerShutDown } RunState;
Error ShutdownErr = Error::success();
std::unique_ptr<SimpleRemoteEPCTransport> T;
std::unique_ptr<Dispatcher> D;
std::vector<std::unique_ptr<ExecutorBootstrapService>> Services;
ReportErrorFunction ReportError;
uint64_t NextSeqNo = 0;
PendingJITDispatchResultsMap PendingJITDispatchResults;
std::vector<sys::DynamicLibrary> Dylibs;
};
} // end namespace orc
} // end namespace llvm
#endif // LLVM_EXECUTIONENGINE_ORC_TARGETPROCESS_SIMPLEREMOTEEPCSERVER_H