blob: 796f6bcb1c7d32fcab9889f0237eea84331e30ab [file] [log] [blame]
Richard Hughes75b965d2018-11-15 13:51:21 +00001/*
2 * Copyright (C) 2018 Richard Hughes <richard@hughsie.com>
3 *
4 * SPDX-License-Identifier: LGPL-2.1+
5 */
6
7#define G_LOG_DOMAIN "FuIdle"
8
9#include "config.h"
10
11#include <glib-object.h>
12
13#include "fu-idle.h"
14#include "fu-mutex.h"
15
16static void fu_idle_finalize (GObject *obj);
17
18struct _FuIdle
19{
20 GObject parent_instance;
21 GPtrArray *items; /* of FuIdleItem */
Richard Hughes161e9b52019-06-12 14:22:45 +010022 GRWLock items_mutex;
Richard Hughes75b965d2018-11-15 13:51:21 +000023 guint idle_id;
24 guint timeout;
25 FwupdStatus status;
26};
27
28enum {
29 PROP_0,
30 PROP_STATUS,
31 PROP_LAST
32};
33
34static void
35fu_idle_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
36{
37 FuIdle *self = FU_IDLE (object);
38 switch (prop_id) {
39 case PROP_STATUS:
40 g_value_set_uint (value, self->status);
41 break;
42 default:
43 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
44 break;
45 }
46}
47
48static void
49fu_idle_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
50{
51 switch (prop_id) {
52 default:
53 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
54 break;
55 }
56}
57
58typedef struct {
59 gchar *reason;
60 guint32 token;
61} FuIdleItem;
62
63G_DEFINE_TYPE (FuIdle, fu_idle, G_TYPE_OBJECT)
64
65FwupdStatus
66fu_idle_get_status (FuIdle *self)
67{
68 g_return_val_if_fail (FU_IS_IDLE (self), FWUPD_STATUS_UNKNOWN);
69 return self->status;
70}
71
72static void
73fu_idle_set_status (FuIdle *self, FwupdStatus status)
74{
75 if (self->status == status)
76 return;
77 self->status = status;
78 g_debug ("status now %s", fwupd_status_to_string (status));
79 g_object_notify (G_OBJECT (self), "status");
80}
81
82static gboolean
83fu_idle_check_cb (gpointer user_data)
84{
85 FuIdle *self = FU_IDLE (user_data);
86 fu_idle_set_status (self, FWUPD_STATUS_SHUTDOWN);
87 return G_SOURCE_CONTINUE;
88}
89
90static void
91fu_idle_start (FuIdle *self)
92{
93 if (self->idle_id != 0)
94 return;
95 if (self->timeout == 0)
96 return;
97 self->idle_id = g_timeout_add_seconds (self->timeout, fu_idle_check_cb, self);
98}
99
100static void
101fu_idle_stop (FuIdle *self)
102{
103 if (self->idle_id == 0)
104 return;
105 g_source_remove (self->idle_id);
106 self->idle_id = 0;
107}
108
109void
110fu_idle_reset (FuIdle *self)
111{
112 g_return_if_fail (FU_IS_IDLE (self));
113 fu_idle_stop (self);
114 if (self->items->len == 0)
115 fu_idle_start (self);
116}
117
118void
119fu_idle_uninhibit (FuIdle *self, guint32 token)
120{
Richard Hughes0fe49142019-11-22 16:56:38 +0000121 g_autoptr(GRWLockWriterLocker) locker = g_rw_lock_writer_locker_new (&self->items_mutex);
Richard Hughes75b965d2018-11-15 13:51:21 +0000122
123 g_return_if_fail (FU_IS_IDLE (self));
124 g_return_if_fail (token != 0);
125 g_return_if_fail (locker != NULL);
126
127 for (guint i = 0; i < self->items->len; i++) {
128 FuIdleItem *item = g_ptr_array_index (self->items, i);
129 if (item->token == token) {
130 g_debug ("uninhibiting: %s", item->reason);
131 g_ptr_array_remove_index (self->items, i);
132 break;
133 }
134 }
135 fu_idle_reset (self);
136}
137
138guint32
139fu_idle_inhibit (FuIdle *self, const gchar *reason)
140{
141 FuIdleItem *item;
Richard Hughes0fe49142019-11-22 16:56:38 +0000142 g_autoptr(GRWLockWriterLocker) locker = g_rw_lock_writer_locker_new (&self->items_mutex);
Richard Hughes75b965d2018-11-15 13:51:21 +0000143
144 g_return_val_if_fail (FU_IS_IDLE (self), 0);
145 g_return_val_if_fail (reason != NULL, 0);
146 g_return_val_if_fail (locker != NULL, 0);
147
148 g_debug ("inhibiting: %s", reason);
149 item = g_new0 (FuIdleItem, 1);
150 item->reason = g_strdup (reason);
151 item->token = g_random_int_range (1, G_MAXINT);
152 g_ptr_array_add (self->items, item);
153 fu_idle_reset (self);
154 return item->token;
155}
156
157void
158fu_idle_set_timeout (FuIdle *self, guint timeout)
159{
160 g_return_if_fail (FU_IS_IDLE (self));
161 g_debug ("setting timeout to %us", timeout);
162 self->timeout = timeout;
163 fu_idle_reset (self);
164}
165
166static void
167fu_idle_item_free (FuIdleItem *item)
168{
169 g_free (item->reason);
170 g_free (item);
171}
172
173FuIdleLocker *
174fu_idle_locker_new (FuIdle *self, const gchar *reason)
175{
176 FuIdleLocker *locker = g_new0 (FuIdleLocker, 1);
177 locker->idle = g_object_ref (self);
178 locker->token = fu_idle_inhibit (self, reason);
179 return locker;
180}
181
182void
183fu_idle_locker_free (FuIdleLocker *locker)
184{
185 if (locker == NULL)
186 return;
187 fu_idle_uninhibit (locker->idle, locker->token);
188 g_object_unref (locker->idle);
189 g_free (locker);
190}
191
192static void
193fu_idle_class_init (FuIdleClass *klass)
194{
195 GObjectClass *object_class = G_OBJECT_CLASS (klass);
196 GParamSpec *pspec;
197
198 object_class->finalize = fu_idle_finalize;
199 object_class->get_property = fu_idle_get_property;
200 object_class->set_property = fu_idle_set_property;
201
202 pspec = g_param_spec_uint ("status", NULL, NULL,
203 FWUPD_STATUS_UNKNOWN,
204 FWUPD_STATUS_LAST,
205 FWUPD_STATUS_UNKNOWN,
206 G_PARAM_READABLE |
207 G_PARAM_STATIC_NAME);
208 g_object_class_install_property (object_class, PROP_STATUS, pspec);
209}
210
211static void
212fu_idle_init (FuIdle *self)
213{
214 self->status = FWUPD_STATUS_IDLE;
215 self->items = g_ptr_array_new_with_free_func ((GDestroyNotify) fu_idle_item_free);
Richard Hughes161e9b52019-06-12 14:22:45 +0100216 g_rw_lock_init (&self->items_mutex);
Richard Hughes75b965d2018-11-15 13:51:21 +0000217}
218
219static void
220fu_idle_finalize (GObject *obj)
221{
222 FuIdle *self = FU_IDLE (obj);
223
224 fu_idle_stop (self);
Richard Hughes161e9b52019-06-12 14:22:45 +0100225 g_rw_lock_clear (&self->items_mutex);
Richard Hughesaae22e42020-06-22 21:32:59 +0100226 g_ptr_array_unref (self->items);
Richard Hughes75b965d2018-11-15 13:51:21 +0000227
228 G_OBJECT_CLASS (fu_idle_parent_class)->finalize (obj);
229}
230
231FuIdle *
232fu_idle_new (void)
233{
234 FuIdle *self;
235 self = g_object_new (FU_TYPE_IDLE, NULL);
236 return FU_IDLE (self);
237}