Fixing things for programs with very large output.
This commit is contained in:
@@ -1,5 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
#include "../Executor.hpp"
|
#include "../Executor.hpp"
|
||||||
|
|
||||||
namespace daggy {
|
namespace daggy {
|
||||||
|
|||||||
@@ -1,5 +1,9 @@
|
|||||||
#include <daggy/executors/ForkingExecutor.hpp>
|
#include <daggy/executors/ForkingExecutor.hpp>
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
#include <fcntl.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <wait.h>
|
#include <wait.h>
|
||||||
#include <poll.h>
|
#include <poll.h>
|
||||||
@@ -9,27 +13,21 @@ using namespace daggy::executor;
|
|||||||
std::string slurp(int fd) {
|
std::string slurp(int fd) {
|
||||||
std::string result;
|
std::string result;
|
||||||
|
|
||||||
const size_t BUFFER_SIZE = 4096;
|
const ssize_t BUFFER_SIZE = 4096;
|
||||||
char buffer[BUFFER_SIZE];
|
char buffer[BUFFER_SIZE];
|
||||||
|
|
||||||
struct pollfd pfd{ .fd = fd, .events = POLLIN, .revents = 0 };
|
struct pollfd pfd{ .fd = fd, .events = POLLIN, .revents = 0 };
|
||||||
poll(&pfd, 1, 0);
|
poll(&pfd, 1, 1);
|
||||||
|
|
||||||
while (pfd.revents & POLLIN) {
|
while (pfd.revents & POLLIN) {
|
||||||
ssize_t bytes = read(fd, buffer, BUFFER_SIZE);
|
ssize_t bytes = read(fd, buffer, BUFFER_SIZE);
|
||||||
if (bytes == -1) {
|
if (bytes == 0) {
|
||||||
if (errno == EINTR) {
|
|
||||||
continue;
|
|
||||||
} else {
|
|
||||||
perror("read");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
} else if (bytes == 0) {
|
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
result += buffer;
|
result.append(buffer, bytes);
|
||||||
if (bytes < BUFFER_SIZE) break;
|
|
||||||
}
|
}
|
||||||
|
pfd.revents = 0;
|
||||||
|
poll(&pfd, 1, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
@@ -51,8 +49,8 @@ daggy::AttemptRecord
|
|||||||
argv.push_back(nullptr);
|
argv.push_back(nullptr);
|
||||||
|
|
||||||
// Create the pipe
|
// Create the pipe
|
||||||
int stdoutPipe[2]; pipe(stdoutPipe);
|
int stdoutPipe[2]; pipe2(stdoutPipe, O_DIRECT);
|
||||||
int stderrPipe[2]; pipe(stderrPipe);
|
int stderrPipe[2]; pipe2(stderrPipe, O_DIRECT);
|
||||||
|
|
||||||
pid_t child = fork();
|
pid_t child = fork();
|
||||||
if (child < 0) {
|
if (child < 0) {
|
||||||
@@ -66,8 +64,13 @@ daggy::AttemptRecord
|
|||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::atomic<bool> running = true;
|
||||||
|
std::thread stdoutReader([&]() { while(running) rec.output.append(slurp(stdoutPipe[0])); });
|
||||||
|
std::thread stderrReader([&]() { while(running) rec.error.append(slurp(stderrPipe[0])); });
|
||||||
|
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
waitpid(child, &rc, 0);
|
waitpid(child, &rc, 0);
|
||||||
|
running = false;
|
||||||
|
|
||||||
rec.stopTime = Clock::now();
|
rec.stopTime = Clock::now();
|
||||||
if (WIFEXITED(rc)) {
|
if (WIFEXITED(rc)) {
|
||||||
@@ -76,9 +79,8 @@ daggy::AttemptRecord
|
|||||||
rec.rc = -1;
|
rec.rc = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
stdoutReader.join();
|
||||||
rec.output = slurp(stdoutPipe[0]);
|
stderrReader.join();
|
||||||
rec.error = slurp(stderrPipe[0]);
|
|
||||||
|
|
||||||
close(stdoutPipe[0]);
|
close(stdoutPipe[0]);
|
||||||
close(stderrPipe[0]);
|
close(stderrPipe[0]);
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <filesystem>
|
||||||
|
|
||||||
#include "daggy/executors/ForkingExecutor.hpp"
|
#include "daggy/executors/ForkingExecutor.hpp"
|
||||||
|
|
||||||
@@ -26,4 +27,15 @@ TEST_CASE("Basic Execution", "[forking_executor]") {
|
|||||||
REQUIRE(rec.error == "/usr/bin/expr: syntax error: missing argument after ‘+’\n");
|
REQUIRE(rec.error == "/usr/bin/expr: syntax error: missing argument after ‘+’\n");
|
||||||
REQUIRE(rec.output.empty());
|
REQUIRE(rec.output.empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SECTION("Large Output") {
|
||||||
|
const std::string BIG_FILE{"/usr/share/dict/cracklib-small"};
|
||||||
|
std::vector<std::string> cmd{"/usr/bin/cat", BIG_FILE};
|
||||||
|
|
||||||
|
auto rec = ex.runCommand(cmd);
|
||||||
|
|
||||||
|
REQUIRE(rec.rc == 0);
|
||||||
|
REQUIRE(rec.output.size() == std::filesystem::file_size(BIG_FILE));
|
||||||
|
REQUIRE(rec.error.empty());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user