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 outputspull/1290/head
parent
bdd2a02a10
commit
3c743a9e92
@ -0,0 +1,73 @@
|
||||
#include "shell.h"
|
||||
#include <thread>
|
||||
#include <iostream>
|
||||
#include <sys/wait.h>
|
||||
|
||||
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);
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
#pragma once
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <cstring>
|
||||
#include <sys/wait.h>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
|
||||
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> shell;
|
Loading…
Reference in New Issue