mirror of
https://github.com/hyprwm/hyprutils.git
synced 2024-11-17 07:15:58 +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 <unistd.h>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <array>
|
#include <array>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
|
#include <sys/fcntl.h>
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
|
|
||||||
Hyprutils::OS::CProcess::CProcess(const std::string& binary_, const std::vector<std::string>& args_) : binary(binary_), args(args_) {
|
Hyprutils::OS::CProcess::CProcess(const std::string& binary_, const std::vector<std::string>& args_) : binary(binary_), args(args_) {
|
||||||
|
@ -57,26 +59,50 @@ bool Hyprutils::OS::CProcess::runSync() {
|
||||||
close(outPipe[1]);
|
close(outPipe[1]);
|
||||||
close(errPipe[1]);
|
close(errPipe[1]);
|
||||||
|
|
||||||
waitpid(pid, nullptr, 0);
|
out = "";
|
||||||
|
err = "";
|
||||||
|
|
||||||
std::string readOutData;
|
|
||||||
std::array<char, 1024> buf;
|
std::array<char, 1024> buf;
|
||||||
buf.fill(0);
|
buf.fill(0);
|
||||||
|
|
||||||
// wait for read
|
// wait for read
|
||||||
size_t ret = 0;
|
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) {
|
while ((ret = read(outPipe[0], buf.data(), 1023)) > 0) {
|
||||||
readOutData += std::string{(char*)buf.data(), ret};
|
out += std::string{(char*)buf.data(), (size_t)ret};
|
||||||
}
|
}
|
||||||
|
|
||||||
out = readOutData;
|
any += errno == EWOULDBLOCK || errno == EAGAIN ? 1 : 0;
|
||||||
readOutData = "";
|
|
||||||
|
buf.fill(0);
|
||||||
|
|
||||||
while ((ret = read(errPipe[0], buf.data(), 1023)) > 0) {
|
while ((ret = read(errPipe[0], buf.data(), 1023)) > 0) {
|
||||||
readOutData += std::string{(char*)buf.data(), ret};
|
err += std::string{(char*)buf.data(), (size_t)ret};
|
||||||
}
|
}
|
||||||
|
|
||||||
err = readOutData;
|
any += errno == EWOULDBLOCK || errno == EAGAIN ? 1 : 0;
|
||||||
|
|
||||||
|
buf.fill(0);
|
||||||
|
|
||||||
|
if (any >= 2)
|
||||||
|
std::this_thread::sleep_for(std::chrono::microseconds(100));
|
||||||
|
}
|
||||||
|
|
||||||
close(outPipe[0]);
|
close(outPipe[0]);
|
||||||
close(errPipe[0]);
|
close(errPipe[0]);
|
||||||
|
|
Loading…
Reference in a new issue