summaryrefslogtreecommitdiff
path: root/process.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'process.cpp')
-rw-r--r--process.cpp77
1 files changed, 77 insertions, 0 deletions
diff --git a/process.cpp b/process.cpp
index 41325c3..061737e 100644
--- a/process.cpp
+++ b/process.cpp
@@ -3,6 +3,8 @@
#include <fcntl.h>
#include <signal.h>
#include <sys/wait.h>
+#include <sys/select.h>
+#include <sys/time.h>
#include "process.h"
#include "error.h"
@@ -189,6 +191,81 @@ optional<string> Process::readLine() {
}
}
+optional<string> Process::readLineTimeout(size_t millis) {
+ if (pid == -1) {
+ cout << "-- readLineTimeout on pid==-1 --" << endl;
+ return nullopt;
+ }
+
+ size_t idx = readBuf.find('\n');
+ if (idx != string::npos) {
+ string res = readBuf.substr(0, idx);
+ readBuf = readBuf.substr(idx + 1);
+ return res;
+ }
+
+ struct timeval start;
+ gettimeofday(&start, nullptr);
+
+ struct timeval totaltime;
+ totaltime.tv_sec = millis / 1000;
+ totaltime.tv_usec = millis % 1000 * 1000;
+
+ struct timeval left = totaltime;
+
+ while (true) {
+ string s(1024, '\0');
+
+ ssize_t nr;
+
+ fd_set inset;
+ FD_ZERO(&inset);
+ FD_SET(outfd, &inset);
+ int ret = select(outfd + 1, &inset, nullptr, nullptr, &left);
+ if (ret < 0) {
+ if (errno == EINTR) goto continue_adjust_time_left;
+ perror("select");
+ return nullopt;
+ }
+
+ if (!FD_ISSET(outfd, &inset)) goto continue_adjust_time_left;
+
+ nr = read(outfd, &s[0], s.size());
+ if (nr < 0) {
+ if (errno == EINTR) goto continue_adjust_time_left;
+ perror("read");
+ return nullopt;
+ }
+ if (nr == 0) { // EOF
+ cout << "-- eof in readLine --" << endl;
+ return nullopt;
+ }
+ s.resize(nr);
+
+ idx = s.find('\n');
+ if (idx != string::npos) {
+ string res = readBuf + s.substr(0, idx);
+ readBuf = s.substr(idx + 1);
+ return res;
+ }
+
+ readBuf += s;
+
+ continue_adjust_time_left:
+ struct timeval now, delta;
+ gettimeofday(&now, nullptr);
+ timersub(&now, &start, &delta);
+ timersub(&totaltime, &delta, &left);
+
+ struct timeval zero;
+ timerclear(&zero);
+ // Not greater, so less-equal; c.f. manpage
+ if (!timercmp(&left, &zero, >)) {
+ return nullopt; // Exceeded timeout
+ }
+ }
+}
+
int Process::terminate() {
// TODO: send only SIGTERM, then wait a little while, then send
// SIGKILL if necessary