RPCChannel.inc 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  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. #include "llvm/Support/Errno.h"
  15. #include "llvm/Support/raw_ostream.h"
  16. #include <stdio.h>
  17. #include <stdlib.h>
  18. #include <sys/wait.h>
  19. #include <unistd.h>
  20. namespace {
  21. struct ConnectionData_t {
  22. int InputPipe;
  23. int OutputPipe;
  24. ConnectionData_t(int in, int out) : InputPipe(in), OutputPipe(out) {}
  25. };
  26. } // namespace
  27. namespace llvm {
  28. bool RPCChannel::createServer() {
  29. int PipeFD[2][2];
  30. pid_t ChildPID;
  31. // Create two pipes.
  32. if (pipe(PipeFD[0]) != 0 || pipe(PipeFD[1]) != 0)
  33. perror("Error creating pipe: ");
  34. ChildPID = fork();
  35. if (ChildPID == 0) {
  36. // In the child...
  37. // Close the parent ends of the pipes
  38. close(PipeFD[0][1]);
  39. close(PipeFD[1][0]);
  40. // Use our pipes as stdin and stdout
  41. if (PipeFD[0][0] != STDIN_FILENO) {
  42. dup2(PipeFD[0][0], STDIN_FILENO);
  43. close(PipeFD[0][0]);
  44. }
  45. if (PipeFD[1][1] != STDOUT_FILENO) {
  46. dup2(PipeFD[1][1], STDOUT_FILENO);
  47. close(PipeFD[1][1]);
  48. }
  49. // Execute the child process.
  50. char *args[1] = { nullptr };
  51. int rc = execv(ChildName.c_str(), args);
  52. if (rc != 0)
  53. perror("Error executing child process: ");
  54. } else {
  55. // In the parent...
  56. // Close the child ends of the pipes
  57. close(PipeFD[0][0]);
  58. close(PipeFD[1][1]);
  59. // Store the parent ends of the pipes
  60. ConnectionData = (void *)new ConnectionData_t(PipeFD[1][0], PipeFD[0][1]);
  61. return true;
  62. }
  63. return false;
  64. }
  65. bool RPCChannel::createClient() {
  66. // Store the parent ends of the pipes
  67. ConnectionData = (void *)new ConnectionData_t(STDIN_FILENO, STDOUT_FILENO);
  68. return true;
  69. }
  70. void RPCChannel::Wait() { wait(nullptr); }
  71. static bool CheckError(int rc, size_t Size, const char *Desc) {
  72. if (rc < 0) {
  73. llvm::errs() << "IO Error: " << Desc << ": " << sys::StrError() << '\n';
  74. return false;
  75. } else if ((size_t)rc != Size) {
  76. std::string ErrorMsg;
  77. char Number[10] = { 0 };
  78. ErrorMsg += "Expecting ";
  79. sprintf(Number, "%d", (uint32_t)Size);
  80. ErrorMsg += Number;
  81. ErrorMsg += " bytes, Got ";
  82. sprintf(Number, "%d", rc);
  83. ErrorMsg += Number;
  84. llvm::errs() << "RPC Error: " << Desc << ": " << ErrorMsg << '\n';
  85. return false;
  86. }
  87. return true;
  88. }
  89. bool RPCChannel::WriteBytes(const void *Data, size_t Size) {
  90. int rc = write(((ConnectionData_t *)ConnectionData)->OutputPipe, Data, Size);
  91. return CheckError(rc, Size, "WriteBytes");
  92. }
  93. bool RPCChannel::ReadBytes(void *Data, size_t Size) {
  94. int rc = read(((ConnectionData_t *)ConnectionData)->InputPipe, Data, Size);
  95. return CheckError(rc, Size, "ReadBytes");
  96. }
  97. RPCChannel::~RPCChannel() {
  98. delete static_cast<ConnectionData_t *>(ConnectionData);
  99. }
  100. } // namespace llvm