//===--- SimpleRemoteEPCUtils.h - Utils for Simple Remote EPC ---*- 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
 
//
 
//===----------------------------------------------------------------------===//
 
//
 
// Message definitions and other utilities for SimpleRemoteEPC and
 
// SimpleRemoteEPCServer.
 
//
 
//===----------------------------------------------------------------------===//
 
 
 
#ifndef LLVM_EXECUTIONENGINE_ORC_SHARED_SIMPLEREMOTEEPCUTILS_H
 
#define LLVM_EXECUTIONENGINE_ORC_SHARED_SIMPLEREMOTEEPCUTILS_H
 
 
 
#include "llvm/ADT/ArrayRef.h"
 
#include "llvm/ADT/SmallVector.h"
 
#include "llvm/ADT/StringMap.h"
 
#include "llvm/ExecutionEngine/Orc/Shared/ExecutorAddress.h"
 
#include "llvm/ExecutionEngine/Orc/Shared/SimplePackedSerialization.h"
 
#include "llvm/Support/Error.h"
 
 
 
#include <atomic>
 
#include <mutex>
 
#include <string>
 
#include <thread>
 
 
 
namespace llvm {
 
namespace orc {
 
 
 
namespace SimpleRemoteEPCDefaultBootstrapSymbolNames {
 
extern const char *ExecutorSessionObjectName;
 
extern const char *DispatchFnName;
 
} // end namespace SimpleRemoteEPCDefaultBootstrapSymbolNames
 
 
 
enum class SimpleRemoteEPCOpcode : uint8_t {
 
  Setup,
 
  Hangup,
 
  Result,
 
  CallWrapper,
 
  LastOpC = CallWrapper
 
};
 
 
 
struct SimpleRemoteEPCExecutorInfo {
 
  std::string TargetTriple;
 
  uint64_t PageSize;
 
  StringMap<ExecutorAddr> BootstrapSymbols;
 
};
 
 
 
using SimpleRemoteEPCArgBytesVector = SmallVector<char, 128>;
 
 
 
class SimpleRemoteEPCTransportClient {
 
public:
 
  enum HandleMessageAction { ContinueSession, EndSession };
 
 
 
  virtual ~SimpleRemoteEPCTransportClient();
 
 
 
  /// Handle receipt of a message.
 
  ///
 
  /// Returns an Error if the message cannot be handled, 'EndSession' if the
 
  /// client will not accept any further messages, and 'ContinueSession'
 
  /// otherwise.
 
  virtual Expected<HandleMessageAction>
 
  handleMessage(SimpleRemoteEPCOpcode OpC, uint64_t SeqNo, ExecutorAddr TagAddr,
 
                SimpleRemoteEPCArgBytesVector ArgBytes) = 0;
 
 
 
  /// Handle a disconnection from the underlying transport. No further messages
 
  /// should be sent to handleMessage after this is called.
 
  /// Err may contain an Error value indicating unexpected disconnection. This
 
  /// allows clients to log such errors, but no attempt should be made at
 
  /// recovery (which should be handled inside the transport class, if it is
 
  /// supported at all).
 
  virtual void handleDisconnect(Error Err) = 0;
 
};
 
 
 
class SimpleRemoteEPCTransport {
 
public:
 
  virtual ~SimpleRemoteEPCTransport();
 
 
 
  /// Called during setup of the client to indicate that the client is ready
 
  /// to receive messages.
 
  ///
 
  /// Transport objects should not access the client until this method is
 
  /// called.
 
  virtual Error start() = 0;
 
 
 
  /// Send a SimpleRemoteEPC message.
 
  ///
 
  /// This function may be called concurrently. Subclasses should implement
 
  /// locking if required for the underlying transport.
 
  virtual Error sendMessage(SimpleRemoteEPCOpcode OpC, uint64_t SeqNo,
 
                            ExecutorAddr TagAddr, ArrayRef<char> ArgBytes) = 0;
 
 
 
  /// Trigger disconnection from the transport. The implementation should
 
  /// respond by calling handleDisconnect on the client once disconnection
 
  /// is complete. May be called more than once and from different threads.
 
  virtual void disconnect() = 0;
 
};
 
 
 
/// Uses read/write on FileDescriptors for transport.
 
class FDSimpleRemoteEPCTransport : public SimpleRemoteEPCTransport {
 
public:
 
  /// Create a FDSimpleRemoteEPCTransport using the given FDs for
 
  /// reading (InFD) and writing (OutFD).
 
  static Expected<std::unique_ptr<FDSimpleRemoteEPCTransport>>
 
  Create(SimpleRemoteEPCTransportClient &C, int InFD, int OutFD);
 
 
 
  /// Create a FDSimpleRemoteEPCTransport using the given FD for both
 
  /// reading and writing.
 
  static Expected<std::unique_ptr<FDSimpleRemoteEPCTransport>>
 
  Create(SimpleRemoteEPCTransportClient &C, int FD) {
 
    return Create(C, FD, FD);
 
  }
 
 
 
  ~FDSimpleRemoteEPCTransport() override;
 
 
 
  Error start() override;
 
 
 
  Error sendMessage(SimpleRemoteEPCOpcode OpC, uint64_t SeqNo,
 
                    ExecutorAddr TagAddr, ArrayRef<char> ArgBytes) override;
 
 
 
  void disconnect() override;
 
 
 
private:
 
  FDSimpleRemoteEPCTransport(SimpleRemoteEPCTransportClient &C, int InFD,
 
                             int OutFD)
 
      : C(C), InFD(InFD), OutFD(OutFD) {}
 
 
 
  Error readBytes(char *Dst, size_t Size, bool *IsEOF = nullptr);
 
  int writeBytes(const char *Src, size_t Size);
 
  void listenLoop();
 
 
 
  std::mutex M;
 
  SimpleRemoteEPCTransportClient &C;
 
  std::thread ListenerThread;
 
  int InFD, OutFD;
 
  std::atomic<bool> Disconnected{false};
 
};
 
 
 
struct RemoteSymbolLookupSetElement {
 
  std::string Name;
 
  bool Required;
 
};
 
 
 
using RemoteSymbolLookupSet = std::vector<RemoteSymbolLookupSetElement>;
 
 
 
struct RemoteSymbolLookup {
 
  uint64_t H;
 
  RemoteSymbolLookupSet Symbols;
 
};
 
 
 
namespace shared {
 
 
 
using SPSRemoteSymbolLookupSetElement = SPSTuple<SPSString, bool>;
 
 
 
using SPSRemoteSymbolLookupSet = SPSSequence<SPSRemoteSymbolLookupSetElement>;
 
 
 
using SPSRemoteSymbolLookup = SPSTuple<uint64_t, SPSRemoteSymbolLookupSet>;
 
 
 
/// Tuple containing target triple, page size, and bootstrap symbols.
 
using SPSSimpleRemoteEPCExecutorInfo =
 
    SPSTuple<SPSString, uint64_t,
 
             SPSSequence<SPSTuple<SPSString, SPSExecutorAddr>>>;
 
 
 
template <>
 
class SPSSerializationTraits<SPSRemoteSymbolLookupSetElement,
 
                             RemoteSymbolLookupSetElement> {
 
public:
 
  static size_t size(const RemoteSymbolLookupSetElement &V) {
 
    return SPSArgList<SPSString, bool>::size(V.Name, V.Required);
 
  }
 
 
 
  static size_t serialize(SPSOutputBuffer &OB,
 
                          const RemoteSymbolLookupSetElement &V) {
 
    return SPSArgList<SPSString, bool>::serialize(OB, V.Name, V.Required);
 
  }
 
 
 
  static size_t deserialize(SPSInputBuffer &IB,
 
                            RemoteSymbolLookupSetElement &V) {
 
    return SPSArgList<SPSString, bool>::deserialize(IB, V.Name, V.Required);
 
  }
 
};
 
 
 
template <>
 
class SPSSerializationTraits<SPSRemoteSymbolLookup, RemoteSymbolLookup> {
 
public:
 
  static size_t size(const RemoteSymbolLookup &V) {
 
    return SPSArgList<uint64_t, SPSRemoteSymbolLookupSet>::size(V.H, V.Symbols);
 
  }
 
 
 
  static size_t serialize(SPSOutputBuffer &OB, const RemoteSymbolLookup &V) {
 
    return SPSArgList<uint64_t, SPSRemoteSymbolLookupSet>::serialize(OB, V.H,
 
                                                                     V.Symbols);
 
  }
 
 
 
  static size_t deserialize(SPSInputBuffer &IB, RemoteSymbolLookup &V) {
 
    return SPSArgList<uint64_t, SPSRemoteSymbolLookupSet>::deserialize(
 
        IB, V.H, V.Symbols);
 
  }
 
};
 
 
 
template <>
 
class SPSSerializationTraits<SPSSimpleRemoteEPCExecutorInfo,
 
                             SimpleRemoteEPCExecutorInfo> {
 
public:
 
  static size_t size(const SimpleRemoteEPCExecutorInfo &SI) {
 
    return SPSSimpleRemoteEPCExecutorInfo::AsArgList ::size(
 
        SI.TargetTriple, SI.PageSize, SI.BootstrapSymbols);
 
  }
 
 
 
  static bool serialize(SPSOutputBuffer &OB,
 
                        const SimpleRemoteEPCExecutorInfo &SI) {
 
    return SPSSimpleRemoteEPCExecutorInfo::AsArgList ::serialize(
 
        OB, SI.TargetTriple, SI.PageSize, SI.BootstrapSymbols);
 
  }
 
 
 
  static bool deserialize(SPSInputBuffer &IB, SimpleRemoteEPCExecutorInfo &SI) {
 
    return SPSSimpleRemoteEPCExecutorInfo::AsArgList ::deserialize(
 
        IB, SI.TargetTriple, SI.PageSize, SI.BootstrapSymbols);
 
  }
 
};
 
 
 
using SPSLoadDylibSignature = SPSExpected<SPSExecutorAddr>(SPSExecutorAddr,
 
                                                           SPSString, uint64_t);
 
 
 
using SPSLookupSymbolsSignature =
 
    SPSExpected<SPSSequence<SPSSequence<SPSExecutorAddr>>>(
 
        SPSExecutorAddr, SPSSequence<SPSRemoteSymbolLookup>);
 
 
 
} // end namespace shared
 
} // end namespace orc
 
} // end namespace llvm
 
 
 
#endif // LLVM_EXECUTIONENGINE_ORC_SHARED_SIMPLEREMOTEEPCUTILS_H