From 38c29fc2426557b43af91e7557c40f7880aaa0b8 Mon Sep 17 00:00:00 2001 From: Aleksei Bavshin Date: Tue, 2 Feb 2021 19:17:06 -0800 Subject: [PATCH] refactor(rfkill): poll rfkill events from Glib main loop Open rfkill device only once per module. Remove rfkill threads and use `Glib::signal_io` as a more efficient way to poll the rfkill device. Handle runtime errors from rfkill and stop polling of the device instead of crashing waybar. --- include/modules/bluetooth.hpp | 16 ++++---- include/modules/network.hpp | 2 - include/util/rfkill.hpp | 15 +++++-- src/modules/bluetooth.cpp | 8 +--- src/modules/network.cpp | 17 ++++---- src/util/rfkill.cpp | 73 ++++++++++++++++++----------------- 6 files changed, 64 insertions(+), 67 deletions(-) diff --git a/include/modules/bluetooth.hpp b/include/modules/bluetooth.hpp index 04c213da..716df0eb 100644 --- a/include/modules/bluetooth.hpp +++ b/include/modules/bluetooth.hpp @@ -1,11 +1,11 @@ #pragma once -#include -#include "ALabel.hpp" - #include -#include "util/sleeper_thread.hpp" +#include + +#include "ALabel.hpp" #include "util/rfkill.hpp" +#include "util/sleeper_thread.hpp" namespace waybar::modules { @@ -16,11 +16,9 @@ class Bluetooth : public ALabel { auto update() -> void; private: - std::string status_; - util::SleeperThread thread_; - util::SleeperThread intervall_thread_; - - util::Rfkill rfkill_; + std::string status_; + util::SleeperThread thread_; + util::Rfkill rfkill_; }; } // namespace waybar::modules diff --git a/include/modules/network.hpp b/include/modules/network.hpp index c02d3c5e..539f4583 100644 --- a/include/modules/network.hpp +++ b/include/modules/network.hpp @@ -75,8 +75,6 @@ class Network : public ALabel { util::SleeperThread thread_; util::SleeperThread thread_timer_; #ifdef WANT_RFKILL - util::SleeperThread thread_rfkill_; - util::Rfkill rfkill_; #endif }; diff --git a/include/util/rfkill.hpp b/include/util/rfkill.hpp index ac3d406b..5d519cae 100644 --- a/include/util/rfkill.hpp +++ b/include/util/rfkill.hpp @@ -1,19 +1,26 @@ #pragma once +#include #include +#include +#include namespace waybar::util { -class Rfkill { +class Rfkill : public sigc::trackable { public: Rfkill(enum rfkill_type rfkill_type); - ~Rfkill() = default; - void waitForEvent(); + ~Rfkill(); bool getState() const; + sigc::signal on_update; + private: enum rfkill_type rfkill_type_; - int state_ = 0; + bool state_ = false; + int fd_ = -1; + + bool on_event(Glib::IOCondition cond); }; } // namespace waybar::util diff --git a/src/modules/bluetooth.cpp b/src/modules/bluetooth.cpp index b390976a..9939cc19 100644 --- a/src/modules/bluetooth.cpp +++ b/src/modules/bluetooth.cpp @@ -1,17 +1,11 @@ #include "modules/bluetooth.hpp" -#include "util/rfkill.hpp" -#include -#include waybar::modules::Bluetooth::Bluetooth(const std::string& id, const Json::Value& config) : ALabel(config, "bluetooth", id, "{icon}", 10), status_("disabled"), rfkill_{RFKILL_TYPE_BLUETOOTH} { + rfkill_.on_update.connect(sigc::hide(sigc::mem_fun(*this, &Bluetooth::update))); thread_ = [this] { - dp.emit(); - rfkill_.waitForEvent(); - }; - intervall_thread_ = [this] { auto now = std::chrono::system_clock::now(); auto timeout = std::chrono::floor(now + interval_); auto diff = std::chrono::seconds(timeout.time_since_epoch().count() % interval_.count()); diff --git a/src/modules/network.cpp b/src/modules/network.cpp index 7d9da8b5..41bc9d51 100644 --- a/src/modules/network.cpp +++ b/src/modules/network.cpp @@ -212,18 +212,15 @@ void waybar::modules::Network::worker() { thread_timer_.sleep_for(interval_); }; #ifdef WANT_RFKILL - thread_rfkill_ = [this] { - rfkill_.waitForEvent(); - { - std::lock_guard lock(mutex_); - if (ifid_ > 0) { - getInfo(); - dp.emit(); - } + rfkill_.on_update.connect([this](auto &) { + std::lock_guard lock(mutex_); + if (ifid_ > 0) { + getInfo(); + dp.emit(); } - }; + }); #else - spdlog::warn("Waybar has been built without rfkill support."); + spdlog::warn("Waybar has been built without rfkill support."); #endif thread_ = [this] { std::array events{}; diff --git a/src/util/rfkill.cpp b/src/util/rfkill.cpp index e968ca18..d3eb516a 100644 --- a/src/util/rfkill.cpp +++ b/src/util/rfkill.cpp @@ -19,60 +19,63 @@ #include "util/rfkill.hpp" #include +#include #include -#include -#include +#include #include #include -#include -#include -waybar::util::Rfkill::Rfkill(const enum rfkill_type rfkill_type) : rfkill_type_(rfkill_type) {} - -void waybar::util::Rfkill::waitForEvent() { - struct rfkill_event event; - struct pollfd p; - ssize_t len; - int fd, n; - - fd = open("/dev/rfkill", O_RDONLY); - if (fd < 0) { - throw std::runtime_error("Can't open RFKILL control device"); +waybar::util::Rfkill::Rfkill(const enum rfkill_type rfkill_type) : rfkill_type_(rfkill_type) { + fd_ = open("/dev/rfkill", O_RDONLY); + if (fd_ < 0) { + spdlog::error("Can't open RFKILL control device"); return; } + int rc = fcntl(fd_, F_SETFL, O_NONBLOCK); + if (rc < 0) { + spdlog::error("Can't set RFKILL control device to non-blocking: {}", errno); + close(fd_); + fd_ = -1; + return; + } + Glib::signal_io().connect( + sigc::mem_fun(*this, &Rfkill::on_event), fd_, Glib::IO_IN | Glib::IO_ERR | Glib::IO_HUP); +} - memset(&p, 0, sizeof(p)); - p.fd = fd; - p.events = POLLIN | POLLHUP; +waybar::util::Rfkill::~Rfkill() { + if (fd_ >= 0) { + close(fd_); + } +} - while (1) { - n = poll(&p, 1, -1); - if (n < 0) { - throw std::runtime_error("Failed to poll RFKILL control device"); - break; - } +bool waybar::util::Rfkill::on_event(Glib::IOCondition cond) { + if (cond & Glib::IO_IN) { + struct rfkill_event event; + ssize_t len; - if (n == 0) continue; - - len = read(fd, &event, sizeof(event)); + len = read(fd_, &event, sizeof(event)); if (len < 0) { - throw std::runtime_error("Reading of RFKILL events failed"); - break; + spdlog::error("Reading of RFKILL events failed: {}", errno); + return false; } if (len < RFKILL_EVENT_SIZE_V1) { - throw std::runtime_error("Wrong size of RFKILL event"); - continue; + if (errno != EAGAIN) { + spdlog::error("Wrong size of RFKILL event: {}", len); + } + return true; } - if (event.type == rfkill_type_ && event.op == RFKILL_OP_CHANGE) { + if (event.type == rfkill_type_ && (event.op == RFKILL_OP_ADD || event.op == RFKILL_OP_CHANGE)) { state_ = event.soft || event.hard; - break; + on_update.emit(event); } + return true; + } else { + spdlog::error("Failed to poll RFKILL control device"); + return false; } - - close(fd); } bool waybar::util::Rfkill::getState() const { return state_; }