summaryrefslogtreecommitdiff
path: root/tools/lli/Unix/RemoteTargetExternal.inc
blob: ea8e4597d5f79ccaf40e4c2dc9aa17d693ba4efe (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
//=- RemoteTargetExternal.inc - LLVM out-of-process JIT execution for Unix --=//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Implementation of the Unix-specific parts of the RemoteTargetExternal class
// which executes JITed code in a separate process from where it was built.
//
//===----------------------------------------------------------------------===//

#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>

namespace {

struct ConnectionData_t {
  int InputPipe;
  int OutputPipe;

  ConnectionData_t(int in, int out) : InputPipe(in), OutputPipe(out) {}
};

} // namespace

namespace llvm {

bool RemoteTargetExternal::create() {
  int PipeFD[2][2];
  pid_t ChildPID;

  // Create two pipes.
  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]);

    // Use our pipes as stdin and stdout
    if (PipeFD[0][0] != STDIN_FILENO) {
      dup2(PipeFD[0][0], STDIN_FILENO);
      close(PipeFD[0][0]);
    }
    if (PipeFD[1][1] != STDOUT_FILENO) {
      dup2(PipeFD[1][1], STDOUT_FILENO);
      close(PipeFD[1][1]);
    }

    // Execute the child process.
    char *args[1] = { NULL };
    int rc = execv(ChildName.c_str(), args);
    if (rc != 0)
      perror("Error executing child process: ");
  }
  else {
    // In the parent...

    // Close the child ends of the pipes
    close(PipeFD[0][0]);
    close(PipeFD[1][1]);

    // Store the parent ends of the pipes
    ConnectionData = (void*)new ConnectionData_t(PipeFD[1][0], PipeFD[0][1]);

    // We must get Ack from the client (blocking read)
    if (!Receive(LLI_ChildActive)) {
      ErrorMsg += ", (RemoteTargetExternal::create) - Stopping process!";
      stop();
      return false;
    }
  }
  return true;
}

static void ReportError(int rc, size_t Size, std::string &ErrorMsg) {
  if (rc == -1) {
    if (errno == EPIPE)
      ErrorMsg += "pipe closed";
    else if (errno == EINTR)
      ErrorMsg += "interrupted";
    else
      ErrorMsg += "file descriptor error";
  } else {
    char Number[10] = { 0 };
    ErrorMsg += "Expecting ";
    sprintf(Number, "%d", (uint32_t)Size);
    ErrorMsg += Number;
    ErrorMsg += " bytes, Got ";
    sprintf(Number, "%d", rc);
    ErrorMsg += Number;
  }
}

bool RemoteTargetExternal::WriteBytes(const void *Data, size_t Size) {
  int rc = write(((ConnectionData_t*)ConnectionData)->OutputPipe, Data, Size);
  if (rc != -1 && (size_t)rc == Size)
    return true;

  ErrorMsg = "WriteBytes: ";
  ReportError(rc, Size, ErrorMsg);
  return false;
}

bool RemoteTargetExternal::ReadBytes(void *Data, size_t Size) {
  int rc = read(((ConnectionData_t*)ConnectionData)->InputPipe, Data, Size);
  if (rc != -1 && (size_t)rc == Size)
    return true;

  ErrorMsg = "ReadBytes: ";
  ReportError(rc, Size, ErrorMsg);
  return false;
}

void RemoteTargetExternal::Wait() {
  wait(NULL);
}

RemoteTargetExternal::~RemoteTargetExternal() {
  delete static_cast<ConnectionData_t *>(ConnectionData);
}

} // namespace llvm