From d8706af2ea7cb0f668cc26c449b3a9cc46516ede Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matt=C3=A9o=20Delabre?= Date: Fri, 12 Feb 2021 20:15:38 +0100 Subject: [PATCH 1/2] Terminate custom module scripts on exit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit (Fixes #358.) Subprocesses created for custom module scripts were previously left running when the parent Waybar process exited. This patch sets the parent-death signal of child processes (PR_SET_PDEATHSIG on Linux, PROC_PDEATHSIG_CTL on FreeBSD) to SIGTERM. Caveats: * This uses Linux-specific or FreeBSD-specific calls. I don’t know if this project targets other systems? * There is a possibility that Waybar exits after calling `fork()`, but before calling `prctl` to set the parent-death signal. In this case, the child will not receive the SIGTERM signal and will continue to run. I did not handle this case as I consider it quite unlikely, since module scripts are usually launched only when Waybar starts. Please let me know if you think it needs to be handled. Testing: * With `htop` open, run Waybar v0.9.5 with a custom module that has an `exec` script. Terminate the Waybar process and notice that the script’s subprocess stays alive and is now a child of the init process. * Run Waybar with this patch and follow the same steps as above. Notice that this time the script’s subprocess terminates when the parent exits. --- include/util/command.hpp | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/include/util/command.hpp b/include/util/command.hpp index 52655581..3a38da36 100644 --- a/include/util/command.hpp +++ b/include/util/command.hpp @@ -5,6 +5,13 @@ #include #include +#ifdef __linux__ +#include +#endif +#ifdef __FreeBSD__ +#include +#endif + #include extern std::mutex reap_mtx; @@ -77,6 +84,18 @@ inline FILE* open(const std::string& cmd, int& pid) { // Reset sigmask err = pthread_sigmask(SIG_UNBLOCK, &mask, nullptr); if (err != 0) spdlog::error("pthread_sigmask in open failed: {}", strerror(err)); + // Kill child if Waybar exits + int deathsig = SIGTERM; +#ifdef __linux__ + if (prctl(PR_SET_PDEATHSIG, deathsig) != 0) { + spdlog::error("prctl(PR_SET_PDEATHSIG) in open failed: {}", strerror(errno)); + } +#endif +#ifdef __FreeBSD__ + if (procctl(P_PID, 0, PROC_PDEATHSIG_CTL, reinterpret_cast(&deathsig)) == -1) { + spdlog::error("procctl(PROC_PDEATHSIG_CTL) in open failed: {}", strerror(errno)); + } +#endif ::close(fd[0]); dup2(fd[1], 1); setpgid(child_pid, child_pid); From 943ba3a2da2730d536a2f6409dfe61a8523239a6 Mon Sep 17 00:00:00 2001 From: Aleksei Bavshin Date: Tue, 9 Feb 2021 19:24:46 -0800 Subject: [PATCH 2/2] fix: schedule output destruction on idle callback Defer destruction of bars for the output to the next iteration of the event loop to avoid deleting objects referenced by currently executed code. --- include/client.hpp | 1 + src/client.cpp | 10 ++++++++++ 2 files changed, 11 insertions(+) diff --git a/include/client.hpp b/include/client.hpp index 5965f7cd..ec3866ad 100644 --- a/include/client.hpp +++ b/include/client.hpp @@ -51,6 +51,7 @@ class Client { static void handleOutputDescription(void *, struct zxdg_output_v1 *, const char *); void handleMonitorAdded(Glib::RefPtr monitor); void handleMonitorRemoved(Glib::RefPtr monitor); + void handleDeferredMonitorRemoval(Glib::RefPtr monitor); Json::Value config_; Glib::RefPtr style_context_; diff --git a/src/client.cpp b/src/client.cpp index fcfcd98c..1c48c813 100644 --- a/src/client.cpp +++ b/src/client.cpp @@ -179,6 +179,16 @@ void waybar::Client::handleMonitorAdded(Glib::RefPtr monitor) { void waybar::Client::handleMonitorRemoved(Glib::RefPtr monitor) { spdlog::debug("Output removed: {} {}", monitor->get_manufacturer(), monitor->get_model()); + /* This event can be triggered from wl_display_roundtrip called by GTK or our code. + * Defer destruction of bars for the output to the next iteration of the event loop to avoid + * deleting objects referenced by currently executed code. + */ + Glib::signal_idle().connect_once( + sigc::bind(sigc::mem_fun(*this, &Client::handleDeferredMonitorRemoval), monitor), + Glib::PRIORITY_HIGH_IDLE); +} + +void waybar::Client::handleDeferredMonitorRemoval(Glib::RefPtr monitor) { for (auto it = bars.begin(); it != bars.end();) { if ((*it)->output->monitor == monitor) { auto output_name = (*it)->output->name;