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>
This commit is contained in:
Philip Withnall 2022-04-12 14:39:43 +01:00
parent fd79c8742b
commit 58f54e8303

View File

@ -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 its 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 doesnt 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 doesnt 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);