Wake all sleeping threads when leaving suspend

std::condition_variable::wait_for does not count time spent in sleep
mode, resulting in longer than expected waits.
This commit is contained in:
Patrick Nicolas 2023-06-07 10:17:42 +02:00
parent c5379fa52d
commit 3c9cbc99d7
4 changed files with 73 additions and 2 deletions

View File

@ -0,0 +1,9 @@
#pragma once
#include "SafeSignal.hpp"
namespace waybar::util {
// Get a signal emited with value true when entering sleep, and false when exiting
SafeSignal<bool>& prepare_for_sleep();
} // namespace waybar::util

View File

@ -6,6 +6,8 @@
#include <functional> #include <functional>
#include <thread> #include <thread>
#include "prepare_for_sleep.h"
namespace waybar::util { namespace waybar::util {
/** /**
@ -33,7 +35,11 @@ class SleeperThread {
signal_ = false; signal_ = false;
func(); func();
} }
}} {} }} {
connection_ = prepare_for_sleep().connect([this](bool sleep) {
if (not sleep) wake_up();
});
}
SleeperThread& operator=(std::function<void()> func) { SleeperThread& operator=(std::function<void()> func) {
thread_ = std::thread([this, func] { thread_ = std::thread([this, func] {
@ -42,6 +48,11 @@ class SleeperThread {
func(); func();
} }
}); });
if (connection_.empty()) {
connection_ = prepare_for_sleep().connect([this](bool sleep) {
if (not sleep) wake_up();
});
}
return *this; return *this;
} }
@ -61,7 +72,7 @@ class SleeperThread {
return condvar_.wait_until(lk, time_point, [this] { return signal_ || !do_run_; }); return condvar_.wait_until(lk, time_point, [this] { return signal_ || !do_run_; });
} }
auto wake_up() { void wake_up() {
{ {
std::lock_guard<std::mutex> lck(mutex_); std::lock_guard<std::mutex> lck(mutex_);
signal_ = true; signal_ = true;
@ -96,6 +107,7 @@ class SleeperThread {
std::mutex mutex_; std::mutex mutex_;
bool do_run_ = true; bool do_run_ = true;
bool signal_ = false; bool signal_ = false;
sigc::connection connection_;
}; };
} // namespace waybar::util } // namespace waybar::util

View File

@ -170,6 +170,7 @@ src_files = files(
'src/client.cpp', 'src/client.cpp',
'src/config.cpp', 'src/config.cpp',
'src/group.cpp', 'src/group.cpp',
'src/util/prepare_for_sleep.cpp',
'src/util/ustring_clen.cpp', 'src/util/ustring_clen.cpp',
'src/util/sanitize_str.cpp', 'src/util/sanitize_str.cpp',
'src/util/rewrite_string.cpp' 'src/util/rewrite_string.cpp'

View File

@ -0,0 +1,49 @@
#include "util/prepare_for_sleep.h"
#include <gio/gio.h>
namespace {
class PrepareForSleep {
private:
PrepareForSleep() {
GError *error = NULL;
login1_connection = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &error);
if (!login1_connection) {
throw std::runtime_error("Unable to connect to the SYSTEM Bus!...");
} else {
login1_id = g_dbus_connection_signal_subscribe(
login1_connection, "org.freedesktop.login1", "org.freedesktop.login1.Manager",
"PrepareForSleep", "/org/freedesktop/login1", NULL, G_DBUS_SIGNAL_FLAGS_NONE,
prepareForSleep_cb, this, NULL);
}
}
static void prepareForSleep_cb(GDBusConnection *system_bus, const gchar *sender_name,
const gchar *object_path, const gchar *interface_name,
const gchar *signal_name, GVariant *parameters,
gpointer user_data) {
if (g_variant_is_of_type(parameters, G_VARIANT_TYPE("(b)"))) {
gboolean sleeping;
g_variant_get(parameters, "(b)", &sleeping);
PrepareForSleep *self = static_cast<PrepareForSleep *>(user_data);
self->signal.emit(sleeping);
}
}
public:
static PrepareForSleep &GetInstance() {
static PrepareForSleep instance;
return instance;
}
waybar::SafeSignal<bool> signal;
private:
guint login1_id;
GDBusConnection *login1_connection;
};
} // namespace
waybar::SafeSignal<bool> &waybar::util::prepare_for_sleep() {
return PrepareForSleep::GetInstance().signal;
}