[rygel] core: Make rygel single-instance.



commit 9d9bfa6679f3896f009ced706e62426203357c18
Author: Jens Georg <mail jensge org>
Date:   Wed Jul 13 17:26:16 2011 +0200

    core: Make rygel single-instance.
    
    The new instance steals the DBus name from the old instance which then
    shuts itself down. This is a temporary solution to avoid a race
    condition when multiple instances of Rygel being started by accident
    are trying to read and write the SCDP files simultaneously, resulting
    in empty SCDP files on-disk.

 src/rygel/rygel-dbus-service.vala |   73 +++++++++++++++++++++++++------------
 src/rygel/rygel-main.vala         |   18 +++++----
 2 files changed, 60 insertions(+), 31 deletions(-)
---
diff --git a/src/rygel/rygel-dbus-service.vala b/src/rygel/rygel-dbus-service.vala
index 330cd88..ebc7bbb 100644
--- a/src/rygel/rygel-dbus-service.vala
+++ b/src/rygel/rygel-dbus-service.vala
@@ -21,44 +21,71 @@
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  */
 
-using FreeDesktop;
-
 [DBus (name = "org.gnome.Rygel1")]
 public class Rygel.DBusService : Object, DBusInterface {
     private Main main;
+    private uint name_id;
     private uint connection_id;
 
-    public DBusService (Main main) throws IOError, DBusError {
+    public DBusService (Main main) {
         this.main = main;
+    }
 
-        DBusObject bus = Bus.get_proxy_sync
-                                        (BusType.SESSION,
-                                         DBUS_SERVICE,
-                                         DBUS_OBJECT,
-                                         DBusProxyFlags.DO_NOT_LOAD_PROPERTIES);
+    public void shutdown () throws IOError {
+        this.main.exit (0);
+    }
 
-        // try to register service in session bus
-        if (bus.request_name (DBusInterface.SERVICE_NAME, 0) !=
-            DBusRequestNameReply.PRIMARY_OWNER) {
-            warning ("Failed to start D-Bus service  name '%s' already taken",
-                     DBusInterface.SERVICE_NAME);
-        } else {
-            var conn = Bus.get_sync (BusType.SESSION);
+    internal void publish () {
+        this.name_id = Bus.own_name (BusType.SESSION,
+                                     DBusInterface.SERVICE_NAME,
+                                     BusNameOwnerFlags.ALLOW_REPLACEMENT |
+                                     BusNameOwnerFlags.REPLACE,
+                                     this.on_bus_aquired,
+                                     this.on_name_available,
+                                     this.on_name_lost);
+    }
 
-            this.connection_id = conn.register_object
-                                        (DBusInterface.OBJECT_PATH, this);
+    internal void unpublish () {
+        if (connection_id != 0) {
+            try {
+                var connection = Bus.get_sync (BusType.SESSION);
+                connection.unregister_object (this.connection_id);
+            } catch (IOError error) {};
+        }
+
+        if (name_id != 0) {
+            Bus.unown_name (this.name_id);
         }
     }
 
-    internal void unpublish () {
+
+    private void on_bus_aquired (DBusConnection connection) {
         try {
-            var conn = Bus.get_sync (BusType.SESSION);
-            conn.unregister_object (this.connection_id);
-        } catch (IOError error) { }
+            this.connection_id = connection.register_object
+                                        (DBusInterface.OBJECT_PATH,
+                                         this);
+        } catch (Error error) { }
     }
 
-    public void shutdown () throws IOError {
-        this.main.exit (0);
+    private void on_name_available (DBusConnection connection) {
+        this.main.dbus_available ();
+    }
+
+    private void on_name_lost (DBusConnection? connection) {
+        if (connection == null) {
+            // This means there is no DBus available at all
+            this.main.dbus_available ();
+
+            return;
+        }
+
+        if (this.connection_id != 0) {
+            message (_("Another instance of Rygel is taking over. Exiting"));
+        } else {
+            message (_("Another instance of Rygel is already running."));
+        }
+
+        this.main.exit (12);
     }
 }
 
diff --git a/src/rygel/rygel-main.vala b/src/rygel/rygel-main.vala
index 5232dd1..fa521d4 100644
--- a/src/rygel/rygel-main.vala
+++ b/src/rygel/rygel-main.vala
@@ -38,6 +38,7 @@ public class Rygel.Main : Object {
     private MainLoop main_loop;
 
     private int exit_code;
+
     public bool need_restart;
 
     private Main () throws GLib.Error {
@@ -48,7 +49,6 @@ public class Rygel.Main : Object {
         this.plugin_loader = new PluginLoader ();
         this.root_devices = new ArrayList <RootDevice> ();
         this.factories = new ArrayList <RootDeviceFactory> ();
-        this.context_manager = this.create_context_manager ();
         this.main_loop = new GLib.MainLoop (null, false);
 
         this.exit_code = 0;
@@ -74,6 +74,13 @@ public class Rygel.Main : Object {
     }
 
     private int run () {
+        this.main_loop.run ();
+
+        return this.exit_code;
+    }
+
+    internal void dbus_available () {
+        this.context_manager = this.create_context_manager ();
         this.plugin_loader.load_plugins ();
 
         Timeout.add_seconds (PLUGIN_TIMEOUT, () => {
@@ -88,12 +95,9 @@ public class Rygel.Main : Object {
 
             return false;
         });
-
-        this.main_loop.run ();
-
-        return this.exit_code;
     }
 
+
     private void on_plugin_loaded (PluginLoader plugin_loader,
                                    Plugin       plugin) {
         var iterator = this.factories.iterator ();
@@ -235,8 +239,7 @@ public class Rygel.Main : Object {
 
             main = new Main ();
             service = new DBusService (main);
-        } catch (IOError err) {
-            warning (_("Failed to start D-Bus service: %s"), err.message);
+            service.publish ();
         } catch (CmdlineConfigError.VERSION_ONLY err) {
             return 0;
         } catch (GLib.Error err) {
@@ -244,7 +247,6 @@ public class Rygel.Main : Object {
         }
 
         int exit_code = main.run ();
-
         if (service != null) {
             service.unpublish ();
         }



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]