mirror of
https://git.proxmox.com/git/fwupd
synced 2025-06-26 02:53:00 +00:00
238 lines
4.9 KiB
C
238 lines
4.9 KiB
C
/*
|
|
* Copyright (C) 2018 Richard Hughes <richard@hughsie.com>
|
|
*
|
|
* SPDX-License-Identifier: LGPL-2.1+
|
|
*/
|
|
|
|
#define G_LOG_DOMAIN "FuIdle"
|
|
|
|
#include "config.h"
|
|
|
|
#include "fu-idle.h"
|
|
#include "fu-mutex.h"
|
|
|
|
static void
|
|
fu_idle_finalize(GObject *obj);
|
|
|
|
struct _FuIdle {
|
|
GObject parent_instance;
|
|
GPtrArray *items; /* of FuIdleItem */
|
|
GRWLock items_mutex;
|
|
guint idle_id;
|
|
guint timeout;
|
|
FwupdStatus status;
|
|
};
|
|
|
|
enum { PROP_0, PROP_STATUS, PROP_LAST };
|
|
|
|
static void
|
|
fu_idle_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
|
|
{
|
|
FuIdle *self = FU_IDLE(object);
|
|
switch (prop_id) {
|
|
case PROP_STATUS:
|
|
g_value_set_uint(value, self->status);
|
|
break;
|
|
default:
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void
|
|
fu_idle_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
|
|
{
|
|
switch (prop_id) {
|
|
default:
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
|
|
break;
|
|
}
|
|
}
|
|
|
|
typedef struct {
|
|
gchar *reason;
|
|
guint32 token;
|
|
} FuIdleItem;
|
|
|
|
G_DEFINE_TYPE(FuIdle, fu_idle, G_TYPE_OBJECT)
|
|
|
|
FwupdStatus
|
|
fu_idle_get_status(FuIdle *self)
|
|
{
|
|
g_return_val_if_fail(FU_IS_IDLE(self), FWUPD_STATUS_UNKNOWN);
|
|
return self->status;
|
|
}
|
|
|
|
static void
|
|
fu_idle_set_status(FuIdle *self, FwupdStatus status)
|
|
{
|
|
if (self->status == status)
|
|
return;
|
|
self->status = status;
|
|
g_debug("status now %s", fwupd_status_to_string(status));
|
|
g_object_notify(G_OBJECT(self), "status");
|
|
}
|
|
|
|
static gboolean
|
|
fu_idle_check_cb(gpointer user_data)
|
|
{
|
|
FuIdle *self = FU_IDLE(user_data);
|
|
fu_idle_set_status(self, FWUPD_STATUS_SHUTDOWN);
|
|
return G_SOURCE_CONTINUE;
|
|
}
|
|
|
|
static void
|
|
fu_idle_start(FuIdle *self)
|
|
{
|
|
if (self->idle_id != 0)
|
|
return;
|
|
if (self->timeout == 0)
|
|
return;
|
|
self->idle_id = g_timeout_add_seconds(self->timeout, fu_idle_check_cb, self);
|
|
}
|
|
|
|
static void
|
|
fu_idle_stop(FuIdle *self)
|
|
{
|
|
if (self->idle_id == 0)
|
|
return;
|
|
g_source_remove(self->idle_id);
|
|
self->idle_id = 0;
|
|
}
|
|
|
|
void
|
|
fu_idle_reset(FuIdle *self)
|
|
{
|
|
g_return_if_fail(FU_IS_IDLE(self));
|
|
fu_idle_stop(self);
|
|
if (self->items->len == 0)
|
|
fu_idle_start(self);
|
|
}
|
|
|
|
void
|
|
fu_idle_uninhibit(FuIdle *self, guint32 token)
|
|
{
|
|
g_autoptr(GRWLockWriterLocker) locker = g_rw_lock_writer_locker_new(&self->items_mutex);
|
|
|
|
g_return_if_fail(FU_IS_IDLE(self));
|
|
g_return_if_fail(token != 0);
|
|
g_return_if_fail(locker != NULL);
|
|
|
|
for (guint i = 0; i < self->items->len; i++) {
|
|
FuIdleItem *item = g_ptr_array_index(self->items, i);
|
|
if (item->token == token) {
|
|
g_debug("uninhibiting: %s", item->reason);
|
|
g_ptr_array_remove_index(self->items, i);
|
|
break;
|
|
}
|
|
}
|
|
fu_idle_reset(self);
|
|
}
|
|
|
|
guint32
|
|
fu_idle_inhibit(FuIdle *self, const gchar *reason)
|
|
{
|
|
FuIdleItem *item;
|
|
g_autoptr(GRWLockWriterLocker) locker = g_rw_lock_writer_locker_new(&self->items_mutex);
|
|
|
|
g_return_val_if_fail(FU_IS_IDLE(self), 0);
|
|
g_return_val_if_fail(reason != NULL, 0);
|
|
g_return_val_if_fail(locker != NULL, 0);
|
|
|
|
g_debug("inhibiting: %s", reason);
|
|
item = g_new0(FuIdleItem, 1);
|
|
item->reason = g_strdup(reason);
|
|
item->token = g_random_int_range(1, G_MAXINT);
|
|
g_ptr_array_add(self->items, item);
|
|
fu_idle_reset(self);
|
|
return item->token;
|
|
}
|
|
|
|
void
|
|
fu_idle_set_timeout(FuIdle *self, guint timeout)
|
|
{
|
|
g_return_if_fail(FU_IS_IDLE(self));
|
|
g_debug("setting timeout to %us", timeout);
|
|
self->timeout = timeout;
|
|
fu_idle_reset(self);
|
|
}
|
|
|
|
static void
|
|
fu_idle_item_free(FuIdleItem *item)
|
|
{
|
|
g_free(item->reason);
|
|
g_free(item);
|
|
}
|
|
|
|
FuIdleLocker *
|
|
fu_idle_locker_new(FuIdle *self, const gchar *reason)
|
|
{
|
|
FuIdleLocker *locker = g_new0(FuIdleLocker, 1);
|
|
locker->idle = g_object_ref(self);
|
|
locker->token = fu_idle_inhibit(self, reason);
|
|
return locker;
|
|
}
|
|
|
|
void
|
|
fu_idle_locker_free(FuIdleLocker *locker)
|
|
{
|
|
if (locker == NULL)
|
|
return;
|
|
fu_idle_uninhibit(locker->idle, locker->token);
|
|
g_object_unref(locker->idle);
|
|
g_free(locker);
|
|
}
|
|
|
|
static void
|
|
fu_idle_class_init(FuIdleClass *klass)
|
|
{
|
|
GObjectClass *object_class = G_OBJECT_CLASS(klass);
|
|
GParamSpec *pspec;
|
|
|
|
object_class->finalize = fu_idle_finalize;
|
|
object_class->get_property = fu_idle_get_property;
|
|
object_class->set_property = fu_idle_set_property;
|
|
|
|
/**
|
|
* FuIdle:status:
|
|
*
|
|
* The status of the idle monitor.
|
|
*/
|
|
pspec = g_param_spec_uint("status",
|
|
NULL,
|
|
NULL,
|
|
FWUPD_STATUS_UNKNOWN,
|
|
FWUPD_STATUS_LAST,
|
|
FWUPD_STATUS_UNKNOWN,
|
|
G_PARAM_READABLE | G_PARAM_STATIC_NAME);
|
|
g_object_class_install_property(object_class, PROP_STATUS, pspec);
|
|
}
|
|
|
|
static void
|
|
fu_idle_init(FuIdle *self)
|
|
{
|
|
self->status = FWUPD_STATUS_IDLE;
|
|
self->items = g_ptr_array_new_with_free_func((GDestroyNotify)fu_idle_item_free);
|
|
g_rw_lock_init(&self->items_mutex);
|
|
}
|
|
|
|
static void
|
|
fu_idle_finalize(GObject *obj)
|
|
{
|
|
FuIdle *self = FU_IDLE(obj);
|
|
|
|
fu_idle_stop(self);
|
|
g_rw_lock_clear(&self->items_mutex);
|
|
g_ptr_array_unref(self->items);
|
|
|
|
G_OBJECT_CLASS(fu_idle_parent_class)->finalize(obj);
|
|
}
|
|
|
|
FuIdle *
|
|
fu_idle_new(void)
|
|
{
|
|
FuIdle *self;
|
|
self = g_object_new(FU_TYPE_IDLE, NULL);
|
|
return FU_IDLE(self);
|
|
}
|