Instrument Neutral Distributed Interface INDI 2.2.5
ProcessController.cpp
Go to the documentation of this file.
1#include <system_error>
2#include <unistd.h>
3#include <string.h>
4#include <sys/types.h>
5#include <sys/wait.h>
6#include <sys/socket.h>
7#include <signal.h>
8#include <dirent.h>
9#include <errno.h>
10#include <unistd.h>
11#include <fcntl.h>
12
13#include "ProcessController.h"
14
16 pid = -1;
17 cmd = "<unstarted>";
18 status = 0;
19}
20
23
24
26 if (pid == -1) {
27 throw std::runtime_error(cmd + " is done - cannot check open fd count");
28 }
29#ifdef __linux__
30 std::string path = "/proc/" + std::to_string(pid) + "/fd";
31
32 int count = 0;
33 auto dirp = opendir(path.c_str());
34 if (dirp == nullptr) {
35 throw std::system_error(errno, std::generic_category(), "opendir error: " + path);
36 }
37
38 for(auto dp = readdir(dirp); dp != nullptr; dp = readdir(dirp)) {
39 std::string name = dp->d_name;
40 if (name.length() == 0 || name[0] == '.') {
41 continue;
42 }
43 count++;
44 }
45 closedir(dirp);
46 return count;
47#else
48 return 0;
49#endif
50}
51
52void ProcessController::checkOpenFdCount(int expected, const std::string & msg) {
53#ifdef __linux__
54 int count = getOpenFdCount();
55 if (count != expected) {
56 throw std::runtime_error(msg + " " + cmd + " open file count is " + std::to_string(count) + " - expected: " + std::to_string(expected));
57 }
58#else
59 (void)expected;
60 (void)msg;
61#endif
62}
63
64void ProcessController::start(const std::string & path, const std::vector<std::string> & args)
65{
66 if (pid != -1) {
67 throw std::runtime_error(cmd + " already running");
68 }
69
70 cmd = path;
71
72 int argCount = 0;
73 argCount = args.size();
74 std::vector<const char *> fullArgs(argCount + 2);
75 fullArgs[0] = path.c_str();
76 for(int i = 0; i < argCount ; i++) {
77 fullArgs[i + 1] = args[i].c_str();
78 }
79 fullArgs[1 + argCount] = nullptr;
80 fprintf(stderr, "Running ");
81 for(int i = 0; i < 2+ argCount ; ++i) {
82 fprintf(stderr, " %s", fullArgs[i] ? fullArgs[i] : "<null>");
83 }
84 fprintf(stderr, "\n");
85 // Do fork & exec for the indiserver binary
86 pid = fork();
87 if (pid == -1) {
88 throw std::system_error(errno, std::generic_category(), "fork error");
89 }
90 if (pid == 0) {
91 std::string error = "exec " + path;
92 // TODO : Close all file descriptor
93 execv(fullArgs[0], (char * const *) fullArgs.data());
94
95 // Child goes here....
96 perror(error.c_str());
97 ::exit(1);
98 }
99}
100
102 join();
103 expectExitCode(exitCode);
104}
105
107 if (pid == -1) {
108 return;
109 }
110 ::kill(pid, SIGKILL);
111}
112
114 if (pid == -1) {
115 return;
116 }
117 pid_t waited = waitpid(pid, &status, 0);
118 if (waited == -1) {
119 throw std::system_error(errno, std::generic_category(), "waitpid error");
120 }
121 pid = -1;
122}
123
125 if (pid == -1) {
126 return;
127 }
128
129 pid_t waited = waitpid(pid, &status, WNOHANG);
130 if (waited == -1) {
131 throw std::system_error(errno, std::generic_category(), "waitpid error");
132 }
133 if (waited == 0) {
134 // No child found... Still running
135 throw std::runtime_error("Process " + cmd + " not done");
136 }
137
138 pid = -1;
139}
140
142 if (pid != -1) {
143 pid_t waited = waitpid(pid, &status, WNOHANG);
144 if (waited == -1) {
145 throw std::system_error(errno, std::generic_category(), "waitpid error");
146 }
147 if (waited != 0) {
148 // Process terminated
149 pid = -1;
150 return;
151 }
152 }
153
154 throw std::runtime_error("Process terminated unexpectedly");
155}
156
158 expectDone();
159
160 if (!WIFEXITED(status)) {
161 if (WIFSIGNALED(status)) {
162 throw std::runtime_error(cmd + " got signal " + strsignal(WTERMSIG(status)));
163 }
164 // Not sure this is possible at all
165 throw std::runtime_error(cmd + " exited abnormally");
166 }
167 int actual = WEXITSTATUS(status);
168 if (actual != e) {
169 throw std::runtime_error("Wrong exit code for " + cmd + ": got " + std::to_string(actual) + " - expecting: " + std::to_string(e));
170 }
171}
void start(const std::string &path, const std::vector< std::string > &args)
void checkOpenFdCount(int expected, const std::string &msg)
void waitProcessEnd(int expectedExitCode)
int errno