From e9ab67b380734d5c9527376b0b5e38b90bf37b97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Mon, 2 Dec 2024 15:54:59 +0800 Subject: [PATCH] Processing (Linux): interrupt poll & read syscalls when the child process is exited Fix #1418 --- src/common/init.c | 11 +++++++---- src/common/processing_linux.c | 22 ++++++++++++++++++---- 2 files changed, 25 insertions(+), 8 deletions(-) diff --git a/src/common/init.c b/src/common/init.c index 2cdce8df4..d6adc1342 100644 --- a/src/common/init.c +++ b/src/common/init.c @@ -76,19 +76,21 @@ static void resetConsole(void) } #ifdef _WIN32 -BOOL WINAPI consoleHandler(DWORD signal) +BOOL WINAPI consoleHandler(FF_MAYBE_UNUSED DWORD signal) { - FF_UNUSED(signal); resetConsole(); exit(0); } #else -static void exitSignalHandler(int signal) +static void exitSignalHandler(FF_MAYBE_UNUSED int signal) { - FF_UNUSED(signal); resetConsole(); exit(0); } +static void chldSignalHandler(FF_MAYBE_UNUSED int signal) +{ + // empty; used to interrupt the poll and read syscalls +} #endif void ffStart(void) @@ -118,6 +120,7 @@ void ffStart(void) sigaction(SIGINT, &action, NULL); sigaction(SIGTERM, &action, NULL); sigaction(SIGQUIT, &action, NULL); + sigaction(SIGCHLD, &(struct sigaction) { .sa_handler = chldSignalHandler }, NULL); #endif //reset everything to default before we start printing diff --git a/src/common/processing_linux.c b/src/common/processing_linux.c index 3b290bc3d..63d395114 100644 --- a/src/common/processing_linux.c +++ b/src/common/processing_linux.c @@ -1,7 +1,6 @@ #include "fastfetch.h" #include "common/processing.h" #include "common/io/io.h" -#include "common/time.h" #include "util/stringUtils.h" #include "util/mallocHelper.h" @@ -90,6 +89,16 @@ const char* ffProcessAppendOutput(FFstrbuf* buffer, char* const argv[], bool use waitpid(childPid, NULL, 0); return "poll(&pollfd, 1, timeout) timeout (try increasing --processing-timeout)"; } + else if (errno == EINTR) + { + // The child process has been terminated. See `chldSignalHandler` in `common/init.c` + if (waitpid(childPid, NULL, WNOHANG) == childPid) + { + // Read remaining data from the pipe + fcntl(childPipeFd, F_SETFL, O_CLOEXEC | O_NONBLOCK); + childPid = -1; + } + } else if (pollfd.revents & POLLERR) { kill(childPid, SIGTERM); @@ -104,7 +113,7 @@ const char* ffProcessAppendOutput(FFstrbuf* buffer, char* const argv[], bool use else if (nRead == 0) { int stat_loc = 0; - if (waitpid(childPid, &stat_loc, 0) == childPid) + if (childPid > 0 && waitpid(childPid, &stat_loc, 0) == childPid) { if (!WIFEXITED(stat_loc)) return "child process exited abnormally"; @@ -113,10 +122,15 @@ const char* ffProcessAppendOutput(FFstrbuf* buffer, char* const argv[], bool use // We only handle 127 as an error. See `getTerminalVersionUrxvt` in `terminalshell.c` return NULL; } - return "waitpid() failed"; + return NULL; } else if (nRead < 0) - break; + { + if (errno == EAGAIN) + return NULL; + else + break; + } }; return "read(childPipeFd, str, FF_PIPE_BUFSIZ) failed";