diff --git a/akit/src/main/native/cpp/ConsoleSource.cpp b/akit/src/main/native/cpp/ConsoleSource.cpp index 41ce7478..c49d5a08 100644 --- a/akit/src/main/native/cpp/ConsoleSource.cpp +++ b/akit/src/main/native/cpp/ConsoleSource.cpp @@ -8,38 +8,117 @@ #include #include #include +#include +#ifdef _WIN32 +#include +#include +#endif #include "akit/ConsoleSource.h" using namespace akit; -SimulatorConsoleSource::SimulatorConsoleSource() : originalCout { - std::cout.rdbuf(&splitCout) }, originalCerr { std::cerr.rdbuf( - &splitCerr) } { +SimulatorConsoleSource::SimulatorConsoleSource() { +#ifdef _WIN32 + _pipe(stdoutPipe, 4096, _O_TEXT); + _pipe(stderrPipe, 4096, _O_TEXT); + + originalCout = _dup(_fileno(stdout)); + originalCerr = _dup(_fileno(stderr)); + + _dup2(stdoutPipe[1], _fileno(stdout)); + _dup2(stderrPipe[1], _fileno(stderr)); + + _close(stdoutPipe[1]); + _close(stderrPipe[1]); +#else + pipe (stdoutPipe); + pipe (stderrPipe); + originalCout = dup(STDOUT_FILENO); + originalCerr = dup(STDERR_FILENO); + + dup2(stdoutPipe[1], STDOUT_FILENO); + dup2(stderrPipe[1], STDERR_FILENO); + + close(stdoutPipe[1]); + close(stderrPipe[1]); + + int flags = fcntl(stdoutPipe[0], F_GETFL, 0); + fcntl(stdoutPipe[0], F_SETFL, flags | O_NONBLOCK); + + flags = fcntl(stderrPipe[0], F_GETFL, 0); + fcntl(stderrPipe[0], F_SETFL, flags | O_NONBLOCK); +#endif + + setvbuf(stdout, NULL, _IONBF, 0); + setvbuf(stderr, NULL, _IONBF, 0); } SimulatorConsoleSource::~SimulatorConsoleSource() { - std::cout.rdbuf(originalCout); - std::cerr.rdbuf(originalCerr); -} + running = false; + thread.join(); -std::string SimulatorConsoleSource::GetNewData() { - std::string fullOut = capturedCout.str(); - std::string newOut = fullOut.substr(coutPos); - coutPos = fullOut.size(); +#ifdef _WIN32 + _dup2(originalCout, _fileno(stdout)); + _dup2(originalCerr, _fileno(stderr)); - std::string fullErr = capturedCerr.str(); - std::string newErr = fullErr.substr(coutPos); - cerrPos = fullErr.size(); + _close(originalCout); + _close(originalCerr); +#else + dup2(originalCout, STDOUT_FILENO); + dup2(originalCerr, STDERR_FILENO); - return newOut + newErr; + close (originalCout); + close (originalCerr); +#endif } -int SimulatorConsoleSource::SplitBuffer::overflow(int c) { - if (c == EOF) - return !EOF; - original->sputc(c); - capture.put(static_cast(c)); - return c; +void SimulatorConsoleSource::Run() { + char buffer[1024]; + while (running) { +#ifdef _WIN32 + DWORD bytesAvailable = 0; + HANDLE hStdOut = reinterpret_cast(_get_osfhandle(stdoutPipe[0])); + if (PeekNamedPipe(hStdOut, NULL, 0, NULL, &bytesAvailable, NULL) && bytesAvailable > 0) { + int count = _read(stdoutPipe[0], buffer, sizeof(buffer)); + if (count > 0) { + _write(originalCout, buffer, count); + std::lock_guard lock{mutex}; + data.append(buffer, count); + } + } + HANDLE hStdErr = reinterpret_cast(_get_osfhandle(stderrPipe[0])); + if (PeekNamedPipe(hStdErr, NULL, 0, NULL, &bytesAvailable, NULL) && bytesAvailable > 0) { + int count = _read(stderrPipe[0], buffer, sizeof(buffer)); + if (count > 0) { + _write(originalCerr, buffer, count); + std::lock_guard lock{mutex}; + data.append(buffer, count); + } + } +#else + ssize_t count = read(stdoutPipe[0], buffer, sizeof(buffer)); + if (count > 0) { + write(originalCout, buffer, count); + std::lock_guard < std::mutex > lock { mutex }; + data.append(buffer, count); + } + count = read(stderrPipe[0], buffer, sizeof(buffer)); + if (count > 0) { + write(originalCerr, buffer, count); + std::lock_guard < std::mutex > lock { mutex }; + data.append(buffer, count); + } +#endif + + std::this_thread::sleep_for(std::chrono::milliseconds { 5 }); + } +} + +std::string SimulatorConsoleSource::GetNewData() { + std::lock_guard < std::mutex > lock { mutex }; + std::string newData = std::move(data); + data.clear(); + return newData; } RoboRIOConsoleSource::~RoboRIOConsoleSource() { diff --git a/akit/src/main/native/include/akit/ConsoleSource.h b/akit/src/main/native/include/akit/ConsoleSource.h index 6c1b90ba..53aee7e9 100644 --- a/akit/src/main/native/include/akit/ConsoleSource.h +++ b/akit/src/main/native/include/akit/ConsoleSource.h @@ -29,31 +29,19 @@ class SimulatorConsoleSource: public ConsoleSource { std::string GetNewData() override; private: - class SplitBuffer: public std::streambuf { - public: - SplitBuffer(std::streambuf *original, std::ostringstream &capture) : original { - original }, capture { capture } { - } - - protected: - int overflow(int c) override; - - private: - std::streambuf *original; - std::ostringstream &capture; - }; + void Run(); - std::streambuf *originalCout; - std::streambuf *originalCerr; + std::atomic running = true; + std::thread thread { &SimulatorConsoleSource::Run, this }; - std::ostringstream capturedCout; - std::ostringstream capturedCerr; + int stdoutPipe[2]; + int stderrPipe[2]; - SplitBuffer splitCout { originalCout, capturedCout }; - SplitBuffer splitCerr { originalCerr, capturedCerr }; + int originalCout; + int originalCerr; - size_t coutPos = 0; - size_t cerrPos = 0; + std::mutex mutex; + std::string data; }; class RoboRIOConsoleSource: public ConsoleSource {