mirror of
https://github.com/hyprwm/hyprutils.git
synced 2024-11-17 04:55:59 +01:00
os: fixup process possible deadlock
Sloppy, but should work... Process shouldn't be used in performance-critical paths anyways. ref https://github.com/hyprwm/Hyprland/issues/8425
This commit is contained in:
parent
d504d45114
commit
8d21d1dfa9
1 changed files with 40 additions and 14 deletions
|
@ -6,7 +6,9 @@ using namespace Hyprutils::OS;
|
|||
#include <unistd.h>
|
||||
#include <cstring>
|
||||
#include <array>
|
||||
#include <thread>
|
||||
|
||||
#include <sys/fcntl.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
Hyprutils::OS::CProcess::CProcess(const std::string& binary_, const std::vector<std::string>& args_) : binary(binary_), args(args_) {
|
||||
|
@ -57,27 +59,51 @@ bool Hyprutils::OS::CProcess::runSync() {
|
|||
close(outPipe[1]);
|
||||
close(errPipe[1]);
|
||||
|
||||
waitpid(pid, nullptr, 0);
|
||||
out = "";
|
||||
err = "";
|
||||
|
||||
std::string readOutData;
|
||||
std::array<char, 1024> buf;
|
||||
buf.fill(0);
|
||||
|
||||
// wait for read
|
||||
size_t ret = 0;
|
||||
while ((ret = read(outPipe[0], buf.data(), 1023)) > 0) {
|
||||
readOutData += std::string{(char*)buf.data(), ret};
|
||||
ssize_t ret = 0;
|
||||
|
||||
int fdFlags = fcntl(outPipe[0], F_GETFL, 0);
|
||||
if (fcntl(outPipe[0], F_SETFL, fdFlags | O_NONBLOCK) < 0)
|
||||
return false;
|
||||
fdFlags = fcntl(errPipe[0], F_GETFL, 0);
|
||||
if (fcntl(errPipe[0], F_SETFL, fdFlags | O_NONBLOCK) < 0)
|
||||
return false;
|
||||
|
||||
// FIXME: this sucks, but it prevents a pipe deadlock.
|
||||
// Problem is, if we exceed the 64k buffer, we end up in a deadlock.
|
||||
// So, as a "solution", we keep reading until the child pid exits.
|
||||
// If nothing is read from either stdout or stderr, sleep for 100µs, to maybe not peg a core THAT much.
|
||||
// If anyone knows a better solution, feel free to make a MR.
|
||||
|
||||
while (waitpid(pid, nullptr, WNOHANG) == 0) {
|
||||
int any = 0;
|
||||
|
||||
while ((ret = read(outPipe[0], buf.data(), 1023)) > 0) {
|
||||
out += std::string{(char*)buf.data(), (size_t)ret};
|
||||
}
|
||||
|
||||
any += errno == EWOULDBLOCK || errno == EAGAIN ? 1 : 0;
|
||||
|
||||
buf.fill(0);
|
||||
|
||||
while ((ret = read(errPipe[0], buf.data(), 1023)) > 0) {
|
||||
err += std::string{(char*)buf.data(), (size_t)ret};
|
||||
}
|
||||
|
||||
any += errno == EWOULDBLOCK || errno == EAGAIN ? 1 : 0;
|
||||
|
||||
buf.fill(0);
|
||||
|
||||
if (any >= 2)
|
||||
std::this_thread::sleep_for(std::chrono::microseconds(100));
|
||||
}
|
||||
|
||||
out = readOutData;
|
||||
readOutData = "";
|
||||
|
||||
while ((ret = read(errPipe[0], buf.data(), 1023)) > 0) {
|
||||
readOutData += std::string{(char*)buf.data(), ret};
|
||||
}
|
||||
|
||||
err = readOutData;
|
||||
|
||||
close(outPipe[0]);
|
||||
close(errPipe[0]);
|
||||
|
||||
|
|
Loading…
Reference in a new issue