[dconf/wip] wip



commit 1c56a520f5a13085d694434d0b9b6ef422dbb67d
Author: Ryan Lortie <desrt desrt ca>
Date:   Fri Nov 5 03:45:37 2010 -0400

    wip

 gsettings/Makefile.am            |    1 +
 gsettings/dconfcontext.c         |   35 +++
 gsettings/dconfcontext.h         |    8 +
 gsettings/dconfsettingsbackend.c |  423 +++++++++++++++++++++++---------------
 4 files changed, 303 insertions(+), 164 deletions(-)
---
diff --git a/gsettings/Makefile.am b/gsettings/Makefile.am
index 92c1154..b26ae71 100644
--- a/gsettings/Makefile.am
+++ b/gsettings/Makefile.am
@@ -9,6 +9,7 @@ libdconfsettings_so_SOURCES = \
 	../engine/dconf-engine.c	\
 	../common/dconf-shmdir.c	\
 	../gvdb/gvdb-reader.c		\
+	dconfcontext.c			\
 	dconfsettingsbackend.c
 
 uninstall-hook:
diff --git a/gsettings/dconfcontext.c b/gsettings/dconfcontext.c
new file mode 100644
index 0000000..339507e
--- /dev/null
+++ b/gsettings/dconfcontext.c
@@ -0,0 +1,35 @@
+#include "dconfcontext.h"
+
+static gpointer
+dconf_context_thread (gpointer data)
+{
+  GMainContext *context = data;
+  GMainLoop *loop;
+
+  g_main_context_push_thread_default (context);
+  loop = g_main_loop_new (context, FALSE);
+  g_main_loop_run (loop);
+
+  g_assert_not_reached ();
+}
+
+GMainContext *
+dconf_context_get (void)
+{
+  static GMainContext *context;
+  static gsize initialised;
+
+  if (g_once_init_enter (&initialised))
+    {
+      GThread *thread;
+
+      context = g_main_context_new ();
+      thread = g_thread_create (dconf_context_thread,
+                                context, FALSE, NULL);
+      g_assert (thread != NULL);
+
+      g_once_init_leave (&initialised, 1);
+    }
+
+  return context;
+}
diff --git a/gsettings/dconfcontext.h b/gsettings/dconfcontext.h
new file mode 100644
index 0000000..ddfb102
--- /dev/null
+++ b/gsettings/dconfcontext.h
@@ -0,0 +1,8 @@
+#ifndef _dconfcontext_h_
+#define _dconfcontext_h_
+
+#include <glib.h>
+
+GMainContext *          dconf_context_get                               (void);
+
+#endif
diff --git a/gsettings/dconfsettingsbackend.c b/gsettings/dconfsettingsbackend.c
index 8b2829b..4af50d7 100644
--- a/gsettings/dconfsettingsbackend.c
+++ b/gsettings/dconfsettingsbackend.c
@@ -26,23 +26,23 @@
 
 #include <string.h>
 
+#include "dconfcontext.h"
+
 typedef GSettingsBackendClass DConfSettingsBackendClass;
 typedef struct _Outstanding Outstanding;
 
 typedef struct
 {
   GSettingsBackend backend;
-  GStaticMutex lock;
-
-  DConfEngine *engine;
 
   GDBusConnection *session_bus;
-  gchar *session_anti_expose;
   GDBusConnection *system_bus;
-  gchar *system_anti_expose;
 
   Outstanding *outstanding;
-  GCond *sync_cond;
+  gchar *anti_expose_tag;
+
+  DConfEngine *engine;
+  GStaticMutex lock;
 } DConfSettingsBackend;
 
 static GType dconf_settings_backend_get_type (void);
@@ -50,120 +50,168 @@ G_DEFINE_TYPE (DConfSettingsBackend,
                dconf_settings_backend,
                G_TYPE_SETTINGS_BACKEND)
 
-
-struct _Outstanding
+static void
+dconf_settings_backend_send (DConfSettingsBackend *dcsb,
+                             DConfEngineMessage   *dcem,
+                             GAsyncReadyCallback   callback,
+                             gpointer              user_data)
 {
-  Outstanding *next;
-
-  DConfEngineMessage dcem;
-  volatile guint32 serial;
+  GDBusConnection *connection;
+  GError *error = NULL;
 
-  gchar *set_key;
-  GVariant *set_value;
+  switch (dcem->bus_type)
+    {
+    case 'e':
+      if (dcsb->session_bus == NULL && callback)
+        dcsb->session_bus = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error);
+      connection = dcsb->session_bus;
+      break;
 
-  GTree *tree;
-};
+    case 'y':
+      if (dcsb->system_bus == NULL && callback)
+        dcsb->system_bus = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error);
+      connection = dcsb->system_bus;
+      break;
 
-static volatile guint32 *
-dconf_settings_backend_new_outstanding (DConfSettingsBackend *dcsb,
-                                        DConfEngineMessage   *dcem,
-                                        const gchar          *set_key,
-                                        GVariant             *set_value,
-                                        GTree                *tree)
-{
-  Outstanding *outstanding;
+    default:
+      g_assert_not_reached ();
+    }
 
-  outstanding = g_slice_new (Outstanding);
-  outstanding->set_key = NULL;
-  outstanding->dcem = *dcem;
+  if (connection == NULL && callback != NULL)
+    {
+      GSimpleAsyncResult *result;
 
-  outstanding->set_key = g_strdup (set_key);
-  outstanding->serial = 0;
+      result = g_simple_async_result_new (NULL, callback, user_data,
+                                          dconf_settings_backend_send);
 
-  if (set_value)
-    outstanding->set_value = g_variant_ref_sink (set_value);
-  else
-    outstanding->set_value = NULL;
 
-  if (tree)
-    outstanding->tree = g_tree_ref (tree);
-  else
-    outstanding->tree = NULL;
+      callback (NULL, NULL, user_data);
+    }
+}
 
-  g_static_mutex_lock (&dcsb->lock);
-  outstanding->next = dcsb->outstanding;
-  dcsb->outstanding = outstanding;
-  g_static_mutex_unlock (&dcsb->lock);
+static GVariant *
+dconf_settings_backend_send_finish (GObject      *source,
+                                    GAsyncResult *result)
+{
+  if (source == NULL)
+    return NULL;
 
-  return &outstanding->serial;
+  return g_dbus_connection_call_finish (G_DBUS_CONNECTION (source),
+                                        result, NULL);
 }
 
-static gboolean
-dconf_settings_backend_remove_outstanding (DConfSettingsBackend  *dcsb,
-                                           guint                  bus_type,
-                                           GDBusMessage          *message,
-                                           gchar                **anti_expose)
+struct _Outstanding
 {
-  gboolean found = FALSE;
-  Outstanding **node;
-  guint32 serial;
+  Outstanding *next;
 
-  if G_LIKELY (dcsb->outstanding == NULL)
-    return FALSE;
+  DConfSettingsBackend *dcsb;
+  DConfEngineMessage    dcem;
 
-  serial = g_dbus_message_get_reply_serial (message);
+  gchar    *set_key;
+  GVariant *set_value;
+  GTree    *tree;
+};
 
-  if (serial == 0)
-    return FALSE;
+static void
+dconf_settings_backend_outstanding_returned (GObject      *source,
+                                             GAsyncResult *result,
+                                             gpointer      user_data)
+{
+  Outstanding *outstanding = user_data;
+  DConfSettingsBackend *dcsb;
+  GVariant *reply;
 
-  g_static_mutex_lock (&dcsb->lock);
+  dcsb = outstanding->dcsb;
 
-  /* this could be made more asymptotically efficient by using a queue
-   * or a double-linked list with a 'tail' pointer but the usual case
-   * here will be one outstanding item and very rarely more than a few.
-   *
-   * so we scan...
+  /* One way or another we no longer need this hooked into the list.
    */
-  for (node = &dcsb->outstanding; *node; node = &(*node)->next)
-    if ((*node)->serial == serial)
-      {
-        Outstanding *tmp;
+  g_static_mutex_lock (&dcsb->lock);
+  {
+    Outstanding **tmp;
 
-        tmp = *node;
-        *node = tmp->next;
+    for (tmp = &dcsb->outstanding; tmp; tmp = &(*tmp)->next)
+      if (*tmp == outstanding)
+        {
+          *tmp = outstanding->next;
+          break;
+        }
+  }
+  g_static_mutex_unlock (&dcsb->lock);
 
-        if (dcsb->outstanding == NULL && dcsb->sync_cond != NULL)
-          g_cond_signal (dcsb->sync_cond);
+  reply = dconf_settings_backend_send_finish (source, result);
 
-        g_static_mutex_unlock (&dcsb->lock);
+  if (reply)
+    {
+      /* Success.
+       *
+       * We want to ensure that we don't emit an extra change
+       * notification signal when we see the signal that the service is
+       * about to send, so store the tag so we know to ignore it when
+       * the signal comes.
+       *
+       * No thread safety issue here since this variable is only
+       * accessed from the worker thread.
+       */
+      g_free (dcsb->anti_expose_tag);
+      g_variant_get_child (reply, 0, "s", &dcsb->anti_expose_tag);
+      g_variant_unref (reply);
+    }
+  else
+    {
+      /* An error of some kind.
+       *
+       * We already removed the outstanding entry from the list, so the
+       * unmodified database is now visible to the client.  Change
+       * notify so that they see it.
+       */
+      if (outstanding->set_key)
+        g_settings_backend_changed (G_SETTINGS_BACKEND (dcsb),
+                                    outstanding->set_key, NULL);
 
-        g_free (tmp->set_key);
+      else
+        g_settings_backend_changed_tree (G_SETTINGS_BACKEND (dcsb),
+                                         outstanding->tree, NULL);
+    }
+}
+
+static gboolean
+dconf_settings_backend_send_outstanding (gpointer data)
+{
+  Outstanding *outstanding = data;
 
-        if (tmp->set_value)
-          g_variant_unref (tmp->set_value);
+  dconf_settings_backend_send (outstanding->dcsb,
+                               &outstanding->dcem,
+                               dconf_settings_backend_outstanding_returned,
+                               outstanding);
 
-        if (tmp->tree)
-          g_tree_unref (tmp->tree);
+  return FALSE;
+}
 
-        if (*anti_expose)
-          {
-            g_free (*anti_expose);
-            *anti_expose = NULL;
-          }
+static void
+dconf_settings_backend_queue (DConfSettingsBackend *dcsb,
+                              DConfEngineMessage   *dcem,
+                              const gchar          *set_key,
+                              GVariant             *set_value,
+                              GTree                *tree)
+{
+  Outstanding *outstanding;
 
-        dconf_engine_interpret_reply (&tmp->dcem,
-                                      g_dbus_message_get_sender (message),
-                                      g_dbus_message_get_body (message),
-                                      anti_expose, NULL);
-        g_slice_free (Outstanding, tmp);
+  outstanding = g_slice_new (Outstanding);
+  outstanding->dcsb = g_object_ref (dcsb);
+  outstanding->dcem = *dcem;
 
-        found = TRUE;
-        break;
-      }
+  outstanding->set_key = g_strdup (set_key);
+  outstanding->set_value = set_value ? g_variant_ref_sink (set_value) : NULL;
+  outstanding->tree = tree ? g_tree_ref (tree) : NULL;
 
+  g_static_mutex_lock (&dcsb->lock);
+  outstanding->next = dcsb->outstanding;
+  dcsb->outstanding = outstanding;
   g_static_mutex_unlock (&dcsb->lock);
 
-  return found;
+  g_main_context_invoke (dconf_context_get (),
+                         dconf_settings_backend_send_outstanding,
+                         outstanding);
 }
 
 static gboolean
@@ -244,14 +292,10 @@ dconf_settings_backend_scan_outstanding (DConfSettingsBackend  *backend,
   return found;
 }
 
-static void
-dconf_settings_backend_incoming_signal (DConfSettingsBackend  *dcsb,
-                                        guint                  bt,
-                                        GDBusMessage          *message,
-                                        gchar                **anti_expose)
+static gboolean
+dconf_settings_backend_signal (gpointer data)
 {
-  const gchar **rels;
-  const gchar *path;
+  GDBusMessage *message = data;
 
   if (dconf_engine_decode_notify (dcsb->engine, *anti_expose,
                                   &path, &rels, bt,
@@ -277,52 +321,29 @@ dconf_settings_backend_incoming_signal (DConfSettingsBackend  *dcsb,
     }
 }
 
+
+  g_object_unref (message);
+
+  return FALSE;
+}
+
 static GDBusMessage *
 dconf_settings_backend_filter (GDBusConnection *connection,
                                GDBusMessage    *message,
                                gboolean         is_incoming,
                                gpointer         user_data)
 {
-  DConfSettingsBackend *dcsb = user_data;
-  guint bus_type;
-  gchar **ae;
-
-  if (!is_incoming)
-    return message;
-
-  if (connection == dcsb->session_bus)
-    {
-      ae = &dcsb->session_anti_expose;
-      bus_type = 'e';
-    }
-  else if (connection == dcsb->system_bus)
+  if (is_incoming &&
+      (g_dbus_message_get_message_type (message) == G_DBUS_MESSAGE_TYPE_SIGNAL) &&
+      (strcmp (g_dbus_message_get_interface (message), "ca.desrt.dconf.Writer") == 0))
     {
-      ae = &dcsb->system_anti_expose;
-      bus_type = 'y';
+      g_main_context_invoke (dconf_context_get (),
+                             dconf_settings_backend_signal,
+                             g_object_ref (message));
     }
 
-  else
-    g_assert_not_reached ();
-
-  switch (g_dbus_message_get_message_type (message))
-    {
-    case G_DBUS_MESSAGE_TYPE_METHOD_RETURN:
-      if (dconf_settings_backend_remove_outstanding (dcsb, bus_type,
-                                                     message, ae))
-        {
-          /* consume message */
-          g_object_unref (message);
-          return NULL;
-        }
-      else
-        return message;
 
-    case G_DBUS_MESSAGE_TYPE_SIGNAL:
-      dconf_settings_backend_incoming_signal (dcsb, bus_type, message, ae);
-
-    default:
-      return message;
-    }
+  return message;
 }
 
 static GVariant *
@@ -433,20 +454,12 @@ dconf_settings_backend_write (GSettingsBackend *backend,
                               gpointer          origin_tag)
 {
   DConfSettingsBackend *dcsb = (DConfSettingsBackend *) backend;
-  volatile guint32 *serial;
   DConfEngineMessage dcem;
-  GDBusConnection *bus;
 
-  if (!dconf_engine_write (dcsb->engine, key, value, &dcem, NULL))
+  if (dconf_engine_write (dcsb->engine, key, value, &dcem, NULL))
     return FALSE;
 
-  if (!dconf_settings_backend_get_bus (dcsb, &bus, &dcem))
-    return FALSE;
-
-  serial = dconf_settings_backend_new_outstanding (dcsb, &dcem, key,
-                                                   value, NULL);
-  dconf_settings_backend_send (bus, &dcem, serial);
-
+  dconf_settings_backend_queue (dcsb, &dcem, key, value, NULL);
   g_settings_backend_changed (backend, key, origin_tag);
 
   return TRUE;
@@ -458,32 +471,25 @@ dconf_settings_backend_write_tree (GSettingsBackend *backend,
                                    gpointer          origin_tag)
 {
   DConfSettingsBackend *dcsb = (DConfSettingsBackend *) backend;
-  gboolean success = FALSE;
-  volatile guint32 *serial;
   DConfEngineMessage dcem;
-  GDBusConnection *bus;
   const gchar **keys;
   GVariant **values;
+  gboolean success;
   gchar *prefix;
 
   g_settings_backend_flatten_tree (tree, &prefix, &keys, &values);
 
-  if (dconf_engine_write_many (dcsb->engine,
-                               prefix, keys, values, &dcem, NULL))
+  if ((success = dconf_engine_write_many (dcsb->engine, prefix,
+                                          keys, values, &dcem, NULL)))
     {
-      if (dconf_settings_backend_get_bus (dcsb, &bus, &dcem))
-        {
-          serial = dconf_settings_backend_new_outstanding (dcsb, &dcem,
-                                                           NULL, NULL, tree);
-
-          dconf_settings_backend_send (bus, &dcem, serial);
-
-          g_settings_backend_keys_changed (backend, prefix, keys, origin_tag);
-
-          success = TRUE;
-        }
+      dconf_settings_backend_queue (dcsb, &dcem, NULL, NULL, tree);
+      g_settings_backend_keys_changed (backend, prefix, keys, origin_tag);
     }
 
+  g_free (prefix);
+  g_free (values);
+  g_free (keys);
+
   return success;
 }
 
@@ -504,18 +510,104 @@ dconf_settings_backend_get_writable (GSettingsBackend *backend,
   return dconf_engine_is_writable (dcsb->engine, name);
 }
 
+typedef struct
+{
+  DConfSettingsBackend *dcsb;
+  guint64 state;
+  gchar name[1];
+} OutstandingWatch;
+
+OutstandingWatch *
+outstanding_watch_new (DConfSettingsBackend *dcsb,
+                       const gchar          *name)
+{
+  OutstandingWatch *watch;
+  gsize length;
+
+  length = strlen (name);
+  watch = g_malloc (G_STRUCT_OFFSET (OutstandingWatch, name) + length + 1);
+  watch->dcsb = g_object_ref (dcsb);
+  watch->state = dconf_engine_get_state (dcsb->state);
+  strcpy (watch->name, name);
+
+  return watch;
+}
+
 static void
-dconf_settings_backend_subscribe (GSettingsBackend *backend,
-                                  const gchar      *name)
+outstanding_watch_free (OutstandingWatch *watch)
 {
-  DConfSettingsBackend *dcsb = (DConfSettingsBackend *) backend;
+  g_object_unref (watch->dcsb);
+  g_free (watch);
+}
+
+static void
+add_match_done (GObject      *source,
+                GAsyncResult *result,
+                gpointer      user_data)
+{
+  OutstandingWatch *watch = user_data;
+  GError *error = NULL;
+  GVariant *reply;
+
+  reply = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source),
+                                         result, &error);
+
+  if (reply == NULL)
+    {
+      g_critical ("DBus AddMatch for dconf path '%s': %s",
+                  watch->name, error->message);
+      outstanding_watch_free (watch);
+      g_error_free (error);
+
+      return;
+    }
+
+  else
+    g_variant_unref (reply); /* it is just an empty tuple */
+
+  /* In the normal case we can just free everything and be done.
+   *
+   * There is a fleeting chance, however, that the database has changed
+   * in the meantime.  In that case we can only assume that the subject
+   * of this watch changed in that time period and emit a signal to that
+   * effect.
+   */
+  if (dconf_engine_get_state (watch->dcsb->engine) != watch->state)
+    g_settings_backend_path_changed (G_SETTINGS_BACKEND (watch->dcsb),
+                                     watch->name, NULL);
+
+  outstanding_watch_free (watch);
+}
+
+static gboolean
+dconf_settings_backend_subscribe_context_func (gpointer data)
+{
+  OutstandingWatch *watch = data;
   DConfEngineMessage dcem;
   GDBusConnection *bus;
 
   dconf_engine_watch (dcsb->engine, name, &dcem);
 
   if (dconf_settings_backend_get_bus (dcsb, &bus, &dcem))
-    dconf_settings_backend_send (bus, &dcem, NULL);
+    g_dbus_connection_call (bus, dcem->destination, dcem->object_path,
+                            dcem->interface, dcem->method, dcem->body,
+                            G_VARIANT_TYPE_UNIT, G_DBUS_CALL_FLAGS_NONE, -1,
+                            NULL, add_match_done, watch);
+
+  else
+    /* Can't watch without a bus, so just do nothing... */
+    outstanding_watch_free (watch);
+}
+
+static void
+dconf_settings_backend_subscribe (GSettingsBackend *backend,
+                                  const gchar      *name)
+{
+  DConfSettingsBackend *dcsb = (DConfSettingsBackend *) backend;
+
+  g_main_context_invoke (dconf_context_get (),
+                         dconf_settings_backend_subscribe_context_func,
+                         outstanding_watch_new (dcsb, name));
 }
 
 static void
@@ -528,8 +620,11 @@ dconf_settings_backend_unsubscribe (GSettingsBackend *backend,
 
   dconf_engine_unwatch (dcsb->engine, name, &dcem);
 
-  if (dconf_settings_backend_get_bus (dcsb, &bus, &dcem))
-    dconf_settings_backend_send (bus, &dcem, NULL);
+  if (dconf_settings_backend_try_bus (dcsb, &bus, &dcem))
+    g_dbus_connection_call (bus, dcem->destination, dcem->object_path,
+                            dcem->interface, dcem->method, dcem->body,
+                            NULL, G_DBUS_CALL_FLAGS_NONE, -1,
+                            NULL, NULL, NULL);
 }
 
 static void



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