xref: /freebsd/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/SimpleRemoteEPC.cpp (revision 66bee50af774673bfaeb4c66a5a82e0ac99e70a4)
1  //===------- SimpleRemoteEPC.cpp -- Simple remote executor control --------===//
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  #include "llvm/ExecutionEngine/Orc/SimpleRemoteEPC.h"
10  #include "llvm/ExecutionEngine/Orc/EPCGenericJITLinkMemoryManager.h"
11  #include "llvm/ExecutionEngine/Orc/EPCGenericMemoryAccess.h"
12  #include "llvm/ExecutionEngine/Orc/Shared/OrcRTBridge.h"
13  #include "llvm/Support/FormatVariadic.h"
14  
15  #define DEBUG_TYPE "orc"
16  
17  namespace llvm {
18  namespace orc {
19  
20  SimpleRemoteEPC::~SimpleRemoteEPC() {
21  #ifndef NDEBUG
22    std::lock_guard<std::mutex> Lock(SimpleRemoteEPCMutex);
23    assert(Disconnected && "Destroyed without disconnection");
24  #endif // NDEBUG
25  }
26  
27  Expected<tpctypes::DylibHandle>
28  SimpleRemoteEPC::loadDylib(const char *DylibPath) {
29    return DylibMgr->open(DylibPath, 0);
30  }
31  
32  Expected<std::vector<tpctypes::LookupResult>>
33  SimpleRemoteEPC::lookupSymbols(ArrayRef<LookupRequest> Request) {
34    std::vector<tpctypes::LookupResult> Result;
35  
36    for (auto &Element : Request) {
37      if (auto R = DylibMgr->lookup(Element.Handle, Element.Symbols)) {
38        Result.push_back({});
39        Result.back().reserve(R->size());
40        for (auto Addr : *R)
41          Result.back().push_back(Addr);
42      } else
43        return R.takeError();
44    }
45    return std::move(Result);
46  }
47  
48  Expected<int32_t> SimpleRemoteEPC::runAsMain(ExecutorAddr MainFnAddr,
49                                               ArrayRef<std::string> Args) {
50    int64_t Result = 0;
51    if (auto Err = callSPSWrapper<rt::SPSRunAsMainSignature>(
52            RunAsMainAddr, Result, MainFnAddr, Args))
53      return std::move(Err);
54    return Result;
55  }
56  
57  Expected<int32_t> SimpleRemoteEPC::runAsVoidFunction(ExecutorAddr VoidFnAddr) {
58    int32_t Result = 0;
59    if (auto Err = callSPSWrapper<rt::SPSRunAsVoidFunctionSignature>(
60            RunAsVoidFunctionAddr, Result, VoidFnAddr))
61      return std::move(Err);
62    return Result;
63  }
64  
65  Expected<int32_t> SimpleRemoteEPC::runAsIntFunction(ExecutorAddr IntFnAddr,
66                                                      int Arg) {
67    int32_t Result = 0;
68    if (auto Err = callSPSWrapper<rt::SPSRunAsIntFunctionSignature>(
69            RunAsIntFunctionAddr, Result, IntFnAddr, Arg))
70      return std::move(Err);
71    return Result;
72  }
73  
74  void SimpleRemoteEPC::callWrapperAsync(ExecutorAddr WrapperFnAddr,
75                                         IncomingWFRHandler OnComplete,
76                                         ArrayRef<char> ArgBuffer) {
77    uint64_t SeqNo;
78    {
79      std::lock_guard<std::mutex> Lock(SimpleRemoteEPCMutex);
80      SeqNo = getNextSeqNo();
81      assert(!PendingCallWrapperResults.count(SeqNo) && "SeqNo already in use");
82      PendingCallWrapperResults[SeqNo] = std::move(OnComplete);
83    }
84  
85    if (auto Err = sendMessage(SimpleRemoteEPCOpcode::CallWrapper, SeqNo,
86                               WrapperFnAddr, ArgBuffer)) {
87      IncomingWFRHandler H;
88  
89      // We just registered OnComplete, but there may be a race between this
90      // thread returning from sendMessage and handleDisconnect being called from
91      // the transport's listener thread. If handleDisconnect gets there first
92      // then it will have failed 'H' for us. If we get there first (or if
93      // handleDisconnect already ran) then we need to take care of it.
94      {
95        std::lock_guard<std::mutex> Lock(SimpleRemoteEPCMutex);
96        auto I = PendingCallWrapperResults.find(SeqNo);
97        if (I != PendingCallWrapperResults.end()) {
98          H = std::move(I->second);
99          PendingCallWrapperResults.erase(I);
100        }
101      }
102  
103      if (H)
104        H(shared::WrapperFunctionResult::createOutOfBandError("disconnecting"));
105  
106      getExecutionSession().reportError(std::move(Err));
107    }
108  }
109  
110  Error SimpleRemoteEPC::disconnect() {
111    T->disconnect();
112    D->shutdown();
113    std::unique_lock<std::mutex> Lock(SimpleRemoteEPCMutex);
114    DisconnectCV.wait(Lock, [this] { return Disconnected; });
115    return std::move(DisconnectErr);
116  }
117  
118  Expected<SimpleRemoteEPCTransportClient::HandleMessageAction>
119  SimpleRemoteEPC::handleMessage(SimpleRemoteEPCOpcode OpC, uint64_t SeqNo,
120                                 ExecutorAddr TagAddr,
121                                 SimpleRemoteEPCArgBytesVector ArgBytes) {
122  
123    LLVM_DEBUG({
124      dbgs() << "SimpleRemoteEPC::handleMessage: opc = ";
125      switch (OpC) {
126      case SimpleRemoteEPCOpcode::Setup:
127        dbgs() << "Setup";
128        assert(SeqNo == 0 && "Non-zero SeqNo for Setup?");
129        assert(!TagAddr && "Non-zero TagAddr for Setup?");
130        break;
131      case SimpleRemoteEPCOpcode::Hangup:
132        dbgs() << "Hangup";
133        assert(SeqNo == 0 && "Non-zero SeqNo for Hangup?");
134        assert(!TagAddr && "Non-zero TagAddr for Hangup?");
135        break;
136      case SimpleRemoteEPCOpcode::Result:
137        dbgs() << "Result";
138        assert(!TagAddr && "Non-zero TagAddr for Result?");
139        break;
140      case SimpleRemoteEPCOpcode::CallWrapper:
141        dbgs() << "CallWrapper";
142        break;
143      }
144      dbgs() << ", seqno = " << SeqNo << ", tag-addr = " << TagAddr
145             << ", arg-buffer = " << formatv("{0:x}", ArgBytes.size())
146             << " bytes\n";
147    });
148  
149    using UT = std::underlying_type_t<SimpleRemoteEPCOpcode>;
150    if (static_cast<UT>(OpC) > static_cast<UT>(SimpleRemoteEPCOpcode::LastOpC))
151      return make_error<StringError>("Unexpected opcode",
152                                     inconvertibleErrorCode());
153  
154    switch (OpC) {
155    case SimpleRemoteEPCOpcode::Setup:
156      if (auto Err = handleSetup(SeqNo, TagAddr, std::move(ArgBytes)))
157        return std::move(Err);
158      break;
159    case SimpleRemoteEPCOpcode::Hangup:
160      T->disconnect();
161      if (auto Err = handleHangup(std::move(ArgBytes)))
162        return std::move(Err);
163      return EndSession;
164    case SimpleRemoteEPCOpcode::Result:
165      if (auto Err = handleResult(SeqNo, TagAddr, std::move(ArgBytes)))
166        return std::move(Err);
167      break;
168    case SimpleRemoteEPCOpcode::CallWrapper:
169      handleCallWrapper(SeqNo, TagAddr, std::move(ArgBytes));
170      break;
171    }
172    return ContinueSession;
173  }
174  
175  void SimpleRemoteEPC::handleDisconnect(Error Err) {
176    LLVM_DEBUG({
177      dbgs() << "SimpleRemoteEPC::handleDisconnect: "
178             << (Err ? "failure" : "success") << "\n";
179    });
180  
181    PendingCallWrapperResultsMap TmpPending;
182  
183    {
184      std::lock_guard<std::mutex> Lock(SimpleRemoteEPCMutex);
185      std::swap(TmpPending, PendingCallWrapperResults);
186    }
187  
188    for (auto &KV : TmpPending)
189      KV.second(
190          shared::WrapperFunctionResult::createOutOfBandError("disconnecting"));
191  
192    std::lock_guard<std::mutex> Lock(SimpleRemoteEPCMutex);
193    DisconnectErr = joinErrors(std::move(DisconnectErr), std::move(Err));
194    Disconnected = true;
195    DisconnectCV.notify_all();
196  }
197  
198  Expected<std::unique_ptr<jitlink::JITLinkMemoryManager>>
199  SimpleRemoteEPC::createDefaultMemoryManager(SimpleRemoteEPC &SREPC) {
200    EPCGenericJITLinkMemoryManager::SymbolAddrs SAs;
201    if (auto Err = SREPC.getBootstrapSymbols(
202            {{SAs.Allocator, rt::SimpleExecutorMemoryManagerInstanceName},
203             {SAs.Reserve, rt::SimpleExecutorMemoryManagerReserveWrapperName},
204             {SAs.Finalize, rt::SimpleExecutorMemoryManagerFinalizeWrapperName},
205             {SAs.Deallocate,
206              rt::SimpleExecutorMemoryManagerDeallocateWrapperName}}))
207      return std::move(Err);
208  
209    return std::make_unique<EPCGenericJITLinkMemoryManager>(SREPC, SAs);
210  }
211  
212  Expected<std::unique_ptr<ExecutorProcessControl::MemoryAccess>>
213  SimpleRemoteEPC::createDefaultMemoryAccess(SimpleRemoteEPC &SREPC) {
214    return nullptr;
215  }
216  
217  Error SimpleRemoteEPC::sendMessage(SimpleRemoteEPCOpcode OpC, uint64_t SeqNo,
218                                     ExecutorAddr TagAddr,
219                                     ArrayRef<char> ArgBytes) {
220    assert(OpC != SimpleRemoteEPCOpcode::Setup &&
221           "SimpleRemoteEPC sending Setup message? That's the wrong direction.");
222  
223    LLVM_DEBUG({
224      dbgs() << "SimpleRemoteEPC::sendMessage: opc = ";
225      switch (OpC) {
226      case SimpleRemoteEPCOpcode::Hangup:
227        dbgs() << "Hangup";
228        assert(SeqNo == 0 && "Non-zero SeqNo for Hangup?");
229        assert(!TagAddr && "Non-zero TagAddr for Hangup?");
230        break;
231      case SimpleRemoteEPCOpcode::Result:
232        dbgs() << "Result";
233        assert(!TagAddr && "Non-zero TagAddr for Result?");
234        break;
235      case SimpleRemoteEPCOpcode::CallWrapper:
236        dbgs() << "CallWrapper";
237        break;
238      default:
239        llvm_unreachable("Invalid opcode");
240      }
241      dbgs() << ", seqno = " << SeqNo << ", tag-addr = " << TagAddr
242             << ", arg-buffer = " << formatv("{0:x}", ArgBytes.size())
243             << " bytes\n";
244    });
245    auto Err = T->sendMessage(OpC, SeqNo, TagAddr, ArgBytes);
246    LLVM_DEBUG({
247      if (Err)
248        dbgs() << "  \\--> SimpleRemoteEPC::sendMessage failed\n";
249    });
250    return Err;
251  }
252  
253  Error SimpleRemoteEPC::handleSetup(uint64_t SeqNo, ExecutorAddr TagAddr,
254                                     SimpleRemoteEPCArgBytesVector ArgBytes) {
255    if (SeqNo != 0)
256      return make_error<StringError>("Setup packet SeqNo not zero",
257                                     inconvertibleErrorCode());
258  
259    if (TagAddr)
260      return make_error<StringError>("Setup packet TagAddr not zero",
261                                     inconvertibleErrorCode());
262  
263    std::lock_guard<std::mutex> Lock(SimpleRemoteEPCMutex);
264    auto I = PendingCallWrapperResults.find(0);
265    assert(PendingCallWrapperResults.size() == 1 &&
266           I != PendingCallWrapperResults.end() &&
267           "Setup message handler not connectly set up");
268    auto SetupMsgHandler = std::move(I->second);
269    PendingCallWrapperResults.erase(I);
270  
271    auto WFR =
272        shared::WrapperFunctionResult::copyFrom(ArgBytes.data(), ArgBytes.size());
273    SetupMsgHandler(std::move(WFR));
274    return Error::success();
275  }
276  
277  Error SimpleRemoteEPC::setup(Setup S) {
278    using namespace SimpleRemoteEPCDefaultBootstrapSymbolNames;
279  
280    std::promise<MSVCPExpected<SimpleRemoteEPCExecutorInfo>> EIP;
281    auto EIF = EIP.get_future();
282  
283    // Prepare a handler for the setup packet.
284    PendingCallWrapperResults[0] =
285      RunInPlace()(
286        [&](shared::WrapperFunctionResult SetupMsgBytes) {
287          if (const char *ErrMsg = SetupMsgBytes.getOutOfBandError()) {
288            EIP.set_value(
289                make_error<StringError>(ErrMsg, inconvertibleErrorCode()));
290            return;
291          }
292          using SPSSerialize =
293              shared::SPSArgList<shared::SPSSimpleRemoteEPCExecutorInfo>;
294          shared::SPSInputBuffer IB(SetupMsgBytes.data(), SetupMsgBytes.size());
295          SimpleRemoteEPCExecutorInfo EI;
296          if (SPSSerialize::deserialize(IB, EI))
297            EIP.set_value(EI);
298          else
299            EIP.set_value(make_error<StringError>(
300                "Could not deserialize setup message", inconvertibleErrorCode()));
301        });
302  
303    // Start the transport.
304    if (auto Err = T->start())
305      return Err;
306  
307    // Wait for setup packet to arrive.
308    auto EI = EIF.get();
309    if (!EI) {
310      T->disconnect();
311      return EI.takeError();
312    }
313  
314    LLVM_DEBUG({
315      dbgs() << "SimpleRemoteEPC received setup message:\n"
316             << "  Triple: " << EI->TargetTriple << "\n"
317             << "  Page size: " << EI->PageSize << "\n"
318             << "  Bootstrap map" << (EI->BootstrapMap.empty() ? " empty" : ":")
319             << "\n";
320      for (const auto &KV : EI->BootstrapMap)
321        dbgs() << "    " << KV.first() << ": " << KV.second.size()
322               << "-byte SPS encoded buffer\n";
323      dbgs() << "  Bootstrap symbols"
324             << (EI->BootstrapSymbols.empty() ? " empty" : ":") << "\n";
325      for (const auto &KV : EI->BootstrapSymbols)
326        dbgs() << "    " << KV.first() << ": " << KV.second << "\n";
327    });
328    TargetTriple = Triple(EI->TargetTriple);
329    PageSize = EI->PageSize;
330    BootstrapMap = std::move(EI->BootstrapMap);
331    BootstrapSymbols = std::move(EI->BootstrapSymbols);
332  
333    if (auto Err = getBootstrapSymbols(
334            {{JDI.JITDispatchContext, ExecutorSessionObjectName},
335             {JDI.JITDispatchFunction, DispatchFnName},
336             {RunAsMainAddr, rt::RunAsMainWrapperName},
337             {RunAsVoidFunctionAddr, rt::RunAsVoidFunctionWrapperName},
338             {RunAsIntFunctionAddr, rt::RunAsIntFunctionWrapperName}}))
339      return Err;
340  
341    if (auto DM =
342            EPCGenericDylibManager::CreateWithDefaultBootstrapSymbols(*this))
343      DylibMgr = std::make_unique<EPCGenericDylibManager>(std::move(*DM));
344    else
345      return DM.takeError();
346  
347    // Set a default CreateMemoryManager if none is specified.
348    if (!S.CreateMemoryManager)
349      S.CreateMemoryManager = createDefaultMemoryManager;
350  
351    if (auto MemMgr = S.CreateMemoryManager(*this)) {
352      OwnedMemMgr = std::move(*MemMgr);
353      this->MemMgr = OwnedMemMgr.get();
354    } else
355      return MemMgr.takeError();
356  
357    // Set a default CreateMemoryAccess if none is specified.
358    if (!S.CreateMemoryAccess)
359      S.CreateMemoryAccess = createDefaultMemoryAccess;
360  
361    if (auto MemAccess = S.CreateMemoryAccess(*this)) {
362      OwnedMemAccess = std::move(*MemAccess);
363      this->MemAccess = OwnedMemAccess.get();
364    } else
365      return MemAccess.takeError();
366  
367    return Error::success();
368  }
369  
370  Error SimpleRemoteEPC::handleResult(uint64_t SeqNo, ExecutorAddr TagAddr,
371                                      SimpleRemoteEPCArgBytesVector ArgBytes) {
372    IncomingWFRHandler SendResult;
373  
374    if (TagAddr)
375      return make_error<StringError>("Unexpected TagAddr in result message",
376                                     inconvertibleErrorCode());
377  
378    {
379      std::lock_guard<std::mutex> Lock(SimpleRemoteEPCMutex);
380      auto I = PendingCallWrapperResults.find(SeqNo);
381      if (I == PendingCallWrapperResults.end())
382        return make_error<StringError>("No call for sequence number " +
383                                           Twine(SeqNo),
384                                       inconvertibleErrorCode());
385      SendResult = std::move(I->second);
386      PendingCallWrapperResults.erase(I);
387      releaseSeqNo(SeqNo);
388    }
389  
390    auto WFR =
391        shared::WrapperFunctionResult::copyFrom(ArgBytes.data(), ArgBytes.size());
392    SendResult(std::move(WFR));
393    return Error::success();
394  }
395  
396  void SimpleRemoteEPC::handleCallWrapper(
397      uint64_t RemoteSeqNo, ExecutorAddr TagAddr,
398      SimpleRemoteEPCArgBytesVector ArgBytes) {
399    assert(ES && "No ExecutionSession attached");
400    D->dispatch(makeGenericNamedTask(
401        [this, RemoteSeqNo, TagAddr, ArgBytes = std::move(ArgBytes)]() {
402          ES->runJITDispatchHandler(
403              [this, RemoteSeqNo](shared::WrapperFunctionResult WFR) {
404                if (auto Err =
405                        sendMessage(SimpleRemoteEPCOpcode::Result, RemoteSeqNo,
406                                    ExecutorAddr(), {WFR.data(), WFR.size()}))
407                  getExecutionSession().reportError(std::move(Err));
408              },
409              TagAddr, ArgBytes);
410        },
411        "callWrapper task"));
412  }
413  
414  Error SimpleRemoteEPC::handleHangup(SimpleRemoteEPCArgBytesVector ArgBytes) {
415    using namespace llvm::orc::shared;
416    auto WFR = WrapperFunctionResult::copyFrom(ArgBytes.data(), ArgBytes.size());
417    if (const char *ErrMsg = WFR.getOutOfBandError())
418      return make_error<StringError>(ErrMsg, inconvertibleErrorCode());
419  
420    detail::SPSSerializableError Info;
421    SPSInputBuffer IB(WFR.data(), WFR.size());
422    if (!SPSArgList<SPSError>::deserialize(IB, Info))
423      return make_error<StringError>("Could not deserialize hangup info",
424                                     inconvertibleErrorCode());
425    return fromSPSSerializable(std::move(Info));
426  }
427  
428  } // end namespace orc
429  } // end namespace llvm
430