diff options
Diffstat (limited to 'process.cpp')
-rw-r--r-- | process.cpp | 77 |
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 |