aboutsummaryrefslogtreecommitdiff
path: root/works/life/linux-run
diff options
context:
space:
mode:
Diffstat (limited to 'works/life/linux-run')
-rw-r--r--works/life/linux-run/.gitignore2
-rw-r--r--works/life/linux-run/Makefile16
-rw-r--r--works/life/linux-run/linux-run-test-bin.cpp8
-rw-r--r--works/life/linux-run/linux-run-test.cpp26
-rw-r--r--works/life/linux-run/linux-run.cpp215
-rw-r--r--works/life/linux-run/linux-run.h43
6 files changed, 0 insertions, 310 deletions
diff --git a/works/life/linux-run/.gitignore b/works/life/linux-run/.gitignore
deleted file mode 100644
index 6c314b3..0000000
--- a/works/life/linux-run/.gitignore
+++ /dev/null
@@ -1,2 +0,0 @@
-linux-run-test
-linux-run-test-bin
diff --git a/works/life/linux-run/Makefile b/works/life/linux-run/Makefile
deleted file mode 100644
index 7392db6..0000000
--- a/works/life/linux-run/Makefile
+++ /dev/null
@@ -1,16 +0,0 @@
-.PHONY: all test clean
-
-all: linux-run-test linux-run-test-bin
-
-linux-run-test: linux-run.h linux-run.cpp linux-run-test.cpp
- g++ linux-run.cpp linux-run-test.cpp -o linux-run-test
-
-linux-run-test-bin: linux-run-test-bin.cpp
- g++ linux-run-test-bin.cpp -o linux-run-test-bin
-
-
-test: linux-run-test linux-run-test-bin
- ./linux-run-test
-
-clean:
- rm linux-run-test linux-run-test-bin
diff --git a/works/life/linux-run/linux-run-test-bin.cpp b/works/life/linux-run/linux-run-test-bin.cpp
deleted file mode 100644
index 3f7bd94..0000000
--- a/works/life/linux-run/linux-run-test-bin.cpp
+++ /dev/null
@@ -1,8 +0,0 @@
-#include <iostream>
-#include <unistd.h>
-
-int main() {
- sleep(5);
- std::cout << "Hello world!\n";
- return 0;
-}
diff --git a/works/life/linux-run/linux-run-test.cpp b/works/life/linux-run/linux-run-test.cpp
deleted file mode 100644
index fe2486b..0000000
--- a/works/life/linux-run/linux-run-test.cpp
+++ /dev/null
@@ -1,26 +0,0 @@
-#include "linux-run.h"
-
-#include <iostream>
-#include <stdexcept>
-
-int main() {
- using namespace linux_run;
- RunOptions options;
- options.timeout_in_second = 1;
-
- bool caught_timeout_error = false;
-
- try {
- run("./linux-run-test-bin", {}, options);
- } catch (const TimeoutError &e) {
- caught_timeout_error = true;
- }
-
- if (!caught_timeout_error) {
- throw std::runtime_error("Test failed. TimeoutError was not thrown.");
- } else {
- std::cout << "Test succeeded. TimeoutError caught.\n";
- }
-
- return 0;
-}
diff --git a/works/life/linux-run/linux-run.cpp b/works/life/linux-run/linux-run.cpp
deleted file mode 100644
index 0c3ab15..0000000
--- a/works/life/linux-run/linux-run.cpp
+++ /dev/null
@@ -1,215 +0,0 @@
-#include "linux-run.h"
-
-#include <functional>
-#include <stdexcept>
-#include <string>
-#include <vector>
-
-#include <errno.h>
-#include <fcntl.h>
-#include <poll.h>
-#include <signal.h>
-#include <string.h> // for strerror_r (GNU extension)
-#include <sys/signalfd.h>
-#include <sys/wait.h>
-#include <unistd.h>
-
-namespace linux_run {
-static std::string get_errno_message() {
- char buffer[100];
- strerror_r(errno, buffer, 100);
- return std::string(buffer);
-}
-
-static std::string get_errno_message(int custom_errno) {
- char buffer[100];
- strerror_r(custom_errno, buffer, 100);
- return std::string(buffer);
-}
-
-static void create_signal_fd(int *pfd) {
- sigset_t sigset;
- sigemptyset(&sigset);
- sigaddset(&sigset, SIGCHLD);
- if (sigprocmask(SIG_BLOCK, &sigset, nullptr) == -1) {
- throw std::runtime_error("Failed to block SIGCHLD. Reason: " +
- get_errno_message());
- }
-
- sigemptyset(&sigset);
- sigaddset(&sigset, SIGCHLD);
- int fd = signalfd(-1, &sigset, 0);
- if (fd == -1) {
- throw std::runtime_error("Failed to create SIGCHLD fd. Reason: " +
- get_errno_message());
- }
- *pfd = fd;
-}
-
-static void destroy_signal_fd(int fd) {
- if (close(fd) == -1) {
- throw std::runtime_error("Failed to close SIGCHLD fd. Reason: " +
- get_errno_message());
- }
-
- sigset_t sigset;
- sigemptyset(&sigset);
- sigaddset(&sigset, SIGCHLD);
- if (sigprocmask(SIG_UNBLOCK, &sigset, nullptr) == -1) {
- throw std::runtime_error("Failed to unblock SIGCHLD. Reason: " +
- get_errno_message());
- }
-}
-
-static char **
-convert_string_vector_to_argv(const std::string &program,
- const std::vector<std::string> &arguments) {
- char **argv;
- argv = new char *[arguments.size() + 2];
- argv[0] = new char[program.size() + 1];
- strcpy(argv[0], program.c_str());
- for (int i = 0; i < arguments.size(); i++) {
- const auto &argument = arguments[i];
- argv[i + 1] = new char[argument.size() + 1];
- strcpy(argv[i + 1], argument.c_str());
- }
- argv[arguments.size() + 1] = nullptr;
- return argv;
-}
-
-static void redirect_file(int old_file_descriptor, const std::string &path,
- int open_file_flags) {
- if (path.empty())
- return;
- int file_descriptor = open(path.c_str(), open_file_flags);
- if (file_descriptor == -1)
- throw std::runtime_error(
- "Failed to open " + path +
- " for redirection. Reason: " + get_errno_message());
- int dup_r = dup2(file_descriptor, old_file_descriptor);
- if (dup_r == -1)
- throw std::runtime_error(
- "Failed to dup file descriptor for redirection. Reason: " +
- get_errno_message());
- int close_r = close(file_descriptor);
- if (close_r == -1)
- throw std::runtime_error(
- "Failed to close old file descriptor for redirection. Reason: " +
- get_errno_message());
-}
-
-void run(const std::string &program, std::vector<std::string> arguments,
- RunOptions options) {
-
- int sigchld_fd;
- create_signal_fd(&sigchld_fd);
-
- pid_t pid = fork();
- if (pid == 0) {
- destroy_signal_fd(sigchld_fd);
-
- redirect_file(STDIN_FILENO, options.stdin_file_path, O_RDONLY);
- redirect_file(STDOUT_FILENO, options.stdout_file_path,
- O_WRONLY | O_CREAT | O_TRUNC);
- auto argv = convert_string_vector_to_argv(program, arguments);
- int r = execvp(program.c_str(), argv);
- throw std::runtime_error("Failed to exec: " + get_errno_message());
- }
- if (pid == -1) {
- throw std::runtime_error("Failed to fork: " + get_errno_message());
- }
-
- struct pollfd sigchld_poll;
- sigchld_poll.fd = sigchld_fd;
- sigchld_poll.events = POLLIN;
- sigchld_poll.revents = 0;
-
- int timeout_value =
- options.timeout_in_second > 0 ? options.timeout_in_second * 1000 : -1;
-
- while (true) {
- int poll_return = poll(&sigchld_poll, 1, timeout_value);
-
- if (poll_return == 0) {
- kill(pid, SIGKILL);
-
- if (options.stop_reason) {
- *options.stop_reason = StopReason::Killed;
- }
-
- if (options.before_reap_callback) {
- options.before_reap_callback(pid);
- }
-
- // Reap child process.
- if (waitpid(pid, nullptr, 0) == -1) {
- throw std::runtime_error("Failed to reap child process. Reason: " +
- get_errno_message());
- }
- throw TimeoutError("Timeout to run command.");
- } else if (poll_return == -1) {
- if (errno == EINTR) {
- continue;
- } else {
- throw std::runtime_error("Failed to poll. Reason: " +
- get_errno_message());
- }
- } else if (poll_return == 1) {
- break;
- } else {
- throw std::runtime_error("Poll returns a wired value.");
- }
- }
-
- signalfd_siginfo sig_info;
-
- if (sigchld_poll.revents & POLLIN) {
- size_t read_size = sizeof(signalfd_siginfo);
- int read_return = read(sigchld_fd, &sig_info, read_size);
- if (read_return == -1) {
- throw std::runtime_error("Failed to read signal fd. Reason: " +
- get_errno_message());
- } else if (read_return != read_size) {
- throw std::runtime_error("Failed to read signal fd because the return "
- "byte count does not match request.");
- }
- } else {
- throw std::runtime_error("SIGCHLD fd is not readable after poll.");
- }
-
- switch (sig_info.ssi_code) {
- case CLD_EXITED: {
- if (options.stop_reason) {
- *options.stop_reason = StopReason::Exited;
- }
- int exit_code = sig_info.ssi_status;
- if (options.exit_code) {
- *options.exit_code = exit_code;
- }
- if (options.check_exit_code) {
- if (exit_code != 0) {
- throw ExitCodeError("Command exit with nonzero value.");
- }
- }
- } break;
- case CLD_KILLED: {
- if (options.stop_reason) {
- *options.stop_reason = StopReason::Killed;
- }
- } break;
- default:
- throw std::runtime_error("Unsupported sig_info code.");
- }
-
- if (options.before_reap_callback) {
- options.before_reap_callback(pid);
- }
-
- // Reap child.
- if (waitpid(pid, nullptr, 0) == -1) {
- throw std::runtime_error("Failed to reap child process. Reason: " +
- get_errno_message());
- }
-}
-
-} // namespace linux_run
diff --git a/works/life/linux-run/linux-run.h b/works/life/linux-run/linux-run.h
deleted file mode 100644
index d953115..0000000
--- a/works/life/linux-run/linux-run.h
+++ /dev/null
@@ -1,43 +0,0 @@
-#ifndef LINUX_RUN_H
-#define LINUX_RUN_H
-
-#include <functional>
-#include <stdexcept>
-#include <string>
-#include <vector>
-
-namespace linux_run {
-
-enum StopReason { Exited, Killed };
-
-struct RunOptions {
- RunOptions()
- : timeout_in_second(0), check_exit_code(true), stop_reason(nullptr),
- exit_code(nullptr) {}
-
- int timeout_in_second;
- bool check_exit_code;
- std::string stdin_file_path;
- std::string stdout_file_path;
- StopReason *stop_reason;
- int *exit_code;
- // Before reap so you can get final information of the process.
- std::function<void(int pid)> before_reap_callback;
-};
-
-class TimeoutError : std::runtime_error {
-public:
- using runtime_error::runtime_error;
-};
-
-class ExitCodeError : std::runtime_error {
-public:
- using runtime_error::runtime_error;
-};
-
-void run(const std::string &program, std::vector<std::string> arguments,
- RunOptions options);
-
-} // namespace linux_run
-
-#endif