+++ /dev/null
-//===--- LLJITWithChildProcess.cpp - LLJIT targeting a child process ------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-//
-// In this example we will execute JITed code in a child process:
-//
-// 1. Launch a remote process.
-// 2. Create a JITLink-compatible remote memory manager.
-// 3. Use LLJITBuilder to create a (greedy) LLJIT instance.
-// 4. Add the Add1Example module and execute add1().
-// 5. Terminate the remote target session.
-//
-//===----------------------------------------------------------------------===//
-
-#include "llvm/ExecutionEngine/JITLink/JITLinkMemoryManager.h"
-#include "llvm/ExecutionEngine/Orc/JITTargetMachineBuilder.h"
-#include "llvm/ExecutionEngine/Orc/LLJIT.h"
-#include "llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h"
-#include "llvm/ExecutionEngine/Orc/OrcRemoteTargetClient.h"
-#include "llvm/Support/Debug.h"
-#include "llvm/Support/Error.h"
-#include "llvm/Support/InitLLVM.h"
-#include "llvm/Support/TargetSelect.h"
-#include "llvm/Support/raw_ostream.h"
-
-#include "../ExampleModules.h"
-#include "RemoteJITUtils.h"
-
-#include <memory>
-#include <string>
-
-#define DEBUG_TYPE "orc"
-
-using namespace llvm;
-using namespace llvm::orc;
-
-// Executable running in the child process for remote execution. It communicates
-// via stdin/stdout pipes.
-cl::opt<std::string>
- ChildExecPath("remote-process", cl::Required,
- cl::desc("Specify the filename of the process to launch for "
- "remote JITing."),
- cl::value_desc("filename"));
-
-int main(int argc, char *argv[]) {
- InitLLVM X(argc, argv);
-
- InitializeNativeTarget();
- InitializeNativeTargetAsmPrinter();
-
- cl::ParseCommandLineOptions(argc, argv, "LLJITWithChildProcess");
-
- ExitOnError ExitOnErr;
- ExitOnErr.setBanner(std::string(argv[0]) + ": ");
-
- if (!sys::fs::can_execute(ChildExecPath)) {
- WithColor::error(errs(), argv[0])
- << "Child executable invalid: '" << ChildExecPath << "'\n";
- return -1;
- }
-
- ExecutionSession ES;
- ES.setErrorReporter([&](Error Err) { ExitOnErr(std::move(Err)); });
-
- // Launch the remote process and get a channel to it.
- pid_t ChildPID;
- std::unique_ptr<FDRawChannel> Ch = launchRemote(ChildExecPath, ChildPID);
- if (!Ch) {
- WithColor::error(errs(), argv[0]) << "Failed to launch remote JIT.\n";
- exit(1);
- }
-
- LLVM_DEBUG({
- dbgs()
- << "Launched executable in subprocess " << ChildPID << ":\n"
- << ChildExecPath << "\n\n"
- << "You may want to attach a debugger now. Press enter to continue.\n";
- fflush(stdin);
- getchar();
- });
-
- std::unique_ptr<remote::OrcRemoteTargetClient> Client =
- ExitOnErr(remote::OrcRemoteTargetClient::Create(*Ch, ES));
-
- // Create a JITLink-compatible remote memory manager.
- using MemManager = remote::OrcRemoteTargetClient::RemoteJITLinkMemoryManager;
- std::unique_ptr<MemManager> RemoteMM =
- ExitOnErr(Client->createRemoteJITLinkMemoryManager());
-
- // Our remote target is running on the host system.
- auto JTMB = ExitOnErr(JITTargetMachineBuilder::detectHost());
- JTMB.setCodeModel(CodeModel::Small);
-
- // Create an LLJIT instance with a JITLink ObjectLinkingLayer.
- auto J = ExitOnErr(
- LLJITBuilder()
- .setJITTargetMachineBuilder(std::move(JTMB))
- .setObjectLinkingLayerCreator(
- [&](ExecutionSession &ES,
- const Triple &TT) -> std::unique_ptr<ObjectLayer> {
- return std::make_unique<ObjectLinkingLayer>(ES, *RemoteMM);
- })
- .create());
-
- auto M = ExitOnErr(parseExampleModule(Add1Example, "add1"));
-
- ExitOnErr(J->addIRModule(std::move(M)));
-
- // Look up the JIT'd function.
- auto Add1Sym = ExitOnErr(J->lookup("add1"));
-
- // Run in child target.
- Expected<int> Result = Client->callIntInt(Add1Sym.getAddress(), 42);
- if (Result)
- outs() << "add1(42) = " << *Result << "\n";
- else
- ES.reportError(Result.takeError());
-
- // Signal the remote target that we're done JITing.
- ExitOnErr(Client->terminateSession());
- LLVM_DEBUG(dbgs() << "Subprocess terminated\n");
-
- return 0;
-}
+++ /dev/null
-//===-- RemoteJITUtils.h - Utilities for remote-JITing ----------*- 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
-//
-//===----------------------------------------------------------------------===//
-//
-// Utilities for remote-JITing
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_EXAMPLES_ORCV2EXAMPLES_LLJITWITHCHILDPROCESS_REMOTEJITUTILS_H
-#define LLVM_EXAMPLES_ORCV2EXAMPLES_LLJITWITHCHILDPROCESS_REMOTEJITUTILS_H
-
-#include "llvm/ExecutionEngine/Orc/RPC/RawByteChannel.h"
-#include <mutex>
-
-#if !defined(_MSC_VER) && !defined(__MINGW32__)
-#include <unistd.h>
-#else
-#include <io.h>
-#endif
-
-/// RPC channel that reads from and writes from file descriptors.
-class FDRawChannel final : public llvm::orc::rpc::RawByteChannel {
-public:
- FDRawChannel(int InFD, int OutFD) : InFD(InFD), OutFD(OutFD) {}
-
- llvm::Error readBytes(char *Dst, unsigned Size) override {
- assert(Dst && "Attempt to read into null.");
- ssize_t Completed = 0;
- while (Completed < static_cast<ssize_t>(Size)) {
- ssize_t Read = ::read(InFD, Dst + Completed, Size - Completed);
- if (Read <= 0) {
- auto ErrNo = errno;
- if (ErrNo == EAGAIN || ErrNo == EINTR)
- continue;
- else
- return llvm::errorCodeToError(
- std::error_code(errno, std::generic_category()));
- }
- Completed += Read;
- }
- return llvm::Error::success();
- }
-
- llvm::Error appendBytes(const char *Src, unsigned Size) override {
- assert(Src && "Attempt to append from null.");
- ssize_t Completed = 0;
- while (Completed < static_cast<ssize_t>(Size)) {
- ssize_t Written = ::write(OutFD, Src + Completed, Size - Completed);
- if (Written < 0) {
- auto ErrNo = errno;
- if (ErrNo == EAGAIN || ErrNo == EINTR)
- continue;
- else
- return llvm::errorCodeToError(
- std::error_code(errno, std::generic_category()));
- }
- Completed += Written;
- }
- return llvm::Error::success();
- }
-
- llvm::Error send() override { return llvm::Error::success(); }
-
-private:
- int InFD, OutFD;
-};
-
-// Launch child process and return a channel to it.
-std::unique_ptr<FDRawChannel> launchRemote(std::string ExecPath,
- pid_t &ChildPID) {
- // Create two pipes.
- int PipeFD[2][2];
- if (pipe(PipeFD[0]) != 0 || pipe(PipeFD[1]) != 0)
- perror("Error creating pipe: ");
-
- ChildPID = fork();
-
- if (ChildPID == 0) {
- // In the child...
-
- // Close the parent ends of the pipes
- close(PipeFD[0][1]);
- close(PipeFD[1][0]);
-
- // Execute the child process.
- std::unique_ptr<char[]> ChildPath, ChildIn, ChildOut;
- {
- ChildPath.reset(new char[ExecPath.size() + 1]);
- std::copy(ExecPath.begin(), ExecPath.end(), &ChildPath[0]);
- ChildPath[ExecPath.size()] = '\0';
- std::string ChildInStr = llvm::utostr(PipeFD[0][0]);
- ChildIn.reset(new char[ChildInStr.size() + 1]);
- std::copy(ChildInStr.begin(), ChildInStr.end(), &ChildIn[0]);
- ChildIn[ChildInStr.size()] = '\0';
- std::string ChildOutStr = llvm::utostr(PipeFD[1][1]);
- ChildOut.reset(new char[ChildOutStr.size() + 1]);
- std::copy(ChildOutStr.begin(), ChildOutStr.end(), &ChildOut[0]);
- ChildOut[ChildOutStr.size()] = '\0';
- }
-
- char *const args[] = {&ChildPath[0], &ChildIn[0], &ChildOut[0], nullptr};
- int rc = execv(ExecPath.c_str(), args);
- if (rc != 0)
- perror("Error executing child process: ");
- llvm_unreachable("Error executing child process");
- }
- // else we're the parent...
-
- // Close the child ends of the pipes
- close(PipeFD[0][0]);
- close(PipeFD[1][1]);
-
- // Return an RPC channel connected to our end of the pipes.
- return std::make_unique<FDRawChannel>(PipeFD[1][0], PipeFD[0][1]);
-}
-
-#endif