mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-03-28 18:40:03 +01:00
gdbusconnection: don't cache G_IO_ERROR_CANCELLED errors
It can cause failures for shared connection objects. What can currently happen is this: 1. A user starts to asynchronously create a proxy object 2. A user starts to asynchronously create another proxy object At this point, the asynchronous initialization for the two proxy objects share the not yet initialized connection object. 3. While the shared connection objected is created, the user cancels the creation with the supplied cancellable from the fist proxy object. 4. initable_init caches the canceled error and marks the connection as initialized. 5. The initialization of the second proxy object fails with the same canceled error. To avoid this, clear the error in this case and destroy any member variables that may have been created before the creation was canceled. This way, the initialization of the second proxy object will restart the connection initialization and with probably succeed. Signed-off-by: Michael Olbrich <m.olbrich@pengutronix.de>
This commit is contained in:
parent
3904d4c13e
commit
19a6742fc2
@ -2642,7 +2642,26 @@ initable_init (GInitable *initable,
|
||||
g_propagate_error (error, g_error_copy (connection->initialization_error));
|
||||
}
|
||||
|
||||
g_atomic_int_or (&connection->atomic_flags, FLAG_INITIALIZED);
|
||||
/* Don't cache canceled errors. Otherwise other concurrent users of the same connection
|
||||
* object will be canceled as well. */
|
||||
if (g_error_matches (connection->initialization_error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
|
||||
{
|
||||
if (connection->worker != NULL)
|
||||
{
|
||||
_g_dbus_worker_stop (connection->worker);
|
||||
connection->worker = NULL;
|
||||
if (alive_connections != NULL)
|
||||
g_warn_if_fail (g_hash_table_remove (alive_connections, connection));
|
||||
}
|
||||
g_clear_error (&connection->initialization_error);
|
||||
g_clear_object (&connection->stream);
|
||||
g_clear_object (&connection->auth);
|
||||
g_clear_object (&connection->credentials);
|
||||
g_clear_pointer (&connection->guid, g_free);
|
||||
connection->capabilities = 0;
|
||||
}
|
||||
else
|
||||
g_atomic_int_or (&connection->atomic_flags, FLAG_INITIALIZED);
|
||||
g_mutex_unlock (&connection->init_lock);
|
||||
|
||||
return ret;
|
||||
|
@ -1215,6 +1215,70 @@ test_connection_serials (void)
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
static void
|
||||
get_connection_cb_expect_cancel (GObject *source_object,
|
||||
GAsyncResult *res,
|
||||
gpointer user_data)
|
||||
{
|
||||
GDBusConnection *c;
|
||||
GError *error;
|
||||
|
||||
error = NULL;
|
||||
c = g_bus_get_finish (res, &error);
|
||||
|
||||
/* unref here to avoid timeouts when the test fails */
|
||||
if (c)
|
||||
g_object_unref (c);
|
||||
|
||||
g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
|
||||
g_assert_null (c);
|
||||
|
||||
g_error_free (error);
|
||||
}
|
||||
|
||||
static void
|
||||
get_connection_cb_expect_success (GObject *source_object,
|
||||
GAsyncResult *res,
|
||||
gpointer user_data)
|
||||
{
|
||||
GDBusConnection *c;
|
||||
GError *error;
|
||||
|
||||
error = NULL;
|
||||
c = g_bus_get_finish (res, &error);
|
||||
g_assert_no_error (error);
|
||||
g_assert_nonnull (c);
|
||||
|
||||
g_main_loop_quit (loop);
|
||||
|
||||
g_object_unref (c);
|
||||
}
|
||||
|
||||
static void
|
||||
test_connection_cancel (void)
|
||||
{
|
||||
GCancellable *cancellable, *cancellable2;
|
||||
|
||||
g_test_summary ("Test that cancelling one of two racing g_bus_get() calls does not cancel the other one");
|
||||
|
||||
session_bus_up ();
|
||||
|
||||
cancellable = g_cancellable_new ();
|
||||
cancellable2 = g_cancellable_new ();
|
||||
|
||||
g_bus_get (G_BUS_TYPE_SESSION, cancellable, get_connection_cb_expect_cancel, NULL);
|
||||
g_bus_get (G_BUS_TYPE_SESSION, cancellable2, get_connection_cb_expect_success, NULL);
|
||||
g_cancellable_cancel (cancellable);
|
||||
g_main_loop_run (loop);
|
||||
|
||||
g_object_unref (cancellable);
|
||||
g_object_unref (cancellable2);
|
||||
|
||||
session_bus_down ();
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
static void
|
||||
test_connection_basic (void)
|
||||
{
|
||||
@ -1301,6 +1365,7 @@ main (int argc,
|
||||
g_test_add_func ("/gdbus/connection/signal-match-rules", test_connection_signal_match_rules);
|
||||
g_test_add_func ("/gdbus/connection/filter", test_connection_filter);
|
||||
g_test_add_func ("/gdbus/connection/serials", test_connection_serials);
|
||||
g_test_add_func ("/gdbus/connection/cancel", test_connection_cancel);
|
||||
ret = g_test_run();
|
||||
|
||||
g_main_loop_unref (loop);
|
||||
|
Loading…
x
Reference in New Issue
Block a user