From c655adea9348bcf522cc80841af5a83d575b8f8d Mon Sep 17 00:00:00 2001
From: patrick96
Date: Thu, 3 Mar 2022 23:38:51 +0100
Subject: [PATCH] fix(script): Prevent stalling during shutdown
If a script module is waiting on a non-tailed script to finish, polybar
cannot shut down until the script has terminted.
To remedy this, we use the same polling loop as for tailed scripts which
checks if it needs to terminate after every iteration.
---
CHANGELOG.md | 1 +
src/adapters/script_runner.cpp | 25 ++++++++++++++++++++++---
2 files changed, 23 insertions(+), 3 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 69509043..78bdc073 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -17,6 +17,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Fixed
- `tray-offset-x`, `tray-offset-y`, `offset-x`, and `offset-y` were mistakenly capped below at 0 ([`#2620`](https://github.com/polybar/polybar/pull/2620))
+- `custom/script`: Polybar shutdown being stalled by hanging script ([`#2621`](https://github.com/polybar/polybar/pull/2621))
## [3.6.0] - 2022-03-01
### Breaking
diff --git a/src/adapters/script_runner.cpp b/src/adapters/script_runner.cpp
index ac8dd041..ce8fef73 100644
--- a/src/adapters/script_runner.cpp
+++ b/src/adapters/script_runner.cpp
@@ -96,16 +96,35 @@ script_runner::interval script_runner::run() {
auto cmd = command_util::make_command(exec);
try {
- cmd->exec(true, m_env);
+ cmd->exec(false, m_env);
} catch (const exception& err) {
m_log.err("script_runner: %s", err.what());
throw modules::module_error("Failed to execute command, stopping module...");
}
- m_exit_status = cmd->get_exit_status();
int fd = cmd->get_stdout(PIPE_READ);
assert(fd != -1);
- bool changed = io_util::poll_read(fd) && set_output(cmd->readline());
+
+ bool changed = false;
+
+ bool got_output = false;
+ while (!m_stopping && cmd->is_running() && !io_util::poll(fd, POLLHUP, 0)) {
+ /**
+ * For non-tailed scripts, we only use the first line. However, to ensure interruptability when the module shuts
+ * down, we still need to continue polling.
+ */
+ if (io_util::poll_read(fd, 25) && !got_output) {
+ changed = set_output(cmd->readline());
+ got_output = true;
+ }
+ }
+
+ if (m_stopping) {
+ cmd->terminate();
+ return 0s;
+ }
+
+ m_exit_status = cmd->wait();
if (!changed && m_exit_status != 0) {
clear_output();