From 776070012e3d5d2bff5a1b2a9e175ced7122f125 Mon Sep 17 00:00:00 2001 From: Jannis Pohlmann <jannis@xfce.org> Date: Wed, 28 Sep 2011 21:11:57 +0000 Subject: Fix ownership race conditions when started twice (bug #8001). It can happen that D-Bus activates tumblerd multiple times if the activated instance doesn't bring up the service quickly enough. We need to detect this in order to exit duplicate instances gracefully (exit code 0). Exiting with an error code breaks clients. For more information, see the following bugs: https://bugzilla.xfce.org/show_bug.cgi?id=8001 https://bugs.freedesktop.org/show_bug.cgi?id=41233 --- diff --git a/tumblerd/main.c b/tumblerd/main.c index f2de4f0..f79049b 100644 --- a/tumblerd/main.c +++ b/tumblerd/main.c @@ -65,6 +65,7 @@ main (int argc, TumblerService *service; TumblerCacheService *cache_service; GMainLoop *main_loop; + gboolean already_running = FALSE; GError *error = NULL; GList *providers; GList *thumbnailers; @@ -99,22 +100,6 @@ main (int argc, /* create the lifecycle manager */ lifecycle_manager = tumbler_lifecycle_manager_new (); - /* create the thumbnail cache service */ - cache_service = tumbler_cache_service_new (connection, lifecycle_manager); - - /* try to start the service and exit if that fails */ - if (!tumbler_cache_service_start (cache_service, &error)) - { - g_warning (_("Failed to start the thumbnail cache service: %s"), error->message); - g_error_free (error); - - g_object_unref (cache_service); - - dbus_g_connection_unref (connection); - - return EXIT_FAILURE; - } - /* create the thumbnailer registry */ registry = tumbler_registry_new (); @@ -152,6 +137,15 @@ main (int argc, /* update the URI schemes / MIME types supported information */ tumbler_registry_update_supported (registry); + /* create the thumbnail cache service */ + cache_service = tumbler_cache_service_new (connection, lifecycle_manager); + + /* create the thumbnailer manager service */ + manager = tumbler_manager_new (connection, lifecycle_manager, registry); + + /* create the generic thumbnailer service */ + service = tumbler_service_new (connection, lifecycle_manager, registry); + /* try to load specialized thumbnailers and exit if that fails */ if (!tumbler_registry_load (registry, &error)) { @@ -159,49 +153,80 @@ main (int argc, error->message); g_error_free (error); - g_object_unref (registry); + g_object_unref (service); + g_object_unref (manager); g_object_unref (cache_service); + g_object_unref (registry); dbus_g_connection_unref (connection); return EXIT_FAILURE; } - /* create the thumbnailer manager service */ - manager = tumbler_manager_new (connection, lifecycle_manager, registry); + /* try to start the service and exit if that fails */ + if (!tumbler_cache_service_start (cache_service, &error)) + { + if (error->domain == DBUS_GERROR && error->code == DBUS_GERROR_ADDRESS_IN_USE) + already_running = TRUE; + + g_warning (_("Failed to start the thumbnail cache service: %s"), error->message); + g_error_free (error); + + g_object_unref (service); + g_object_unref (manager); + g_object_unref (cache_service); + g_object_unref (registry); + + dbus_g_connection_unref (connection); + + if (already_running) + return EXIT_SUCCESS; + else + return EXIT_FAILURE; + } /* try to start the service and exit if that fails */ if (!tumbler_manager_start (manager, &error)) { + if (error->domain == DBUS_GERROR && error->code == DBUS_GERROR_ADDRESS_IN_USE) + already_running = TRUE; + g_warning (_("Failed to start the thumbnailer manager: %s"), error->message); g_error_free (error); + g_object_unref (service); g_object_unref (manager); - g_object_unref (registry); g_object_unref (cache_service); + g_object_unref (registry); dbus_g_connection_unref (connection); - return EXIT_FAILURE; + if (already_running) + return EXIT_SUCCESS; + else + return EXIT_FAILURE; } - /* create the generic thumbnailer service */ - service = tumbler_service_new (connection, lifecycle_manager, registry); - /* try to start the service and exit if that fails */ if (!tumbler_service_start (service, &error)) { + if (error->domain == DBUS_GERROR && error->code == DBUS_GERROR_ADDRESS_IN_USE) + already_running = TRUE; + g_warning (_("Failed to start the thumbnailer service: %s"), error->message); g_error_free (error); g_object_unref (service); g_object_unref (manager); - g_object_unref (registry); g_object_unref (cache_service); + g_object_unref (registry); dbus_g_connection_unref (connection); - return EXIT_FAILURE; + if (already_running) + return EXIT_SUCCESS; + else + return EXIT_FAILURE; } /* create a new main loop */ @@ -220,8 +245,8 @@ main (int argc, /* shut our services down and release all objects */ g_object_unref (service); g_object_unref (manager); - g_object_unref (registry); g_object_unref (cache_service); + g_object_unref (registry); g_object_unref (lifecycle_manager); /* disconnect from the D-Bus session bus */ diff --git a/tumblerd/tumbler-cache-service.c b/tumblerd/tumbler-cache-service.c index f13177c..f6b2dc5 100644 --- a/tumblerd/tumbler-cache-service.c +++ b/tumblerd/tumbler-cache-service.c @@ -174,6 +174,15 @@ tumbler_cache_service_constructed (GObject *object) service, 1, FALSE, NULL); service->cleanup_pool = g_thread_pool_new (tumbler_cache_service_cleanup_thread, service, 1, FALSE, NULL); + + /* everything's fine, install the cache type D-Bus info */ + dbus_g_object_type_install_info (G_OBJECT_TYPE (service), + &dbus_glib_tumbler_cache_service_object_info); + + /* register the cache instance as a handler of the cache interface */ + dbus_g_connection_register_g_object (service->connection, + "/org/freedesktop/thumbnails/Cache1", + G_OBJECT (service)); } @@ -400,7 +409,19 @@ tumbler_cache_service_start (TumblerCacheService *service, DBUS_NAME_FLAG_DO_NOT_QUEUE, &dbus_error); /* check if that failed */ - if (result != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) + if (result == DBUS_REQUEST_NAME_REPLY_EXISTS) + { + if (error != NULL) + { + g_set_error (error, DBUS_GERROR, DBUS_GERROR_ADDRESS_IN_USE, + _("Another thumbnail cache service is already running")); + } + + g_mutex_unlock (service->mutex); + + return FALSE; + } + else if (result != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) { /* propagate the D-Bus error */ if (dbus_error_is_set (&dbus_error)) @@ -421,15 +442,6 @@ tumbler_cache_service_start (TumblerCacheService *service, return FALSE; } - /* everything's fine, install the cache type D-Bus info */ - dbus_g_object_type_install_info (G_OBJECT_TYPE (service), - &dbus_glib_tumbler_cache_service_object_info); - - /* register the cache instance as a handler of the cache interface */ - dbus_g_connection_register_g_object (service->connection, - "/org/freedesktop/thumbnails/Cache1", - G_OBJECT (service)); - g_mutex_unlock (service->mutex); return TRUE; diff --git a/tumblerd/tumbler-manager.c b/tumblerd/tumbler-manager.c index 73e6778..feb2943 100644 --- a/tumblerd/tumbler-manager.c +++ b/tumblerd/tumbler-manager.c @@ -63,6 +63,7 @@ typedef struct _ThumbnailerInfo ThumbnailerInfo; +static void tumbler_manager_constructed (GObject *object); static void tumbler_manager_finalize (GObject *object); static void tumbler_manager_get_property (GObject *object, guint prop_id, @@ -158,6 +159,7 @@ tumbler_manager_class_init (TumblerManagerClass *klass) GObjectClass *gobject_class; gobject_class = G_OBJECT_CLASS (klass); + gobject_class->constructed = tumbler_manager_constructed; gobject_class->finalize = tumbler_manager_finalize; gobject_class->get_property = tumbler_manager_get_property; gobject_class->set_property = tumbler_manager_set_property; @@ -198,6 +200,25 @@ tumbler_manager_init (TumblerManager *manager) + + +static void +tumbler_manager_constructed (GObject *object) +{ + TumblerManager *manager = TUMBLER_MANAGER (object); + + /* everything's fine, install the manager type D-Bus info */ + dbus_g_object_type_install_info (G_OBJECT_TYPE (manager), + &dbus_glib_tumbler_manager_object_info); + + /* register the manager instance as a handler of the manager interface */ + dbus_g_connection_register_g_object (manager->connection, + "/org/freedesktop/thumbnails/Manager1", + G_OBJECT (manager)); +} + + + static void tumbler_manager_finalize (GObject *object) { @@ -1838,7 +1859,19 @@ tumbler_manager_start (TumblerManager *manager, DBUS_NAME_FLAG_DO_NOT_QUEUE, &dbus_error); /* check if that failed */ - if (result != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) + if (result == DBUS_REQUEST_NAME_REPLY_EXISTS) + { + if (error != NULL) + { + g_set_error (error, DBUS_GERROR, DBUS_GERROR_ADDRESS_IN_USE, + _("Another thumbnail cache service is already running")); + } + + g_mutex_unlock (manager->mutex); + + return FALSE; + } + else if (result != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) { /* propagate the D-Bus error */ if (dbus_error_is_set (&dbus_error)) @@ -1860,15 +1893,6 @@ tumbler_manager_start (TumblerManager *manager, return FALSE; } - /* everything's fine, install the manager type D-Bus info */ - dbus_g_object_type_install_info (G_OBJECT_TYPE (manager), - &dbus_glib_tumbler_manager_object_info); - - /* register the manager instance as a handler of the manager interface */ - dbus_g_connection_register_g_object (manager->connection, - "/org/freedesktop/thumbnails/Manager1", - G_OBJECT (manager)); - g_mutex_unlock (manager->mutex); /* load thumbnailers installed into the system permanently */ diff --git a/tumblerd/tumbler-service.c b/tumblerd/tumbler-service.c index 92ab7ac..8214a45 100644 --- a/tumblerd/tumbler-service.c +++ b/tumblerd/tumbler-service.c @@ -295,6 +295,15 @@ tumbler_service_constructed (GObject *object) scheduler = tumbler_group_scheduler_new ("background"); tumbler_service_add_scheduler (service, scheduler); g_object_unref (scheduler); + + /* everything is fine, install the generic thumbnailer D-Bus info */ + dbus_g_object_type_install_info (G_OBJECT_TYPE (service), + &dbus_glib_tumbler_service_object_info); + + /* register the service instance as a handler of this interface */ + dbus_g_connection_register_g_object (service->connection, + THUMBNAILER_PATH, + G_OBJECT (service)); } @@ -744,7 +753,19 @@ tumbler_service_start (TumblerService *service, DBUS_NAME_FLAG_DO_NOT_QUEUE, &dbus_error); /* check if that failed */ - if (result != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) + if (result == DBUS_REQUEST_NAME_REPLY_EXISTS) + { + if (error != NULL) + { + g_set_error (error, DBUS_GERROR, DBUS_GERROR_ADDRESS_IN_USE, + _("Another thumbnail cache service is already running")); + } + + g_mutex_unlock (service->mutex); + + return FALSE; + } + else if (result != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) { /* propagate the D-Bus error */ if (dbus_error_is_set (&dbus_error)) @@ -765,15 +786,6 @@ tumbler_service_start (TumblerService *service, return FALSE; } - /* everything is fine, install the generic thumbnailer D-Bus info */ - dbus_g_object_type_install_info (G_OBJECT_TYPE (service), - &dbus_glib_tumbler_service_object_info); - - /* register the service instance as a handler of this interface */ - dbus_g_connection_register_g_object (service->connection, - THUMBNAILER_PATH, - G_OBJECT (service)); - g_mutex_unlock (service->mutex); return TRUE; -- cgit