Fork.hpp
Go to the documentation of this file.
1 // @formatter:off
2 //
3 // Balau core C++ library
4 //
5 // Copyright (C) 2008 Bora Software (contact@borasoftware.com)
6 //
7 // Licensed under the Boost Software License - Version 1.0 - August 17th, 2003.
8 // See the LICENSE file for the full license text.
9 //
10 
16 
17 #ifndef COM_BORA_SOFTWARE__BALAU_CONCURRENT__FORK
18 #define COM_BORA_SOFTWARE__BALAU_CONCURRENT__FORK
19 
21 #include <Balau/Dev/Assert.hpp>
22 
23 #include <boost/predef.h>
24 #include <sys/wait.h>
25 
26 namespace Balau::Concurrent {
27 
31 class Fork {
35  public: static bool forkSupported() {
36  #pragma clang diagnostic push
37  #pragma ide diagnostic ignored "OCSimplifyInspection"
38  #pragma ide diagnostic ignored "OCDFAInspection"
39  return BOOST_OS_UNIX;
40  #pragma clang diagnostic pop
41  }
42 
55  public: static int performFork(const std::function<int ()> & function, bool exitChild) {
56  Assert::assertion(forkSupported(), "fork() called for platform that does not support it.");
57 
58  const int pid = ::fork();
59 
60  if (pid == 0) {
61  const int status = function();
62 
63  if (exitChild) {
64  _Exit(status);
65  } else {
66  return status;
67  }
68  } else if (pid > 0) {
69  return pid;
70  } else {
71  ThrowBalauException(Exception::ForkException, errno, "Failed to fork process.");
72  }
73  }
74 
87  public: static int performFork(const std::function<int ()> & function) {
88  Assert::assertion(forkSupported(), "fork() called for platform that does not support it.");
89 
90  const int pid = ::fork();
91 
92  if (pid == 0) {
93  function();
94  return 0;
95  } else if (pid > 0) {
96  return pid;
97  } else {
98  ThrowBalauException(Exception::ForkException, errno, "Failed to fork process.");
99  }
100  }
101 
108  public: struct TerminationReport {
112  int pid;
113 
117  int code;
118 
123 
124  TerminationReport() : pid(0), code(0), exitStatus(0) {}
125 
126  TerminationReport(int pid_, int code_, int exitStatus_)
127  : pid(pid_), code(code_), exitStatus(exitStatus_) {}
128 
129  TerminationReport(const TerminationReport & copy) = default;
130 
131  TerminationReport(TerminationReport && rhs) noexcept
132  : pid(rhs.pid), code(rhs.code), exitStatus(rhs.exitStatus) {}
133 
134  TerminationReport & operator = (const TerminationReport & copy) = default;
135 
136  TerminationReport & operator = (TerminationReport && rhs) noexcept {
137  pid = rhs.pid;
138  code = rhs.code;
139  exitStatus = rhs.exitStatus;
140  return *this;
141  }
142  };
143 
153  public: static TerminationReport waitOnProcess(int pid) {
154  if (pid <= 0) {
155  return TerminationReport();
156  }
157 
158  siginfo_t infop;
159  int options = WEXITED;
160 
161  memset(&infop, 0, sizeof(siginfo_t));
162 
163  if (waitid(P_PID, (unsigned int) pid, &infop, options) == -1) {
165  } else if (infop.si_pid) {
166  return TerminationReport(pid, infop.si_code, infop.si_status);
167  }
168 
169  // TODO what else may happen here?
170  return TerminationReport();
171  }
172 
186  if (pid <= 0) {
187  return TerminationReport();
188  }
189 
190  siginfo_t infop;
191  int options = WEXITED | WNOHANG;
192 
193  memset(&infop, 0, sizeof(siginfo_t));
194 
195  if (waitid(P_PID, (unsigned int) pid, &infop, options) == -1) {
197  } else if (infop.si_pid) {
198  switch (infop.si_code) {
199  case CLD_EXITED:
200  case CLD_KILLED:
201  case CLD_DUMPED: {
202  return TerminationReport(pid, infop.si_code, infop.si_status);
203  }
204 
205  default: {
206  break;
207  }
208  }
209  }
210 
211  return TerminationReport();
212  }
213 
221  public: static std::vector<TerminationReport> checkForTermination(const std::vector<int> & pids) {
222  std::vector<TerminationReport> reports;
223  siginfo_t infop;
224  int options = WEXITED | WNOHANG; // NOLINT
225 
226  for (int pid : pids) {
227  if (pid <= 0) {
228  continue;
229  }
230 
231  memset(&infop, 0, sizeof(siginfo_t));
232 
233  if (waitid(P_PID, (unsigned int) pid, &infop, options) == -1) {
235  } else if (infop.si_pid) {
236  switch (infop.si_code) {
237  case CLD_EXITED:
238  case CLD_KILLED:
239  case CLD_DUMPED: {
240  reports.emplace_back(pid, infop.si_code, infop.si_status);
241  }
242 
243  default: {
244  break;
245  }
246  }
247  }
248  }
249 
250  return reports;
251  }
252 
263  public: static TerminationReport terminateProcess(int pid) {
264  if (pid <= 0) {
265  return TerminationReport();
266  }
267 
268  siginfo_t infop;
269  int options = WEXITED | WNOHANG; // NOLINT
270 
271  memset(&infop, 0, sizeof(siginfo_t));
272 
273  if (waitid(P_PID, (unsigned int) pid, &infop, options) == -1) {
275  } else if (infop.si_pid) {
276  switch (infop.si_code) {
277  case CLD_EXITED:
278  case CLD_KILLED:
279  case CLD_DUMPED: {
280  return TerminationReport(pid, infop.si_code, infop.si_status);
281  }
282 
283  default: {
284  kill(pid, SIGKILL);
285  break;
286  }
287  }
288  }
289 
290  return TerminationReport();
291  }
292 };
293 
294 } // namespace Balau::Concurrent
295 
296 #endif // COM_BORA_SOFTWARE__BALAU_CONCURRENT__FORK
static TerminationReport terminateProcess(int pid)
Terminate the child process if it is running.
Definition: Fork.hpp:263
static bool forkSupported()
Determine whether forking is support on this platform.
Definition: Fork.hpp:35
static std::vector< TerminationReport > checkForTermination(const std::vector< int > &pids)
Check without blocking the supplied processes for termination.
Definition: Fork.hpp:221
#define ThrowBalauException(ExceptionClass,...)
Throw a Balau style exception, with implicit file and line number, and optional stacktrace.
Definition: BalauException.hpp:45
static int performFork(const std::function< int()> &function, bool exitChild)
Perform a fork operator and run the supplied function for the child.
Definition: Fork.hpp:55
Convenience wrapper for forking processes.
Definition: Fork.hpp:31
int code
The signal code.
Definition: Fork.hpp:117
Balau exceptions for system utilities.
static TerminationReport waitOnProcess(int pid)
Wait on a process until the process terminates.
Definition: Fork.hpp:153
static int performFork(const std::function< int()> &function)
Perform a fork operator and run the supplied function for the child.
Definition: Fork.hpp:87
Concurrency control classes.
Definition: CyclicBarrier.hpp:26
A termination report, returned by wait methods.
Definition: Fork.hpp:108
Thrown when a fork call fails.
Definition: SystemExceptions.hpp:58
Assertion utilities for development purposes.
Thrown when a wait call fails.
Definition: SystemExceptions.hpp:70
static TerminationReport checkForTermination(int pid)
Check the process for termination without blocking.
Definition: Fork.hpp:185
int pid
The PID of the process.
Definition: Fork.hpp:112
int exitStatus
The exit status.
Definition: Fork.hpp:122
static void assertion(bool test, StringFunctionT function)
If the bug test assertion fails, abort after logging the message supplied by the function.
Definition: Assert.hpp:49