summaryrefslogtreecommitdiff
path: root/gdbus
diff options
context:
space:
mode:
authorRyan Lortie <desrt@desrt.ca>2012-07-20 11:07:15 -0400
committerRyan Lortie <desrt@desrt.ca>2012-07-20 11:07:15 -0400
commit1a580f4465d80bad209d7dccdad92063aa2861fa (patch)
tree20da193415f3cf0e5e5bb511398365d2b21a4e9f /gdbus
parentbc02d65a6c8defcee64022ba2f9a2607495281f7 (diff)
downloaddconf-1a580f4465d80bad209d7dccdad92063aa2861fa.tar.gz
GDBus thread backend: fix obscure race condition
It was possible for outgoing messages to be delivered in the wrong order due to an annoying race condition when dealing with delivery of "fast" change messages. This was hitting the in-order assertion on return of those messages. The race goes like this: - a write is requested from the main thread (1 in-flight, 0 pending) - the reply for this first change message comes back (but is not yet handled). - another write is requested from the main thread and immediately placed in-flight (with an idle on the worker thread for actually sending it). 2 in-flight, 0 pending. - a third write is requested from the main thread but goes to the pending queue (since the in-flight queue is full). 2 in-flight, 1 pending. - the reply for the first change message is now handled in the worker thread, removing the first change from the in-flight queue. The queue management sees the third write in the pending queue and promotes it to the in-flight queue (properly following the second write) but sends the message immediately since it's already in the worker thread (leapfrogging the second write which is still waiting in an idle). - the idle for the second write runs We solve this problem by dispatching all writes via idles, even if we're already in the worker thread.
Diffstat (limited to 'gdbus')
-rw-r--r--gdbus/dconf-gdbus-thread.c6
1 files changed, 5 insertions, 1 deletions
diff --git a/gdbus/dconf-gdbus-thread.c b/gdbus/dconf-gdbus-thread.c
index e3d69d8..15cf70a 100644
--- a/gdbus/dconf-gdbus-thread.c
+++ b/gdbus/dconf-gdbus-thread.c
@@ -266,6 +266,7 @@ dconf_engine_dbus_call_async_func (GBusType bus_type,
GError **error)
{
DConfGDBusCall *call;
+ GSource *source;
call = g_slice_new (DConfGDBusCall);
call->bus_type = bus_type;
@@ -276,7 +277,10 @@ dconf_engine_dbus_call_async_func (GBusType bus_type,
call->parameters = g_variant_ref_sink (parameters);
call->handle = handle;
- g_main_context_invoke (dconf_gdbus_get_worker_context (), dconf_gdbus_method_call, call);
+ source = g_idle_source_new ();
+ g_source_set_callback (source, dconf_gdbus_method_call, call, NULL);
+ g_source_attach (source, dconf_gdbus_get_worker_context ());
+ g_source_unref (source);
return TRUE;
}