[dconf/wip] wip
- From: Ryan Lortie <ryanl src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [dconf/wip] wip
- Date: Fri, 5 Nov 2010 07:45:54 +0000 (UTC)
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]