Hello,


As far as i knew, the GDBusProxy object initialization flow have two mainly 
actions:



(1). Listen for properties change signal to update property cache in GDBusProxy.

(2). Called the GetAll metod call to get the default value of an object 
properties.



I've encountered a race condition with GDBusProxy object initialization. if the 
signal of properties_change occurred while the GDBusProxy was already in a 
GetAll reply handler flow, the properties_change signal will be immediately 
discarded. This causes the GDBusProxy object has not yet initialized when the 
callback function on_properties_changed() called.



The ascii figure below shows the possible execution of this isseus: (Y axis is 
a time axis)


    [GDBus Worker thread]                   {Default GLib main context}         
                     [Main thread]

             |                                           |                      
                           |

+-------------------------+  push the idle GSource       |                      
                           |

|                         |  <async_init_get_all_cb()>   |  pop the idle 
GSource                           |

| receiving GetAll method |  to the mainloop             |  
<async_init_get_all_cb()>                      |

| reply message           +--------------------------->> |  from the mainloop   
        +------------------------------------+

|                         |                              
+--------------------------->> |                                    |

+-------------------------+                              |                      
        | running <async_init_get_all_cb()>  |

             |                                           |                      
        | callback function, and adding the  |

+-------------------------+  push the idle GSource       |                      
        | idle GSource user-defined          |

|                         |  <on_properties_changed()>   |  push the idle 
GSource       | GDBusProxy ready callback function |

| ((unexpected signal!))  |  to the mainloop             |  <on_proxy_ready()>  
        | to the mainloop (such as           |

| receiving the signal of +--------------------------->> |  to the mainloop     
        | <on_proxy_ready()> ...)            |

| properties change       |                              | 
<<---------------------------+                                    |

|                         |                              |                      
        +------------------------------------+

+-------------------------+                              |                      
                           |

             |                                           |                      
                           |

             |                                           |                      
        +------------------------------------+

             |                                           |  pop the idle 
GSource        |                                    |

             |                                           |  
<on_properties_changed()>   | running <on_properties_changed()>  |

             |                                           |  from the mainloop   
        | callback function, but the         |

             |                                           
+--------------------------->> | GDBusProxy object has not yet been |

             |                                           |                      
        | initialized, so the signal will be |

             |                                           |                      
        | DISCARDED!                         |

             |                                           |                      
        +------------------------------------+

             |                                           |                      
                           |

             |                                           |                      
        +------------------------------------+

             |                                           |  pop the idle 
GSource        |                                    |

             |                                           |  <on_proxy_ready()>  
        | running <on_proxy_ready()>         |

             |                                           |  from the mainloop   
        | callback function, and call the    |

             |                                           
+--------------------------->> | function =>                        |

             |                                           |                      
        | <async_initable_init_finish()>     |

             |                                           |                      
        | to set GDBusProxy object           |

             |                                           |                      
        | initialization compiled, but some  |

             |                                           |                      
        | cache results of properties was    |

             |                                           |                      
        | incorrect!                         |

             |                                           |                      
        |                                    |

             |                                           |                      
        +------------------------------------+

             |                                           |                      
                           |

             |                                           |                      
                           |

            ...                                         ...                     
                          ...


I think an easy way to fix this problem is to raising idle GSources priority in 
whole GetAll reply handler flow, to makesure the on_properties_changed() have 
been executed after async_init_get_all_cb() and on_proxy_ready(). However this 
occurs rarely, and in any case the signal of properties changed should not be 
discarded.


There is proposed patch corrects this.

1. add new API <g_simple_async_result_complete_in_idle_full()> in order to 
raising idle GSources priority.

2. Change idle GSources priority to HIGH in whole GetAll reply handler flow, to 
avoid the properties_change signal will be discarded when it's fallowing 
recevie GetAll reply message.


diff --git a/gio/gdbusconnection.c b/gio/gdbusconnection.c

index fc9acbe..6b2a434 100644

--- a/gio/gdbusconnection.c

+++ b/gio/gdbusconnection.c

@@ -1832,7 +1832,7 @@ send_message_with_reply_deliver (SendMessageData *data, 
gboolean remove)



   data->delivered = TRUE;



-  g_simple_async_result_complete_in_idle (data->simple);

+  g_simple_async_result_complete_in_idle_full (data->simple, G_PRIORITY_HIGH);

   g_object_unref (data->simple);

   data->simple = NULL;



diff --git a/gio/gdbusproxy.c b/gio/gdbusproxy.c

index 33492b7..c7ace07 100644

--- a/gio/gdbusproxy.c

+++ b/gio/gdbusproxy.c

@@ -1463,7 +1463,7 @@ async_init_get_all_cb (GDBusConnection *connection,

                                                  (GDestroyNotify) 
g_variant_unref);

     }



-  g_simple_async_result_complete_in_idle (data->simple);

+  g_simple_async_result_complete_in_idle_full (data->simple, G_PRIORITY_HIGH);

   async_init_data_free (data);

 }



diff --git a/gio/gsimpleasyncresult.c b/gio/gsimpleasyncresult.c

index ee30da2..7e9caf3 100644

--- a/gio/gsimpleasyncresult.c

+++ b/gio/gsimpleasyncresult.c

@@ -778,19 +778,16 @@ complete_in_idle_cb (gpointer data)

 }



 /**

- * g_simple_async_result_complete_in_idle:

+ * g_simple_async_result_complete_in_idle_full:

  * @simple: a #GSimpleAsyncResult.

  *

- * Completes an asynchronous function in an idle handler in the

- * [thread-default main context][g-main-context-push-thread-default]

- * of the thread that @simple was initially created in

- * (and re-pushes that context around the invocation of the callback).

+ * This function is the same as g_simple_async_result_complete_in_idle() 
except that it lets you specify the priority.

  *

  * Calling this function takes a reference to @simple for as long as

  * is needed to complete the call.

  */

 void

-g_simple_async_result_complete_in_idle (GSimpleAsyncResult *simple)

+g_simple_async_result_complete_in_idle_full (GSimpleAsyncResult *simple, gint 
priority)

 {

   GSource *source;



@@ -799,13 +796,31 @@ g_simple_async_result_complete_in_idle 
(GSimpleAsyncResult *simple)

   g_object_ref (simple);



   source = g_idle_source_new ();

-  g_source_set_priority (source, G_PRIORITY_DEFAULT);

+  g_source_set_priority (source, priority);

   g_source_set_callback (source, complete_in_idle_cb, simple, g_object_unref);



   g_source_attach (source, simple->context);

   g_source_unref (source);

 }



+/**

+ * g_simple_async_result_complete_in_idle:

+ * @simple: a #GSimpleAsyncResult.

+ *

+ * Completes an asynchronous function in an idle handler in the

+ * [thread-default main context][g-main-context-push-thread-default]

+ * of the thread that @simple was initially created in

+ * (and re-pushes that context around the invocation of the callback).

+ *

+ * Calling this function takes a reference to @simple for as long as

+ * is needed to complete the call.

+ */

+void

+g_simple_async_result_complete_in_idle (GSimpleAsyncResult *simple)

+{

+  g_simple_async_result_complete_in_idle_full (simple, G_PRIORITY_DEFAULT);

+}

+

 typedef struct {

   GSimpleAsyncResult *simple;

   GCancellable *cancellable;

diff --git a/gio/gsimpleasyncresult.h b/gio/gsimpleasyncresult.h

index 94412f4..52b1039 100644

--- a/gio/gsimpleasyncresult.h

+++ b/gio/gsimpleasyncresult.h

@@ -103,6 +103,8 @@ void                
g_simple_async_result_set_handle_cancellation (GSimpleAsyncR

 GLIB_AVAILABLE_IN_ALL

 void                g_simple_async_result_complete         (GSimpleAsyncResult 
     *simple);

 GLIB_AVAILABLE_IN_ALL

+void                g_simple_async_result_complete_in_idle_full 
(GSimpleAsyncResult      *simple, gint priority);

+GLIB_AVAILABLE_IN_ALL

 void                g_simple_async_result_complete_in_idle (GSimpleAsyncResult 
     *simple);

 GLIB_AVAILABLE_IN_ALL

 void                g_simple_async_result_run_in_thread    (GSimpleAsyncResult 
     *simple,


--
Regards,


Brant Li

Attachment: glib_gdbusproxy_race_condition.patch
Description: glib_gdbusproxy_race_condition.patch

_______________________________________________
gtk-devel-list mailing list
gtk-devel-list@gnome.org
https://mail.gnome.org/mailman/listinfo/gtk-devel-list

Reply via email to