diff --git a/CHANGELOG.md b/CHANGELOG.md index 4d03cedc..04063b28 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -143,6 +143,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Increased the double click interval from 150ms to 400ms. ### Fixed +- `custom/script`: Concurrency issues with fast-updating tailed scripts. + ([`#1978`](https://github.com/polybar/polybar/issues/1978)) - Trailing space after the layout label when indicators are empty and made sure right amount of spacing is added between the indicator labels, in the xkeyboard module. ([`#2292`](https://github.com/polybar/polybar/issues/2292)) diff --git a/cmake/cxx.cmake b/cmake/cxx.cmake index 128b12ca..fa6776af 100644 --- a/cmake/cxx.cmake +++ b/cmake/cxx.cmake @@ -99,11 +99,11 @@ elseif (CMAKE_BUILD_TYPE_UPPER STREQUAL "COVERAGE") list(APPEND cxx_flags ${cxx_coverage}) endif() -list(APPEND cxx_linker_flags ${cxx_flags}) - string(REPLACE " " ";" polybar_flags_list "${POLYBAR_FLAGS}") list(APPEND cxx_flags ${polybar_flags_list}) +list(APPEND cxx_linker_flags ${cxx_flags}) + string(REPLACE ";" " " cxx_flags_str "${cxx_flags}") string(REPLACE ";" " " cxx_linker_flags_str "${cxx_linker_flags}") diff --git a/include/adapters/script_runner.hpp b/include/adapters/script_runner.hpp new file mode 100644 index 00000000..9ecec1c1 --- /dev/null +++ b/include/adapters/script_runner.hpp @@ -0,0 +1,57 @@ +#pragma once + +#include +#include +#include + +#include "common.hpp" +#include "components/logger.hpp" + +POLYBAR_NS + +class script_runner { + public: + using interval = std::chrono::duration; + script_runner(std::function on_update, const string& exec, const string& exec_if, bool tail, + interval interval, const vector>& env); + + bool check_condition() const; + interval process(); + + void clear_output(); + + void stop(); + + int get_pid() const; + int get_counter() const; + + string get_output(); + + bool is_stopping() const; + + protected: + bool set_output(const string&&); + + interval run_tail(); + interval run(); + + private: + const logger& m_log; + + const std::function m_on_update; + + const string m_exec; + const string m_exec_if; + const bool m_tail; + const interval m_interval; + const vector> m_env; + + std::mutex m_output_lock; + string m_output; + + std::atomic_int m_counter{0}; + std::atomic_bool m_stopping{false}; + std::atomic_int m_pid{-1}; +}; + +POLYBAR_NS_END diff --git a/include/components/eventloop.hpp b/include/components/eventloop.hpp index 26f030be..553bdff4 100644 --- a/include/components/eventloop.hpp +++ b/include/components/eventloop.hpp @@ -70,7 +70,7 @@ struct UVHandleGeneric { return unpackedThis->func(std::forward(args)...); } - H* handle; + H* handle{nullptr}; function func; }; diff --git a/include/modules/meta/base.inl b/include/modules/meta/base.inl index c7742744..182a2ab2 100644 --- a/include/modules/meta/base.inl +++ b/include/modules/meta/base.inl @@ -20,6 +20,8 @@ namespace modules { , m_bar(bar) , m_log(logger::make()) , m_conf(config::make()) + // TODO this cast is illegal because 'this' is not yet of type Impl but only of type module + // Change action router to use lambdas , m_router(make_unique>(CAST_MOD(Impl))) , m_name("module/" + name) , m_name_raw(name) @@ -27,22 +29,21 @@ namespace modules { , m_formatter(make_unique(m_conf, m_name)) , m_handle_events(m_conf.get(m_name, "handle-events", true)) , m_visible(!m_conf.get(m_name, "hidden", false)) { - m_router->register_action(EVENT_MODULE_TOGGLE, &module::action_module_toggle); - m_router->register_action(EVENT_MODULE_SHOW, &module::action_module_show); - m_router->register_action(EVENT_MODULE_HIDE, &module::action_module_hide); - } + m_router->register_action(EVENT_MODULE_TOGGLE, &module::action_module_toggle); + m_router->register_action(EVENT_MODULE_SHOW, &module::action_module_show); + m_router->register_action(EVENT_MODULE_HIDE, &module::action_module_hide); + } template module::~module() noexcept { m_log.trace("%s: Deconstructing", name()); - for (auto&& thread_ : m_threads) { - if (thread_.joinable()) { - thread_.join(); - } - } - if (m_mainthread.joinable()) { - m_mainthread.join(); + if (running()) { + /* + * We can't stop in the destructor because we have to call the subclasses which at this point already have been + * destructed. + */ + m_log.err("%s: Module was not stopped before deconstructing.", name()); } } @@ -87,6 +88,15 @@ namespace modules { CAST_MOD(Impl)->wakeup(); CAST_MOD(Impl)->teardown(); + for (auto&& thread_ : m_threads) { + if (thread_.joinable()) { + thread_.join(); + } + } + if (m_mainthread.joinable()) { + m_mainthread.join(); + } + m_sig.emit(signals::eventqueue::check_state{}); } } diff --git a/include/modules/script.hpp b/include/modules/script.hpp index 0ce8bea1..c00dcdbf 100644 --- a/include/modules/script.hpp +++ b/include/modules/script.hpp @@ -1,5 +1,6 @@ #pragma once +#include "adapters/script_runner.hpp" #include "modules/meta/base.hpp" #include "utils/command.hpp" #include "utils/io.hpp" @@ -10,7 +11,6 @@ namespace modules { class script_module : public module { public: explicit script_module(const bar_settings&, string); - ~script_module() {} void start() override; void stop() override; @@ -21,32 +21,19 @@ namespace modules { static constexpr auto TYPE = "custom/script"; protected: - chrono::duration process(const mutex_wrapper()>>& handler) const; bool check_condition(); private: static constexpr const char* TAG_LABEL{"