From 3c743a9e9286c41370d7ef5f22ac5da706307173 Mon Sep 17 00:00:00 2001 From: flightlessmango Date: Fri, 5 Apr 2024 01:17:25 +0200 Subject: [PATCH] param: exec: rewrite exec This rewrites the exec function to have a persistent shell. This should reduce or even fix frame time spikes when updating outputs --- src/hud_elements.cpp | 5 ++- src/hud_elements.h | 2 ++ src/meson.build | 3 +- src/shell.cpp | 73 ++++++++++++++++++++++++++++++++++++++++++++ src/shell.h | 33 ++++++++++++++++++++ 5 files changed, 114 insertions(+), 2 deletions(-) create mode 100644 src/shell.cpp create mode 100644 src/shell.h diff --git a/src/hud_elements.cpp b/src/hud_elements.cpp index 853012b2..ced35ef0 100644 --- a/src/hud_elements.cpp +++ b/src/hud_elements.cpp @@ -1658,8 +1658,11 @@ void HudElements::legacy_elements(){ } void HudElements::update_exec(){ + if (!HUDElements.shell) + HUDElements.shell = std::make_unique(); + for(auto& item : exec_list) - item.ret = exec(item.value); + item.ret = HUDElements.shell->exec(item.value + "\n"); } HudElements HUDElements; diff --git a/src/hud_elements.h b/src/hud_elements.h index 5c37d1db..2bba705a 100644 --- a/src/hud_elements.h +++ b/src/hud_elements.h @@ -10,6 +10,7 @@ #include #include "net.h" #include "overlay_params.h" +#include "shell.h" struct Function { std::function run; // Using std::function instead of a raw function pointer for more flexibility @@ -53,6 +54,7 @@ class HudElements{ int refresh = 0; std::unique_ptr winesync_ptr = nullptr; std::unique_ptr net = nullptr; + std::unique_ptr shell = nullptr; void sort_elements(const std::pair& option); void legacy_elements(); diff --git a/src/meson.build b/src/meson.build index 573682b4..3d2d5e07 100644 --- a/src/meson.build +++ b/src/meson.build @@ -92,7 +92,8 @@ if is_unixy 'amdgpu.cpp', 'intel.cpp', 'msm.cpp', - 'net.cpp' + 'net.cpp', + 'shell.cpp' ) opengl_files = files( diff --git a/src/shell.cpp b/src/shell.cpp new file mode 100644 index 00000000..84277aa8 --- /dev/null +++ b/src/shell.cpp @@ -0,0 +1,73 @@ +#include "shell.h" +#include +#include +#include + +std::string Shell::readOutput() { + std::string output; + char buffer[256]; + ssize_t bytesRead; + bool dataAvailable = false; + + // Wait for up to 500 milliseconds for output to become available + for (int i = 0; i < 10; ++i) { + bytesRead = read(from_shell[0], buffer, sizeof(buffer) - 1); + if (bytesRead > 0) { + buffer[bytesRead] = '\0'; + output += buffer; + dataAvailable = true; + break; // Break as soon as we get some data + } else { + std::this_thread::sleep_for(std::chrono::milliseconds(50)); + } + } + + // If we detected data, keep reading until no more is available + while (dataAvailable) { + bytesRead = read(from_shell[0], buffer, sizeof(buffer) - 1); + if (bytesRead > 0) { + buffer[bytesRead] = '\0'; + output += buffer; + } else { + break; // No more data available + } + } + + return output; +} + +Shell::Shell() { + pipe(to_shell); + pipe(from_shell); + + shell_pid = fork(); + + if (shell_pid == 0) { // Child process + close(to_shell[1]); + close(from_shell[0]); + + dup2(to_shell[0], STDIN_FILENO); + dup2(from_shell[1], STDOUT_FILENO); + dup2(from_shell[1], STDERR_FILENO); + execl("/bin/sh", "sh", nullptr); + exit(1); // Exit if execl fails + } else { + close(to_shell[0]); + close(from_shell[1]); + + // Set the read end of the from_shell pipe to non-blocking + setNonBlocking(from_shell[0]); + } +} + +std::string Shell::exec(std::string cmd) { + writeCommand(cmd); + return readOutput(); +} + +Shell::~Shell() { + write(to_shell[1], "exit\n", 5); + close(to_shell[1]); + close(from_shell[0]); + waitpid(shell_pid, nullptr, 0); +} \ No newline at end of file diff --git a/src/shell.h b/src/shell.h new file mode 100644 index 00000000..d23c2327 --- /dev/null +++ b/src/shell.h @@ -0,0 +1,33 @@ +#pragma once +#include +#include +#include +#include +#include +#include + +class Shell { +private: + int to_shell[2]; + int from_shell[2]; + pid_t shell_pid; + + void setNonBlocking(int fd) { + int flags = fcntl(fd, F_GETFL, 0); + fcntl(fd, F_SETFL, flags | O_NONBLOCK); + } + + void writeCommand(const std::string& command) { + write(to_shell[1], command.c_str(), command.length()); + } + + std::string readOutput(); + +public: + Shell(); + ~Shell(); + std::string exec(std::string cmd); + +}; + +extern std::unique_ptr shell;