1//=- RPCChannel.inc - LLVM out-of-process JIT execution for Unix --=// 2// 3// The LLVM Compiler Infrastructure 4// 5// This file is distributed under the University of Illinois Open Source 6// License. See LICENSE.TXT for details. 7// 8//===----------------------------------------------------------------------===// 9// 10// Implementation of the Unix-specific parts of the RPCChannel class 11// which executes JITed code in a separate process from where it was built. 12// 13//===----------------------------------------------------------------------===// 14 15#include "llvm/Support/Errno.h" 16#include "llvm/Support/raw_ostream.h" 17#include <stdio.h> 18#include <stdlib.h> 19#include <sys/wait.h> 20#include <unistd.h> 21 22namespace { 23 24struct ConnectionData_t { 25 int InputPipe; 26 int OutputPipe; 27 28 ConnectionData_t(int in, int out) : InputPipe(in), OutputPipe(out) {} 29}; 30 31} // namespace 32 33namespace llvm { 34 35bool RPCChannel::createServer() { 36 int PipeFD[2][2]; 37 pid_t ChildPID; 38 39 // Create two pipes. 40 if (pipe(PipeFD[0]) != 0 || pipe(PipeFD[1]) != 0) 41 perror("Error creating pipe: "); 42 43 ChildPID = fork(); 44 45 if (ChildPID == 0) { 46 // In the child... 47 48 // Close the parent ends of the pipes 49 close(PipeFD[0][1]); 50 close(PipeFD[1][0]); 51 52 // Use our pipes as stdin and stdout 53 if (PipeFD[0][0] != STDIN_FILENO) { 54 dup2(PipeFD[0][0], STDIN_FILENO); 55 close(PipeFD[0][0]); 56 } 57 if (PipeFD[1][1] != STDOUT_FILENO) { 58 dup2(PipeFD[1][1], STDOUT_FILENO); 59 close(PipeFD[1][1]); 60 } 61 62 // Execute the child process. 63 char *args[1] = { nullptr }; 64 int rc = execv(ChildName.c_str(), args); 65 if (rc != 0) 66 perror("Error executing child process: "); 67 } else { 68 // In the parent... 69 70 // Close the child ends of the pipes 71 close(PipeFD[0][0]); 72 close(PipeFD[1][1]); 73 74 // Store the parent ends of the pipes 75 ConnectionData = (void *)new ConnectionData_t(PipeFD[1][0], PipeFD[0][1]); 76 return true; 77 } 78 return false; 79} 80 81bool RPCChannel::createClient() { 82 // Store the parent ends of the pipes 83 ConnectionData = (void *)new ConnectionData_t(STDIN_FILENO, STDOUT_FILENO); 84 return true; 85} 86 87void RPCChannel::Wait() { wait(nullptr); } 88 89static bool CheckError(int rc, size_t Size, const char *Desc) { 90 if (rc < 0) { 91 llvm::errs() << "IO Error: " << Desc << ": " << sys::StrError() << '\n'; 92 return false; 93 } else if ((size_t)rc != Size) { 94 std::string ErrorMsg; 95 char Number[10] = { 0 }; 96 ErrorMsg += "Expecting "; 97 sprintf(Number, "%d", (uint32_t)Size); 98 ErrorMsg += Number; 99 ErrorMsg += " bytes, Got "; 100 sprintf(Number, "%d", rc); 101 ErrorMsg += Number; 102 llvm::errs() << "RPC Error: " << Desc << ": " << ErrorMsg << '\n'; 103 return false; 104 } 105 return true; 106} 107 108bool RPCChannel::WriteBytes(const void *Data, size_t Size) { 109 int rc = write(((ConnectionData_t *)ConnectionData)->OutputPipe, Data, Size); 110 return CheckError(rc, Size, "WriteBytes"); 111} 112 113bool RPCChannel::ReadBytes(void *Data, size_t Size) { 114 int rc = read(((ConnectionData_t *)ConnectionData)->InputPipe, Data, Size); 115 return CheckError(rc, Size, "ReadBytes"); 116} 117 118RPCChannel::~RPCChannel() { 119 delete static_cast<ConnectionData_t *>(ConnectionData); 120} 121 122} // namespace llvm 123