[dconf] GDBus thread backend: fix obscure race condition



commit 1a580f4465d80bad209d7dccdad92063aa2861fa
Author: Ryan Lortie <desrt desrt ca>
Date:   Fri Jul 20 11:07:15 2012 -0400

    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.

 gdbus/dconf-gdbus-thread.c |    6 +++++-
 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;
 }



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