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 22 namespace { 23 24 struct 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 33 namespace llvm { 34 35 bool 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 81 bool 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 87 void RPCChannel::Wait() { wait(nullptr); } 88 89 static 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 108 bool 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 113 bool 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 118 RPCChannel::~RPCChannel() { 119 delete static_cast<ConnectionData_t *>(ConnectionData); 120 } 121 122 } // namespace llvm 123