forked from indilib/indi
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathProcessController.cpp
171 lines (149 loc) · 4.27 KB
/
ProcessController.cpp
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
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
#include <system_error>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/socket.h>
#include <signal.h>
#include <dirent.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include "ProcessController.h"
ProcessController::ProcessController() {
pid = -1;
cmd = "<unstarted>";
status = 0;
}
ProcessController::~ProcessController() {
}
int ProcessController::getOpenFdCount() {
if (pid == -1) {
throw std::runtime_error(cmd + " is done - cannot check open fd count");
}
#ifdef __linux__
std::string path = "/proc/" + std::to_string(pid) + "/fd";
int count = 0;
auto dirp = opendir(path.c_str());
if (dirp == nullptr) {
throw std::system_error(errno, std::generic_category(), "opendir error: " + path);
}
for(auto dp = readdir(dirp); dp != nullptr; dp = readdir(dirp)) {
std::string name = dp->d_name;
if (name.length() == 0 || name[0] == '.') {
continue;
}
count++;
}
closedir(dirp);
return count;
#else
return 0;
#endif
}
void ProcessController::checkOpenFdCount(int expected, const std::string & msg) {
#ifdef __linux__
int count = getOpenFdCount();
if (count != expected) {
throw std::runtime_error(msg + " " + cmd + " open file count is " + std::to_string(count) + " - expected: " + std::to_string(expected));
}
#else
(void)expected;
(void)msg;
#endif
}
void ProcessController::start(const std::string & path, const std::vector<std::string> & args)
{
if (pid != -1) {
throw std::runtime_error(cmd + " already running");
}
cmd = path;
int argCount = 0;
argCount = args.size();
const char * fullArgs[argCount + 2];
fullArgs[0] = path.c_str();
for(int i = 0; i < argCount ; i++) {
fullArgs[i + 1] = args[i].c_str();
}
fullArgs[1 + argCount] = nullptr;
fprintf(stderr, "Running ");
for(int i = 0; i < 2+ argCount ; ++i) {
fprintf(stderr, " %s", fullArgs[i] ? fullArgs[i] : "<null>");
}
fprintf(stderr, "\n");
// Do fork & exec for the indiserver binary
pid = fork();
if (pid == -1) {
throw std::system_error(errno, std::generic_category(), "fork error");
}
if (pid == 0) {
std::string error = "exec " + path;
// TODO : Close all file descriptor
execv(fullArgs[0], (char * const *) fullArgs);
// Child goes here....
perror(error.c_str());
::exit(1);
}
}
void ProcessController::waitProcessEnd(int exitCode) {
join();
expectExitCode(exitCode);
}
void ProcessController::kill() {
if (pid == -1) {
return;
}
::kill(pid, SIGKILL);
}
void ProcessController::join() {
if (pid == -1) {
return;
}
pid_t waited = waitpid(pid, &status, 0);
if (waited == -1) {
throw std::system_error(errno, std::generic_category(), "waitpid error");
}
pid = -1;
}
void ProcessController::expectDone() {
if (pid == -1) {
return;
}
pid_t waited = waitpid(pid, &status, WNOHANG);
if (waited == -1) {
throw std::system_error(errno, std::generic_category(), "waitpid error");
}
if (waited == 0) {
// No child found... Still running
throw std::runtime_error("Process " + cmd + " not done");
}
pid = -1;
}
void ProcessController::expectAlive() {
if (pid != -1) {
pid_t waited = waitpid(pid, &status, WNOHANG);
if (waited == -1) {
throw std::system_error(errno, std::generic_category(), "waitpid error");
}
if (waited != 0) {
// Process terminated
pid = -1;
return;
}
}
throw std::runtime_error("Process terminated unexpectedly");
}
void ProcessController::expectExitCode(int e) {
expectDone();
if (!WIFEXITED(status)) {
if (WIFSIGNALED(status)) {
throw std::runtime_error(cmd + " got signal " + strsignal(WTERMSIG(status)));
}
// Not sure this is possible at all
throw std::runtime_error(cmd + " exited abnormally");
}
int actual = WEXITSTATUS(status);
if (actual != e) {
throw std::runtime_error("Wrong exit code for " + cmd + ": got " + std::to_string(actual) + " - expecting: " + std::to_string(e));
}
}