Pakman
ForkedWorkerHandler.cc
1 #include <string>
2 #include <thread>
3 #include <stdexcept>
4 #include <signal.h>
5 #include <sys/wait.h>
6 #include <sys/types.h>
7 
8 #include "core/common.h"
9 #include "system/system_call.h"
10 #include "system/pipe_io.h"
11 #include "mpi/mpi_common.h"
12 
13 #include "ForkedWorkerHandler.h"
14 
16  const Command& simulator,
17  const std::string& input_string) :
18  AbstractWorkerHandler(simulator, input_string)
19 {
20 
21  // Start process
22  std::tie(m_child_pid, m_pipe_write_fd, m_pipe_read_fd) =
23  system_call_non_blocking_read_write(m_simulator);
24 
25  // Write input string to stdin of process
26  write_to_pipe(m_pipe_write_fd, input_string);
27  close_check(m_pipe_write_fd);
28 }
29 
31 {
32  // Wait on child process if it has not yet been waited for
33  if (m_child_pid) terminate();
34 
35  // Close pipe if not already closed
36  if (!m_read_done) close_check(m_pipe_read_fd);
37 }
38 
39 void ForkedWorkerHandler::terminate()
40 {
41  // If already terminated, return immediately
42  if (!m_child_pid) return;
43 
44  // If simulation has finished, mark by setting m_child_pid to zero
45  if ( waitpid_success(m_child_pid, WNOHANG, m_simulator) )
46  {
47  m_child_pid = 0;
48  return;
49  }
50 
51  // Send SIGTERM to child process
52  if ( kill(m_child_pid, SIGTERM) )
53  {
54  std::runtime_error e("an error occurred while trying to terminate "
55  "child process");
56  throw e;
57  }
58 
59  // Sleep for g_kill_timeout
60  std::this_thread::sleep_for(g_kill_timeout);
61 
62  // If simulation has finished, mark by setting m_child_pid to zero
63  if ( waitpid_success(m_child_pid, WNOHANG, m_simulator, ignore_error) )
64  {
65  m_child_pid = 0;
66  return;
67  }
68 
69  // Send SIGKILL to child process
70  if ( kill(m_child_pid, SIGKILL) )
71  {
72  std::runtime_error e("an error occurred while trying to kill "
73  "child process");
74  throw e;
75  }
76 
77  waitpid_success(m_child_pid, 0, m_simulator, ignore_error);
78  m_child_pid = 0;
79 }
80 
82 {
83  // Poll pipe if m_read_done flag is false. If pipe is finished reading,
84  // close pipe and set m_read_done flag to true
85  if ( !m_read_done &&
86  poll_read_from_pipe(m_pipe_read_fd, m_output_buffer) )
87  {
88  close_check(m_pipe_read_fd);
89 
90  // Get error code
91  waitpid_success(m_child_pid, m_error_code, 0);
92  m_child_pid = 0;
93 
94  m_read_done = true;
95  }
96 
97  return m_read_done;
98 }
virtual bool isDone() override
std::chrono::milliseconds g_kill_timeout
virtual ~ForkedWorkerHandler() override
ForkedWorkerHandler(const Command &simulator, const std::string &input_string)