[glib: 1/2] tests: Reduce wakeup interval in gdbus-threading




commit 58f54e8303ea7d55bd3d52742b82e912ade6f616
Author: Philip Withnall <pwithnall endlessos org>
Date:   Tue Apr 12 14:39:43 2022 +0100

    tests: Reduce wakeup interval in gdbus-threading
    
    When checking that the connection has the expected number of refs, the
    test would block on a `GMainContext` iteration for up to 3s before
    waking up and failing (if the refcount was still not as expected).
    
    This check was written in the expectation that changing the refcount of
    the connection would only happen due to dispatching a source on
    `GMainContext` — hence the `GMainContext` would wake up as the refcount
    changed.
    
    That’s probably not actually true though. It might be the case that the
    connection’s refcount is changed on from the GDBus worker thread, which
    would not cause any wakeups on the main thread’s `GMainContext`.
    
    In this case, the `GMainContext` iteration in
    `assert_connection_has_one_ref()` would block for the full 3s, and then
    wake up and notice the refcount is correct (then the test would
    proceed).
    
    That’s fine, apart from the fact that `test_threaded_singleton()` does
    this 1000 times. If the slow case is hit on a significant number of
    those test runs, the test will take around 3000s to complete, which is
    significantly more than meson’s test timeout of 360s. So the test fails
    with something like:
    ```
    220/266 glib:gio+slow / gdbus-threading         TIMEOUT 360.07 s
    
    --- command ---
    G_TEST_SRCDIR='/builds/GNOME/glib/gio/tests' GIO_MODULE_DIR='' 
G_TEST_BUILDDIR='/builds/GNOME/glib/_build/gio/tests' /builds/GNOME/glib/_build/gio/tests/gdbus-threading
    --- stdout ---
    \# random seed: R02S83fe8de22db4d4f376e6d179e2bdd601
    1..3
    \# Start of gdbus tests
    ok 1 /gdbus/delivery-in-thread
    ok 2 /gdbus/method-calls-in-thread
    \# GLib-GIO-DEBUG: refcount of 0x5602de913660 is not right (3 rather than 1) in 
test_threaded_singleton(), sleeping
    \# GLib-GIO-DEBUG: refcount of 0x5602de913660 is not right (3 rather than 1) in 
test_threaded_singleton(), sleeping
    \# GLib-GIO-DEBUG: refcount of 0x5602de913c60 is not right (3 rather than 1) in 
test_threaded_singleton(), sleeping
    \# GLib-GIO-DEBUG: refcount of 0x5602de913c60 is not right (3 rather than 1) in 
test_threaded_singleton(), sleeping
    \# GLib-GIO-DEBUG: refcount of 0x5602de913260 is not right (3 rather than 1) in 
test_threaded_singleton(), sleeping
    \# GLib-GIO-DEBUG: refcount of 0x5602de913260 is not right (3 rather than 1) in 
test_threaded_singleton(), sleeping
    ```
    
    From this log, it can be seen that the sleep is happening on a different
    `GMainContext` every other time, so the test *is* making progress.
    
    Assuming this is a correct diagnosis (it’s a lot of guessing), this
    commit tries to fix the test by adding a wakeup timeout to the
    `GMainContext` in `assert_connection_has_one_ref()`, which will wake it
    up every 50ms to re-check the exit condition.
    
    This polling approach has been taken because it doesn’t seem feasible to
    make sure that every `g_object_ref()`/`g_object_unref()` call on a
    `GDBusConnection` causes the main context to wake up.
    
    Signed-off-by: Philip Withnall <pwithnall endlessos org>

 gio/tests/gdbus-threading.c | 21 +++++++++++++++++++++
 1 file changed, 21 insertions(+)
---
diff --git a/gio/tests/gdbus-threading.c b/gio/tests/gdbus-threading.c
index 23dc1fde35..a14a776c5b 100644
--- a/gio/tests/gdbus-threading.c
+++ b/gio/tests/gdbus-threading.c
@@ -44,6 +44,13 @@ timeout_cb (gpointer user_data)
   return G_SOURCE_REMOVE;
 }
 
+static gboolean
+wakeup_cb (gpointer user_data)
+{
+  /* nothing to do here */
+  return G_SOURCE_CONTINUE;
+}
+
 /* Check that the given @connection has only one ref, waiting to let any pending
  * unrefs complete first. This is typically used on the shared connection, to
  * ensure it’s in a correct state before beginning the next test. */
@@ -53,15 +60,26 @@ static void
                                  const gchar     *calling_function)
 {
   GSource *timeout_source = NULL;
+  GSource *wakeup_source = NULL;
   TimeoutData data = { context, FALSE };
 
   if (g_atomic_int_get (&G_OBJECT (connection)->ref_count) == 1)
     return;
 
+  /* Use two timeout sources: @timeout_source to set a deadline after which the
+   * test will fail if the @connection doesn’t have the right number of refs;
+   * and @wakeup_source to periodically wake the @context up to allow the
+   * termination condition to be checked. This allows the termination condition
+   * to be fulfilled by something which doesn’t wake @context up, such as an
+   * unref happening in the GDBus worker thread. */
   timeout_source = g_timeout_source_new_seconds (3);
   g_source_set_callback (timeout_source, timeout_cb, &data, NULL);
   g_source_attach (timeout_source, context);
 
+  wakeup_source = g_timeout_source_new (50 /* ms */);
+  g_source_set_callback (wakeup_source, wakeup_cb, NULL, NULL);
+  g_source_attach (wakeup_source, context);
+
   while (g_atomic_int_get (&G_OBJECT (connection)->ref_count) != 1 && !data.timed_out)
     {
       g_debug ("refcount of %p is not right (%u rather than 1) in %s(), sleeping",
@@ -69,6 +87,9 @@ static void
       g_main_context_iteration (NULL, TRUE);
     }
 
+  g_source_destroy (wakeup_source);
+  g_source_unref (wakeup_source);
+
   g_source_destroy (timeout_source);
   g_source_unref (timeout_source);
 


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