1 //===---- SimpleRemoteEPC.h - Simple remote executor control ----*- 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 // Simple remote executor process control.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #ifndef LLVM_EXECUTIONENGINE_ORC_SIMPLEREMOTEEPC_H
14 #define LLVM_EXECUTIONENGINE_ORC_SIMPLEREMOTEEPC_H
15 
16 #include "llvm/ADT/DenseMap.h"
17 #include "llvm/ADT/FunctionExtras.h"
18 #include "llvm/ExecutionEngine/Orc/EPCGenericDylibManager.h"
19 #include "llvm/ExecutionEngine/Orc/EPCGenericJITLinkMemoryManager.h"
20 #include "llvm/ExecutionEngine/Orc/EPCGenericMemoryAccess.h"
21 #include "llvm/ExecutionEngine/Orc/ExecutorProcessControl.h"
22 #include "llvm/ExecutionEngine/Orc/Shared/SimpleRemoteEPCUtils.h"
23 #include "llvm/Support/Error.h"
24 #include "llvm/Support/MSVCErrorWorkarounds.h"
25 
26 #include <future>
27 
28 namespace llvm {
29 namespace orc {
30 
31 class SimpleRemoteEPC : public ExecutorProcessControl,
32                         public SimpleRemoteEPCTransportClient {
33 public:
34   /// A setup object containing callbacks to construct a memory manager and
35   /// memory access object. Both are optional. If not specified,
36   /// EPCGenericJITLinkMemoryManager and EPCGenericMemoryAccess will be used.
37   struct Setup {
38     using CreateMemoryManagerFn =
39         Expected<std::unique_ptr<jitlink::JITLinkMemoryManager>>(
40             SimpleRemoteEPC &);
41     using CreateMemoryAccessFn =
42         Expected<std::unique_ptr<MemoryAccess>>(SimpleRemoteEPC &);
43 
44     unique_function<CreateMemoryManagerFn> CreateMemoryManager;
45     unique_function<CreateMemoryAccessFn> CreateMemoryAccess;
46   };
47 
48   /// Create a SimpleRemoteEPC using the given transport type and args.
49   template <typename TransportT, typename... TransportTCtorArgTs>
50   static Expected<std::unique_ptr<SimpleRemoteEPC>>
51   Create(std::unique_ptr<TaskDispatcher> D, Setup S,
52          TransportTCtorArgTs &&...TransportTCtorArgs) {
53     std::unique_ptr<SimpleRemoteEPC> SREPC(
54         new SimpleRemoteEPC(std::make_shared<SymbolStringPool>(),
55                             std::move(D)));
56     auto T = TransportT::Create(
57         *SREPC, std::forward<TransportTCtorArgTs>(TransportTCtorArgs)...);
58     if (!T)
59       return T.takeError();
60     SREPC->T = std::move(*T);
61     if (auto Err = SREPC->setup(std::move(S)))
62       return joinErrors(std::move(Err), SREPC->disconnect());
63     return std::move(SREPC);
64   }
65 
66   SimpleRemoteEPC(const SimpleRemoteEPC &) = delete;
67   SimpleRemoteEPC &operator=(const SimpleRemoteEPC &) = delete;
68   SimpleRemoteEPC(SimpleRemoteEPC &&) = delete;
69   SimpleRemoteEPC &operator=(SimpleRemoteEPC &&) = delete;
70   ~SimpleRemoteEPC();
71 
72   Expected<tpctypes::DylibHandle> loadDylib(const char *DylibPath) override;
73 
74   Expected<std::vector<tpctypes::LookupResult>>
75   lookupSymbols(ArrayRef<LookupRequest> Request) override;
76 
77   Expected<int32_t> runAsMain(ExecutorAddr MainFnAddr,
78                               ArrayRef<std::string> Args) override;
79 
80   Expected<int32_t> runAsVoidFunction(ExecutorAddr VoidFnAddr) override;
81 
82   Expected<int32_t> runAsIntFunction(ExecutorAddr IntFnAddr, int Arg) override;
83 
84   void callWrapperAsync(ExecutorAddr WrapperFnAddr,
85                         IncomingWFRHandler OnComplete,
86                         ArrayRef<char> ArgBuffer) override;
87 
88   Error disconnect() override;
89 
90   Expected<HandleMessageAction>
91   handleMessage(SimpleRemoteEPCOpcode OpC, uint64_t SeqNo, ExecutorAddr TagAddr,
92                 SimpleRemoteEPCArgBytesVector ArgBytes) override;
93 
94   void handleDisconnect(Error Err) override;
95 
96 private:
97   SimpleRemoteEPC(std::shared_ptr<SymbolStringPool> SSP,
98                   std::unique_ptr<TaskDispatcher> D)
99     : ExecutorProcessControl(std::move(SSP), std::move(D)) {}
100 
101   static Expected<std::unique_ptr<jitlink::JITLinkMemoryManager>>
102   createDefaultMemoryManager(SimpleRemoteEPC &SREPC);
103   static Expected<std::unique_ptr<MemoryAccess>>
104   createDefaultMemoryAccess(SimpleRemoteEPC &SREPC);
105 
106   Error sendMessage(SimpleRemoteEPCOpcode OpC, uint64_t SeqNo,
107                     ExecutorAddr TagAddr, ArrayRef<char> ArgBytes);
108 
109   Error handleSetup(uint64_t SeqNo, ExecutorAddr TagAddr,
110                     SimpleRemoteEPCArgBytesVector ArgBytes);
111   Error setup(Setup S);
112 
113   Error handleResult(uint64_t SeqNo, ExecutorAddr TagAddr,
114                      SimpleRemoteEPCArgBytesVector ArgBytes);
115   void handleCallWrapper(uint64_t RemoteSeqNo, ExecutorAddr TagAddr,
116                          SimpleRemoteEPCArgBytesVector ArgBytes);
117   Error handleHangup(SimpleRemoteEPCArgBytesVector ArgBytes);
118 
119   uint64_t getNextSeqNo() { return NextSeqNo++; }
120   void releaseSeqNo(uint64_t SeqNo) {}
121 
122   using PendingCallWrapperResultsMap =
123     DenseMap<uint64_t, IncomingWFRHandler>;
124 
125   std::mutex SimpleRemoteEPCMutex;
126   std::condition_variable DisconnectCV;
127   bool Disconnected = false;
128   Error DisconnectErr = Error::success();
129 
130   std::unique_ptr<SimpleRemoteEPCTransport> T;
131   std::unique_ptr<jitlink::JITLinkMemoryManager> OwnedMemMgr;
132   std::unique_ptr<MemoryAccess> OwnedMemAccess;
133 
134   std::unique_ptr<EPCGenericDylibManager> DylibMgr;
135   ExecutorAddr RunAsMainAddr;
136   ExecutorAddr RunAsVoidFunctionAddr;
137   ExecutorAddr RunAsIntFunctionAddr;
138 
139   uint64_t NextSeqNo = 0;
140   PendingCallWrapperResultsMap PendingCallWrapperResults;
141 };
142 
143 } // end namespace orc
144 } // end namespace llvm
145 
146 #endif // LLVM_EXECUTIONENGINE_ORC_SIMPLEREMOTEEPC_H
147