/* * 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 #endif #include #include #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; }