gdbus-peer: Drop some usage of g_thread_yield()

It's a recipe for race conditions and error; on some hardware
architectures one thread isn't guaranteed to see the results
of writes from another thread without a cache flush.

https://bugzilla.gnome.org/show_bug.cgi?id=700855
This commit is contained in:
Colin Walters 2013-05-22 17:41:32 +01:00
parent ff8f37ac05
commit 49030c8797

View File

@ -66,6 +66,8 @@ static const gchar *datapath;
static gchar *tmp_address = NULL; static gchar *tmp_address = NULL;
static gchar *test_guid = NULL; static gchar *test_guid = NULL;
static GMutex service_loop_lock;
static GCond service_loop_cond;
static GMainLoop *service_loop = NULL; static GMainLoop *service_loop = NULL;
static GDBusServer *server = NULL; static GDBusServer *server = NULL;
static GMainLoop *loop = NULL; static GMainLoop *loop = NULL;
@ -344,6 +346,33 @@ on_new_connection (GDBusServer *server,
return TRUE; return TRUE;
} }
static void
create_service_loop (GMainContext *service_context)
{
g_assert (service_loop == NULL);
g_mutex_lock (&service_loop_lock);
service_loop = g_main_loop_new (service_context, FALSE);
g_cond_broadcast (&service_loop_cond);
g_mutex_unlock (&service_loop_lock);
}
static void
teardown_service_loop (void)
{
g_mutex_lock (&service_loop_lock);
g_clear_pointer (&service_loop, g_main_loop_unref);
g_mutex_unlock (&service_loop_lock);
}
static void
await_service_loop (void)
{
g_mutex_lock (&service_loop_lock);
while (service_loop == NULL)
g_cond_wait (&service_loop_cond, &service_loop_lock);
g_mutex_unlock (&service_loop_lock);
}
static gpointer static gpointer
service_thread_func (gpointer user_data) service_thread_func (gpointer user_data)
{ {
@ -399,12 +428,12 @@ service_thread_func (gpointer user_data)
g_dbus_server_start (server); g_dbus_server_start (server);
service_loop = g_main_loop_new (service_context, FALSE); create_service_loop (service_context);
g_main_loop_run (service_loop); g_main_loop_run (service_loop);
g_main_context_pop_thread_default (service_context); g_main_context_pop_thread_default (service_context);
g_main_loop_unref (service_loop); teardown_service_loop ();
g_main_context_unref (service_context); g_main_context_unref (service_context);
/* test code specifically unrefs the server - see below */ /* test code specifically unrefs the server - see below */
@ -494,12 +523,12 @@ service_thread_func (gpointer data)
data); data);
g_socket_service_start (service); g_socket_service_start (service);
service_loop = g_main_loop_new (service_context, FALSE); create_service_loop (service_context);
g_main_loop_run (service_loop); g_main_loop_run (service_loop);
g_main_context_pop_thread_default (service_context); g_main_context_pop_thread_default (service_context);
g_main_loop_unref (service_loop); teardown_service_loop ();
g_main_context_unref (service_context); g_main_context_unref (service_context);
g_object_unref (address); g_object_unref (address);
@ -649,12 +678,10 @@ test_peer (void)
g_assert (c == NULL); g_assert (c == NULL);
/* bring up a server - we run the server in a different thread to avoid deadlocks */ /* bring up a server - we run the server in a different thread to avoid deadlocks */
service_loop = NULL;
service_thread = g_thread_new ("test_peer", service_thread = g_thread_new ("test_peer",
service_thread_func, service_thread_func,
&data); &data);
while (service_loop == NULL) await_service_loop ();
g_thread_yield ();
g_assert (server != NULL); g_assert (server != NULL);
/* bring up a connection and accept it */ /* bring up a connection and accept it */
@ -1213,12 +1240,12 @@ nonce_tcp_service_thread_func (gpointer user_data)
g_dbus_server_start (server); g_dbus_server_start (server);
service_loop = g_main_loop_new (service_context, FALSE); create_service_loop (service_context);
g_main_loop_run (service_loop); g_main_loop_run (service_loop);
g_main_context_pop_thread_default (service_context); g_main_context_pop_thread_default (service_context);
g_main_loop_unref (service_loop); teardown_service_loop ();
g_main_context_unref (service_context); g_main_context_unref (service_context);
/* test code specifically unrefs the server - see below */ /* test code specifically unrefs the server - see below */
@ -1244,15 +1271,12 @@ test_nonce_tcp (void)
error = NULL; error = NULL;
server = NULL; server = NULL;
service_loop = NULL;
service_thread = g_thread_new ("nonce-tcp-service", service_thread = g_thread_new ("nonce-tcp-service",
nonce_tcp_service_thread_func, nonce_tcp_service_thread_func,
&data); &data);
while (service_loop == NULL) await_service_loop ();
g_thread_yield ();
g_assert (server != NULL); g_assert (server != NULL);
/* bring up a connection and accept it */ /* bring up a connection and accept it */
data.accept_connection = TRUE; data.accept_connection = TRUE;
error = NULL; error = NULL;
@ -1532,12 +1556,12 @@ tcp_anonymous_service_thread_func (gpointer user_data)
g_dbus_server_start (server); g_dbus_server_start (server);
service_loop = g_main_loop_new (service_context, FALSE); create_service_loop (service_context);
g_main_loop_run (service_loop); g_main_loop_run (service_loop);
g_main_context_pop_thread_default (service_context); g_main_context_pop_thread_default (service_context);
g_main_loop_unref (service_loop); teardown_service_loop ();
g_main_context_unref (service_context); g_main_context_unref (service_context);
return NULL; return NULL;
@ -1552,12 +1576,10 @@ test_tcp_anonymous (void)
GError *error; GError *error;
seen_connection = FALSE; seen_connection = FALSE;
service_loop = NULL;
service_thread = g_thread_new ("tcp-anon-service", service_thread = g_thread_new ("tcp-anon-service",
tcp_anonymous_service_thread_func, tcp_anonymous_service_thread_func,
&seen_connection); &seen_connection);
while (service_loop == NULL) await_service_loop ();
g_thread_yield ();
g_assert (server != NULL); g_assert (server != NULL);
error = NULL; error = NULL;
@ -1690,14 +1712,14 @@ codegen_service_thread_func (gpointer user_data)
G_CALLBACK (codegen_on_new_connection), G_CALLBACK (codegen_on_new_connection),
animal); animal);
service_loop = g_main_loop_new (service_context, FALSE); create_service_loop (service_context);
g_main_loop_run (service_loop); g_main_loop_run (service_loop);
g_object_unref (animal); g_object_unref (animal);
g_main_context_pop_thread_default (service_context); g_main_context_pop_thread_default (service_context);
g_main_loop_unref (service_loop); teardown_service_loop ();
g_main_context_unref (service_context); g_main_context_unref (service_context);
g_dbus_server_stop (codegen_server); g_dbus_server_stop (codegen_server);
@ -1725,12 +1747,10 @@ codegen_test_peer (void)
GVariant *value; GVariant *value;
/* bring up a server - we run the server in a different thread to avoid deadlocks */ /* bring up a server - we run the server in a different thread to avoid deadlocks */
service_loop = NULL;
service_thread = g_thread_new ("codegen_test_peer", service_thread = g_thread_new ("codegen_test_peer",
codegen_service_thread_func, codegen_service_thread_func,
NULL); NULL);
while (service_loop == NULL) await_service_loop ();
g_thread_yield ();
g_assert (codegen_server != NULL); g_assert (codegen_server != NULL);
/* Get an animal 1 ... */ /* Get an animal 1 ... */