diff options
author | Gaƫl Bonithon <gael@xfce.org> | 2022-01-11 11:04:52 +0100 |
---|---|---|
committer | Andre Miranda <andreldm@xfce.org> | 2022-03-05 16:56:48 +0000 |
commit | 0e3355a8dd9c732dfa09ff1528f5fef9de17af39 (patch) | |
tree | 017063244b31258cc673add0fd2f70db1c029f82 | |
parent | 4784fd5c274255d574c6fa600c1ce83dea76d159 (diff) | |
download | xfconf-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.am | 2 | ||||
-rw-r--r-- | xfconfd/main.c | 16 | ||||
-rw-r--r-- | xfconfd/xfconf-daemon.c | 77 | ||||
-rw-r--r-- | xfconfd/xfconf-daemon.h | 2 | ||||
-rw-r--r-- | xfconfd/xfconf-lifecycle-manager.c | 224 | ||||
-rw-r--r-- | xfconfd/xfconf-lifecycle-manager.h | 51 |
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__ */ |