summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGaƫl Bonithon <gael@xfce.org>2022-01-11 11:04:52 +0100
committerAndre Miranda <andreldm@xfce.org>2022-03-05 16:56:48 +0000
commit0e3355a8dd9c732dfa09ff1528f5fef9de17af39 (patch)
tree017063244b31258cc673add0fd2f70db1c029f82
parent4784fd5c274255d574c6fa600c1ce83dea76d159 (diff)
downloadxfconf-0e3355a8dd9c732dfa09ff1528f5fef9de17af39.tar.gz
Add a lifecycle manager to xfconfd
Copied from Tumbler, with some adjustments. Closes #28, see !19 for more details.
-rw-r--r--xfconfd/Makefile.am2
-rw-r--r--xfconfd/main.c16
-rw-r--r--xfconfd/xfconf-daemon.c77
-rw-r--r--xfconfd/xfconf-daemon.h2
-rw-r--r--xfconfd/xfconf-lifecycle-manager.c224
-rw-r--r--xfconfd/xfconf-lifecycle-manager.h51
6 files changed, 336 insertions, 36 deletions
diff --git a/xfconfd/Makefile.am b/xfconfd/Makefile.am
index d7fdfcb..248efb6 100644
--- a/xfconfd/Makefile.am
+++ b/xfconfd/Makefile.am
@@ -26,6 +26,8 @@ xfconfd_SOURCES = \
xfconf-backend.h \
xfconf-daemon.c \
xfconf-daemon.h \
+ xfconf-lifecycle-manager.c \
+ xfconf-lifecycle-manager.h \
xfconf-locking-utils.c \
xfconf-locking-utils.h \
$(xfconf_backend_sources) \
diff --git a/xfconfd/main.c b/xfconfd/main.c
index 1965210..c2b3830 100644
--- a/xfconfd/main.c
+++ b/xfconfd/main.c
@@ -136,6 +136,7 @@ main(int argc,
{
GMainLoop *mloop;
XfconfDaemon *xfconfd;
+ XfconfLifecycleManager *manager;
GError *error = NULL;
struct sigaction act = {0};
GIOChannel *signal_io;
@@ -220,15 +221,21 @@ main(int argc,
backends = g_new0(gchar *, 2);
backends[0] = g_strdup(DEFAULT_BACKEND);
}
-
- xfconfd = xfconf_daemon_new_unique(backends, &error);
+
+ manager = xfconf_lifecycle_manager_new ();
+ xfconfd = xfconf_daemon_new_unique (backends, manager, &error);
if(!xfconfd) {
g_critical("Xfconfd failed to start: %s\n", error->message);
+ g_object_unref (manager);
g_error_free(error);
return EXIT_FAILURE;
}
g_strfreev(backends);
-
+
+ /* quit the main loop when the xfconf daemon asks us to shutdown */
+ g_signal_connect_swapped (manager, "shutdown", G_CALLBACK (g_main_loop_quit), mloop);
+ xfconf_lifecycle_manager_start (manager);
+
/* acquire name */
is_test_mode = g_getenv ("XFCONF_RUN_IN_TEST_MODE");
g_bus_own_name (G_BUS_TYPE_SESSION,
@@ -256,7 +263,8 @@ main(int argc,
g_main_loop_run(mloop);
- g_object_unref(G_OBJECT(xfconfd));
+ g_object_unref (xfconfd);
+ g_object_unref (manager);
xfconf_backend_factory_cleanup();
diff --git a/xfconfd/xfconf-daemon.c b/xfconfd/xfconf-daemon.c
index fbe5da3..314b76c 100644
--- a/xfconfd/xfconf-daemon.c
+++ b/xfconfd/xfconf-daemon.c
@@ -175,7 +175,7 @@ xfconf_set_property(XfconfExported *skeleton,
if(error) {
g_dbus_method_invocation_return_gerror(invocation, error);
g_error_free(error);
- return FALSE;
+ return G_DBUS_METHOD_INVOCATION_UNHANDLED;
}
}
@@ -192,7 +192,7 @@ xfconf_set_property(XfconfExported *skeleton,
g_value_unset (value);
g_free (value);
- return TRUE;
+ return G_DBUS_METHOD_INVOCATION_UNHANDLED;
}
@@ -225,13 +225,13 @@ xfconf_get_property(XfconfExported *skeleton,
g_error_free(error);
}
g_value_unset(&value);
- return TRUE;
+ return G_DBUS_METHOD_INVOCATION_UNHANDLED;
} else if(l->next)
g_clear_error(&error);
}
g_dbus_method_invocation_return_gerror(invocation, error);
g_error_free(error);
- return TRUE;
+ return G_DBUS_METHOD_INVOCATION_UNHANDLED;
}
static gboolean
@@ -248,7 +248,7 @@ xfconf_get_all_properties(XfconfExported *skeleton,
properties = g_hash_table_new_full(g_str_hash, g_str_equal,
(GDestroyNotify)g_free,
(GDestroyNotify)_xfconf_gvalue_free);
- /* get all properties from all backends. if they all fail, return FALSE */
+ /* get all properties from all backends */
for(l = xfconfd->backends; l; l = l->next) {
if(xfconf_backend_get_all(l->data, channel, property_base,
properties, &error))
@@ -268,7 +268,7 @@ xfconf_get_all_properties(XfconfExported *skeleton,
if(error)
g_error_free(error);
g_hash_table_destroy(properties);
- return TRUE;
+ return G_DBUS_METHOD_INVOCATION_UNHANDLED;
}
static gboolean
@@ -282,8 +282,7 @@ xfconf_property_exists(XfconfExported *skeleton,
gboolean succeed = FALSE;
GList *l;
GError *error = NULL;
- /* if at least one backend returns TRUE (regardles if |*exists| gets set
- * to TRUE or FALSE), we'll return TRUE from this function */
+
for(l = xfconfd->backends; !exists && l; l = l->next) {
if(xfconf_backend_exists(l->data, channel, property, &exists, &error))
succeed = TRUE;
@@ -297,7 +296,7 @@ xfconf_property_exists(XfconfExported *skeleton,
g_dbus_method_invocation_return_gerror(invocation, error);
g_error_free(error);
}
- return TRUE;
+ return G_DBUS_METHOD_INVOCATION_UNHANDLED;
}
static gboolean
@@ -330,7 +329,7 @@ xfconf_reset_property(XfconfExported *skeleton,
if(error)
g_error_free(error);
- return TRUE;
+ return G_DBUS_METHOD_INVOCATION_UNHANDLED;
}
static gboolean
@@ -370,7 +369,7 @@ xfconf_list_channels(XfconfExported *skeleton,
if(error)
g_error_free(error);
- return TRUE;
+ return G_DBUS_METHOD_INVOCATION_UNHANDLED;
}
static gboolean xfconf_is_property_locked(XfconfExported *skeleton,
@@ -399,7 +398,7 @@ static gboolean xfconf_is_property_locked(XfconfExported *skeleton,
if(error)
g_error_free(error);
- return TRUE;
+ return G_DBUS_METHOD_INVOCATION_UNHANDLED;
}
static void
@@ -491,8 +490,39 @@ xfconf_daemon_load_config(XfconfDaemon *xfconfd,
}
+#define XFCONF_DAEMON_CONNECT(signal_name, signal_handler) \
+ G_STMT_START{ \
+ g_signal_connect_swapped (xfconfd, signal_name, \
+ G_CALLBACK (xfconf_lifecycle_manager_increment_use_count), \
+ manager); \
+ g_signal_connect (xfconfd, signal_name, signal_handler, xfconfd); \
+ g_signal_connect_swapped (xfconfd, signal_name, \
+ G_CALLBACK (xfconf_lifecycle_manager_keep_alive), manager); \
+ g_signal_connect_swapped (xfconfd, signal_name, \
+ G_CALLBACK (xfconf_lifecycle_manager_decrement_use_count), \
+ manager); \
+ }G_STMT_END
+
+typedef struct
+{
+ gchar *name;
+ GCallback handler;
+} XfconfExportedSignal;
+
+static const XfconfExportedSignal xfconf_exported_signals[] =
+{
+ { "handle-get-all-properties", G_CALLBACK (xfconf_get_all_properties) },
+ { "handle-get-property", G_CALLBACK (xfconf_get_property) },
+ { "handle-is-property-locked", G_CALLBACK (xfconf_is_property_locked) },
+ { "handle-list-channels", G_CALLBACK (xfconf_list_channels) },
+ { "handle-property-exists", G_CALLBACK (xfconf_property_exists) },
+ { "handle-reset-property", G_CALLBACK (xfconf_reset_property) },
+ { "handle-set-property", G_CALLBACK (xfconf_set_property) },
+};
+
XfconfDaemon *
xfconf_daemon_new_unique(gchar * const *backend_ids,
+ XfconfLifecycleManager *manager,
GError **error)
{
XfconfDaemon *xfconfd;
@@ -508,26 +538,9 @@ xfconf_daemon_new_unique(gchar * const *backend_ids,
return NULL;
}
- g_signal_connect (xfconfd, "handle-get-all-properties",
- G_CALLBACK(xfconf_get_all_properties), xfconfd);
-
- g_signal_connect (xfconfd, "handle-get-property",
- G_CALLBACK(xfconf_get_property), xfconfd);
-
- g_signal_connect (xfconfd, "handle-is-property-locked",
- G_CALLBACK(xfconf_is_property_locked), xfconfd);
-
- g_signal_connect (xfconfd, "handle-list-channels",
- G_CALLBACK(xfconf_list_channels), xfconfd);
+ for (guint n = 0; n < G_N_ELEMENTS (xfconf_exported_signals); n++)
+ XFCONF_DAEMON_CONNECT (xfconf_exported_signals[n].name,
+ xfconf_exported_signals[n].handler);
- g_signal_connect (xfconfd, "handle-property-exists",
- G_CALLBACK(xfconf_property_exists), xfconfd);
-
- g_signal_connect (xfconfd, "handle-reset-property",
- G_CALLBACK(xfconf_reset_property), xfconfd);
-
- g_signal_connect (xfconfd, "handle-set-property",
- G_CALLBACK(xfconf_set_property), xfconfd);
-
return xfconfd;
}
diff --git a/xfconfd/xfconf-daemon.h b/xfconfd/xfconf-daemon.h
index aaddb2a..1735ee7 100644
--- a/xfconfd/xfconf-daemon.h
+++ b/xfconfd/xfconf-daemon.h
@@ -21,6 +21,7 @@
#define __XFCONF_DAEMON_H__
#include <glib-object.h>
+#include "xfconf-lifecycle-manager.h"
#include "xfconf/xfconf-errors.h"
#define XFCONF_TYPE_DAEMON (xfconf_daemon_get_type())
@@ -37,6 +38,7 @@ typedef struct _XfconfDaemon XfconfDaemon;
GType xfconf_daemon_get_type(void) G_GNUC_CONST;
XfconfDaemon *xfconf_daemon_new_unique(gchar * const *backend_ids,
+ XfconfLifecycleManager *manager,
GError **error);
G_END_DECLS
diff --git a/xfconfd/xfconf-lifecycle-manager.c b/xfconfd/xfconf-lifecycle-manager.c
new file mode 100644
index 0000000..794f3ad
--- /dev/null
+++ b/xfconfd/xfconf-lifecycle-manager.c
@@ -0,0 +1,224 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License ONLY.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <gio/gio.h>
+
+#include <xfconf-lifecycle-manager.h>
+
+
+
+#define SHUTDOWN_TIMEOUT_SECONDS 300
+
+
+
+enum
+{
+ SIGNAL_SHUTDOWN,
+ N_SIGNALS,
+};
+
+
+
+static void xfconf_lifecycle_manager_finalize (GObject *object);
+
+
+
+struct _XfconfLifecycleManagerPrivate
+{
+ GMutex lock;
+
+ guint timeout_id;
+ guint use_count;
+ gboolean shutdown_emitted;
+};
+
+
+
+static guint lifecycle_manager_signals[N_SIGNALS];
+
+
+
+G_DEFINE_TYPE_WITH_PRIVATE (XfconfLifecycleManager, xfconf_lifecycle_manager, G_TYPE_OBJECT)
+
+
+
+static void
+xfconf_lifecycle_manager_class_init (XfconfLifecycleManagerClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+ gobject_class->finalize = xfconf_lifecycle_manager_finalize;
+
+ lifecycle_manager_signals[SIGNAL_SHUTDOWN] =
+ g_signal_new ("shutdown", XFCONF_TYPE_LIFECYCLE_MANAGER, G_SIGNAL_RUN_LAST, 0,
+ NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
+}
+
+
+
+static void
+xfconf_lifecycle_manager_init (XfconfLifecycleManager *manager)
+{
+ manager->priv = xfconf_lifecycle_manager_get_instance_private (manager);
+ g_mutex_init (&manager->priv->lock);
+ manager->priv->timeout_id = 0;
+ manager->priv->use_count = 0;
+ manager->priv->shutdown_emitted = FALSE;
+}
+
+
+
+static void
+xfconf_lifecycle_manager_finalize (GObject *object)
+{
+ XfconfLifecycleManager *manager = XFCONF_LIFECYCLE_MANAGER (object);
+
+ g_mutex_clear (&manager->priv->lock);
+
+ G_OBJECT_CLASS (xfconf_lifecycle_manager_parent_class)->finalize (object);
+}
+
+
+
+static gboolean
+xfconf_lifecycle_manager_timeout (gpointer user_data)
+{
+ XfconfLifecycleManager *manager = user_data;
+
+ g_mutex_lock (&manager->priv->lock);
+
+ /* reschedule the timeout if the daemon is currently in use */
+ if (manager->priv->use_count > 0)
+ {
+ g_mutex_unlock (&manager->priv->lock);
+ return TRUE;
+ }
+
+ /* reset the timeout id */
+ manager->priv->timeout_id = 0;
+
+ /* emit the shutdown signal */
+ g_signal_emit (manager, lifecycle_manager_signals[SIGNAL_SHUTDOWN], 0);
+
+ /* set the shutdown emitted flag to force other threads not to reschedule
+ * the timeout */
+ manager->priv->shutdown_emitted = TRUE;
+
+ g_mutex_unlock (&manager->priv->lock);
+
+ return FALSE;
+}
+
+
+
+XfconfLifecycleManager *
+xfconf_lifecycle_manager_new (void)
+{
+ return g_object_new (XFCONF_TYPE_LIFECYCLE_MANAGER, NULL);
+}
+
+
+
+void
+xfconf_lifecycle_manager_start (XfconfLifecycleManager *manager)
+{
+ g_return_if_fail (XFCONF_IS_LIFECYCLE_MANAGER (manager));
+
+ g_mutex_lock (&manager->priv->lock);
+
+ /* ignore if there already is a timeout scheduled */
+ if (manager->priv->timeout_id != 0)
+ {
+ g_mutex_unlock (&manager->priv->lock);
+ return;
+ }
+
+ manager->priv->timeout_id =
+ g_timeout_add_seconds (SHUTDOWN_TIMEOUT_SECONDS,
+ xfconf_lifecycle_manager_timeout,
+ manager);
+
+ g_mutex_unlock (&manager->priv->lock);
+}
+
+
+
+gboolean
+xfconf_lifecycle_manager_keep_alive (XfconfLifecycleManager *manager)
+{
+ g_return_val_if_fail (XFCONF_IS_LIFECYCLE_MANAGER (manager), G_DBUS_METHOD_INVOCATION_UNHANDLED);
+
+ g_mutex_lock (&manager->priv->lock);
+
+ /* if the shutdown signal has been emitted, there's nothing we can do to prevent
+ * a shutdown anymore */
+ if (manager->priv->shutdown_emitted)
+ {
+ g_mutex_unlock (&manager->priv->lock);
+ return G_DBUS_METHOD_INVOCATION_UNHANDLED;
+ }
+
+ /* drop existing timeout, if any */
+ if (manager->priv->timeout_id != 0)
+ g_source_remove (manager->priv->timeout_id);
+
+ /* reschedule the shutdown timeout */
+ manager->priv->timeout_id =
+ g_timeout_add_seconds (SHUTDOWN_TIMEOUT_SECONDS,
+ xfconf_lifecycle_manager_timeout,
+ manager);
+
+ g_mutex_unlock (&manager->priv->lock);
+
+ return G_DBUS_METHOD_INVOCATION_UNHANDLED;
+}
+
+
+
+gboolean
+xfconf_lifecycle_manager_increment_use_count (XfconfLifecycleManager *manager)
+{
+ g_return_val_if_fail (XFCONF_IS_LIFECYCLE_MANAGER (manager), G_DBUS_METHOD_INVOCATION_UNHANDLED);
+
+ g_mutex_lock (&manager->priv->lock);
+
+ manager->priv->use_count++;
+
+ g_mutex_unlock (&manager->priv->lock);
+
+ return G_DBUS_METHOD_INVOCATION_UNHANDLED;
+}
+
+
+
+gboolean
+xfconf_lifecycle_manager_decrement_use_count (XfconfLifecycleManager *manager)
+{
+ g_return_val_if_fail (XFCONF_IS_LIFECYCLE_MANAGER (manager), G_DBUS_METHOD_INVOCATION_HANDLED);
+
+ g_mutex_lock (&manager->priv->lock);
+
+ /* decrement the use count, make sure not to drop below zero */
+ if (manager->priv->use_count > 0)
+ manager->priv->use_count--;
+
+ g_mutex_unlock (&manager->priv->lock);
+
+ return G_DBUS_METHOD_INVOCATION_HANDLED;
+}
diff --git a/xfconfd/xfconf-lifecycle-manager.h b/xfconfd/xfconf-lifecycle-manager.h
new file mode 100644
index 0000000..5c4b6ad
--- /dev/null
+++ b/xfconfd/xfconf-lifecycle-manager.h
@@ -0,0 +1,51 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License ONLY.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __XFCONF_LIFECYCLE_MANAGER_H__
+#define __XFCONF_LIFECYCLE_MANAGER_H__
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#if ! GLIB_CHECK_VERSION (2, 68, 0)
+#define G_DBUS_METHOD_INVOCATION_HANDLED TRUE
+#define G_DBUS_METHOD_INVOCATION_UNHANDLED FALSE
+#endif
+
+#define XFCONF_TYPE_LIFECYCLE_MANAGER xfconf_lifecycle_manager_get_type ()
+G_DECLARE_FINAL_TYPE (XfconfLifecycleManager, xfconf_lifecycle_manager, XFCONF, LIFECYCLE_MANAGER, GObject)
+
+typedef struct _XfconfLifecycleManagerPrivate XfconfLifecycleManagerPrivate;
+
+struct _XfconfLifecycleManager
+{
+ GObject parent;
+ XfconfLifecycleManagerPrivate *priv;
+};
+
+XfconfLifecycleManager* xfconf_lifecycle_manager_new (void) G_GNUC_MALLOC G_GNUC_WARN_UNUSED_RESULT;
+
+void xfconf_lifecycle_manager_start (XfconfLifecycleManager *manager);
+
+gboolean xfconf_lifecycle_manager_keep_alive (XfconfLifecycleManager *manager);
+
+gboolean xfconf_lifecycle_manager_increment_use_count (XfconfLifecycleManager *manager);
+
+gboolean xfconf_lifecycle_manager_decrement_use_count (XfconfLifecycleManager *manager);
+
+G_END_DECLS
+
+#endif /* !__XFCONF_LIFECYCLE_MANAGER_H__ */