5274dba99dc48745c8b5c1fecae37f6d48607668
[m6w6/libmemcached] / testing / lib / ForkAndExec.cpp
1 #include "ForkAndExec.hpp"
2
3 #include <cerrno>
4 #include <cstdio>
5
6 #include <fcntl.h>
7 #include <sys/poll.h>
8 #include <unistd.h>
9
10 ForkAndExec::ForkAndExec(const char *binary_, char **argv_)
11 : ready{-1, -1}
12 , pipes{-1, -1}
13 , binary{binary_}
14 , argv{argv_}
15 {
16 }
17
18 ForkAndExec::~ForkAndExec() {
19 for (auto &pipe : {ready, pipes}) {
20 for (auto m : {READ, WRITE}) {
21 closePipe(pipe[m]);
22 }
23 }
24 }
25
26 int ForkAndExec::createPipe() {
27 if (pipes[mode::READ] == -1) {
28 if(pipe2(pipes, O_NONBLOCK)) {
29 perror("ForkAndExec pipe()");
30 return -1;
31 }
32 }
33
34 return pipes[mode::READ];
35 }
36
37 pid_t ForkAndExec::operator()() {
38 if (!prepareExecReadyPipe()) {
39 return 0;
40 }
41
42 switch (pid_t pid = fork()) {
43 case 0:
44 closePipe(pipes[mode::READ]);
45 prepareOutputPipe();
46 execvp(binary, argv);
47 perror("ForkAndExec exec()");
48 _exit(EXIT_FAILURE);
49
50 case -1:
51 perror("ForkAndExec fork()");
52 return 0;
53
54 default:
55 pipes[mode::READ] = -1;
56 closePipe(pipes[mode::WRITE]);
57 pollExecReadyPipe();
58 return pid;
59 }
60 }
61
62 bool ForkAndExec::prepareExecReadyPipe() {
63 if (ready[mode::READ] == -1) {
64 if (pipe2(ready, O_CLOEXEC | O_NONBLOCK)) {
65 perror("ForkAndExec pipe()");
66 return false;
67 }
68 closePipe(ready[mode::WRITE]);
69 }
70
71 return true;
72 }
73
74 void ForkAndExec::prepareOutputPipe() {
75 if (pipes[mode::WRITE] != -1) {
76 if (0 > dup2(pipes[mode::WRITE], STDERR_FILENO) ||
77 0 > dup2(pipes[mode::WRITE], STDOUT_FILENO)) {
78 perror("ForkAndExec dup()");
79 }
80 }
81 }
82
83 void ForkAndExec::closePipe(int &fd) {
84 if (fd != -1) {
85 close(fd);
86 fd = -1;
87 }
88 }
89
90 void ForkAndExec::pollExecReadyPipe() {
91 pollfd fd{ready[mode::READ], 0, 0};
92 if (1 > poll(&fd, 1, 5000)) {
93 cerr << "exec() timed out" << endl;
94 }
95 }