1//===---- SimpleRemoteEPCServer.h - EPC over abstract channel ---*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// EPC over simple abstract channel.
10//
11//===----------------------------------------------------------------------===//
12
13#ifndef LLVM_EXECUTIONENGINE_ORC_TARGETPROCESS_SIMPLEREMOTEEPCSERVER_H
14#define LLVM_EXECUTIONENGINE_ORC_TARGETPROCESS_SIMPLEREMOTEEPCSERVER_H
15
16#include "llvm/ADT/DenseMap.h"
17#include "llvm/ADT/FunctionExtras.h"
18#include "llvm/Config/llvm-config.h"
19#include "llvm/ExecutionEngine/Orc/Shared/SimpleRemoteEPCUtils.h"
20#include "llvm/ExecutionEngine/Orc/Shared/TargetProcessControlTypes.h"
21#include "llvm/ExecutionEngine/Orc/Shared/WrapperFunctionUtils.h"
22#include "llvm/ExecutionEngine/Orc/TargetProcess/ExecutorBootstrapService.h"
23#include "llvm/ExecutionEngine/Orc/TargetProcess/SimpleExecutorDylibManager.h"
24#include "llvm/Support/DynamicLibrary.h"
25#include "llvm/Support/Error.h"
26
27#include <condition_variable>
28#include <future>
29#include <memory>
30#include <mutex>
31
32namespace llvm {
33namespace orc {
34
35/// A simple EPC server implementation.
36class SimpleRemoteEPCServer : public SimpleRemoteEPCTransportClient {
37public:
38  using ReportErrorFunction = unique_function<void(Error)>;
39
40  /// Dispatches calls to runWrapper.
41  class Dispatcher {
42  public:
43    virtual ~Dispatcher();
44    virtual void dispatch(unique_function<void()> Work) = 0;
45    virtual void shutdown() = 0;
46  };
47
48#if LLVM_ENABLE_THREADS
49  class ThreadDispatcher : public Dispatcher {
50  public:
51    void dispatch(unique_function<void()> Work) override;
52    void shutdown() override;
53
54  private:
55    std::mutex DispatchMutex;
56    bool Running = true;
57    size_t Outstanding = 0;
58    std::condition_variable OutstandingCV;
59  };
60#endif
61
62  class Setup {
63    friend class SimpleRemoteEPCServer;
64
65  public:
66    SimpleRemoteEPCServer &server() { return S; }
67    StringMap<ExecutorAddr> &bootstrapSymbols() { return BootstrapSymbols; }
68    std::vector<std::unique_ptr<ExecutorBootstrapService>> &services() {
69      return Services;
70    }
71    void setDispatcher(std::unique_ptr<Dispatcher> D) { S.D = std::move(D); }
72    void setErrorReporter(unique_function<void(Error)> ReportError) {
73      S.ReportError = std::move(ReportError);
74    }
75
76  private:
77    Setup(SimpleRemoteEPCServer &S) : S(S) {}
78    SimpleRemoteEPCServer &S;
79    StringMap<ExecutorAddr> BootstrapSymbols;
80    std::vector<std::unique_ptr<ExecutorBootstrapService>> Services;
81  };
82
83  static StringMap<ExecutorAddr> defaultBootstrapSymbols();
84
85  template <typename TransportT, typename... TransportTCtorArgTs>
86  static Expected<std::unique_ptr<SimpleRemoteEPCServer>>
87  Create(unique_function<Error(Setup &S)> SetupFunction,
88         TransportTCtorArgTs &&...TransportTCtorArgs) {
89    auto Server = std::make_unique<SimpleRemoteEPCServer>();
90    Setup S(*Server);
91    if (auto Err = SetupFunction(S))
92      return std::move(Err);
93
94    // Set ReportError up-front so that it can be used if construction
95    // process fails.
96    if (!Server->ReportError)
97      Server->ReportError = [](Error Err) {
98        logAllUnhandledErrors(std::move(Err), errs(), "SimpleRemoteEPCServer ");
99      };
100
101    // Attempt to create transport.
102    auto T = TransportT::Create(
103        *Server, std::forward<TransportTCtorArgTs>(TransportTCtorArgs)...);
104    if (!T)
105      return T.takeError();
106    Server->T = std::move(*T);
107    if (auto Err = Server->T->start())
108      return std::move(Err);
109
110    // If transport creation succeeds then start up services.
111    Server->Services = std::move(S.services());
112    Server->Services.push_back(
113        std::make_unique<rt_bootstrap::SimpleExecutorDylibManager>());
114    for (auto &Service : Server->Services)
115      Service->addBootstrapSymbols(S.bootstrapSymbols());
116
117    if (auto Err = Server->sendSetupMessage(std::move(S.BootstrapSymbols)))
118      return std::move(Err);
119    return std::move(Server);
120  }
121
122  /// Set an error reporter for this server.
123  void setErrorReporter(ReportErrorFunction ReportError) {
124    this->ReportError = std::move(ReportError);
125  }
126
127  /// Call to handle an incoming message.
128  ///
129  /// Returns 'Disconnect' if the message is a 'detach' message from the remote
130  /// otherwise returns 'Continue'. If the server has moved to an error state,
131  /// returns an error, which should be reported and treated as a 'Disconnect'.
132  Expected<HandleMessageAction>
133  handleMessage(SimpleRemoteEPCOpcode OpC, uint64_t SeqNo, ExecutorAddr TagAddr,
134                SimpleRemoteEPCArgBytesVector ArgBytes) override;
135
136  Error waitForDisconnect();
137
138  void handleDisconnect(Error Err) override;
139
140private:
141  Error sendMessage(SimpleRemoteEPCOpcode OpC, uint64_t SeqNo,
142                    ExecutorAddr TagAddr, ArrayRef<char> ArgBytes);
143
144  Error sendSetupMessage(StringMap<ExecutorAddr> BootstrapSymbols);
145
146  Error handleResult(uint64_t SeqNo, ExecutorAddr TagAddr,
147                     SimpleRemoteEPCArgBytesVector ArgBytes);
148  void handleCallWrapper(uint64_t RemoteSeqNo, ExecutorAddr TagAddr,
149                         SimpleRemoteEPCArgBytesVector ArgBytes);
150
151  shared::WrapperFunctionResult
152  doJITDispatch(const void *FnTag, const char *ArgData, size_t ArgSize);
153
154  static shared::CWrapperFunctionResult jitDispatchEntry(void *DispatchCtx,
155                                                         const void *FnTag,
156                                                         const char *ArgData,
157                                                         size_t ArgSize);
158
159  uint64_t getNextSeqNo() { return NextSeqNo++; }
160  void releaseSeqNo(uint64_t) {}
161
162  using PendingJITDispatchResultsMap =
163      DenseMap<uint64_t, std::promise<shared::WrapperFunctionResult> *>;
164
165  std::mutex ServerStateMutex;
166  std::condition_variable ShutdownCV;
167  enum { ServerRunning, ServerShuttingDown, ServerShutDown } RunState;
168  Error ShutdownErr = Error::success();
169  std::unique_ptr<SimpleRemoteEPCTransport> T;
170  std::unique_ptr<Dispatcher> D;
171  std::vector<std::unique_ptr<ExecutorBootstrapService>> Services;
172  ReportErrorFunction ReportError;
173
174  uint64_t NextSeqNo = 0;
175  PendingJITDispatchResultsMap PendingJITDispatchResults;
176  std::vector<sys::DynamicLibrary> Dylibs;
177};
178
179} // end namespace orc
180} // end namespace llvm
181
182#endif // LLVM_EXECUTIONENGINE_ORC_TARGETPROCESS_SIMPLEREMOTEEPCSERVER_H
183