From 4144fb410110cdb76f52db677fa29ec43fbd13a7 Mon Sep 17 00:00:00 2001 From: Simon McVittie Date: Thu, 20 Jan 2011 13:41:58 +0000 Subject: [PATCH 4/4] test-privserver-client: wait for server to die between iterations This fixes a race condition: the server exits while the client continues to the next iteration. If the server wins, the test passes. If the client wins, it sends a message to the dying service, never gets a reply, and the test fails. My branch to refactor the main loop for fd.o #23194 seems to make the client more likely to win this race, resulting in intermittent test failures. This is an instance of the general problem described by fd.o #11454. --- test/name-test/test-privserver-client.c | 80 +++++++++++++++++++++++++----- 1 files changed, 66 insertions(+), 14 deletions(-) diff --git a/test/name-test/test-privserver-client.c b/test/name-test/test-privserver-client.c index d02eea8..1c43fae 100644 --- a/test/name-test/test-privserver-client.c +++ b/test/name-test/test-privserver-client.c @@ -11,18 +11,52 @@ die (const char *message, ...) exit (1); } +#define PRIVSERVER_SERVICE "org.freedesktop.DBus.TestSuite.PrivServer" +#define PRIVSERVER_INTERFACE PRIVSERVER_SERVICE +#define PRIVSERVER_DIED_RULE \ + "type='signal',sender='" DBUS_SERVICE_DBUS "'," \ + "interface='" DBUS_INTERFACE_DBUS "',member='NameOwnerChanged'," \ + "arg0='" PRIVSERVER_SERVICE "',arg2=''" + +static DBusHandlerResult +filter_session_message (DBusConnection *connection, + DBusMessage *message, + void *user_data) +{ + dbus_bool_t *service_died_p = user_data; + const char *name, *old_owner, *new_owner; + + if (dbus_message_is_signal (message, + DBUS_INTERFACE_DBUS, + "NameOwnerChanged") && + dbus_message_has_sender (message, DBUS_SERVICE_DBUS) && + dbus_message_get_args (message, NULL, + DBUS_TYPE_STRING, &name, + DBUS_TYPE_STRING, &old_owner, + DBUS_TYPE_STRING, &new_owner, + DBUS_TYPE_INVALID) && + strcmp (name, PRIVSERVER_SERVICE) == 0 && + old_owner[0] != '\0' && + new_owner[0] == '\0') + { + *service_died_p = TRUE; + } + + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; +} + static DBusHandlerResult filter_private_message (DBusConnection *connection, DBusMessage *message, void *user_data) { + dbus_bool_t *private_conn_lost_p = user_data; + if (dbus_message_is_signal (message, DBUS_INTERFACE_LOCAL, "Disconnected")) { - DBusLoop *loop = user_data; - _dbus_loop_quit (loop); - return DBUS_HANDLER_RESULT_HANDLED; + *private_conn_lost_p = TRUE; } return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } @@ -38,8 +72,12 @@ open_shutdown_private_connection (dbus_bool_t use_guid) DBusConnection *privconn; char *addr; char *comma; + dbus_bool_t service_died; + dbus_bool_t private_conn_lost; dbus_error_init (&error); + service_died = FALSE; + private_conn_lost = FALSE; loop = _dbus_loop_new (); @@ -47,10 +85,19 @@ open_shutdown_private_connection (dbus_bool_t use_guid) if (!session) die ("couldn't access session bus\n"); dbus_connection_set_exit_on_disconnect (session, FALSE); - msg = dbus_message_new_method_call ("org.freedesktop.DBus.TestSuite.PrivServer", - "/", - "org.freedesktop.DBus.TestSuite.PrivServer", - "GetPrivateAddress"); + test_connection_setup (loop, session); + + dbus_bus_add_match (session, PRIVSERVER_DIED_RULE, &error); + if (dbus_error_is_set (&error)) + die ("couldn't add match rule \"%s\": %s: %s", PRIVSERVER_DIED_RULE, + error.name, error.message); + + if (!dbus_connection_add_filter (session, filter_session_message, + &service_died, NULL)) + die ("couldn't add filter to session bus\n"); + + msg = dbus_message_new_method_call (PRIVSERVER_SERVICE, "/", + PRIVSERVER_INTERFACE, "GetPrivateAddress"); if (!(reply = dbus_connection_send_with_reply_and_block (session, msg, -1, &error))) die ("couldn't send message: %s\n", error.message); dbus_message_unref (msg); @@ -71,24 +118,29 @@ open_shutdown_private_connection (dbus_bool_t use_guid) dbus_message_unref (reply); dbus_connection_set_exit_on_disconnect (privconn, FALSE); - dbus_connection_add_filter (privconn, filter_private_message, loop, NULL); + if (!dbus_connection_add_filter (privconn, filter_private_message, + &private_conn_lost, NULL)) + die ("couldn't add filter to private connection\n"); test_connection_setup (loop, privconn); - msg = dbus_message_new_method_call ("org.freedesktop.DBus.TestSuite.PrivServer", - "/", - "org.freedesktop.DBus.TestSuite.PrivServer", - "Quit"); + msg = dbus_message_new_method_call (PRIVSERVER_SERVICE, "/", + PRIVSERVER_INTERFACE, "Quit"); if (!dbus_connection_send (session, msg, NULL)) die ("couldn't send Quit message\n"); dbus_message_unref (msg); - _dbus_loop_run (loop); + while (!service_died || !private_conn_lost) + _dbus_loop_iterate (loop, TRUE); + dbus_connection_remove_filter (session, filter_session_message, + &service_died); + dbus_bus_remove_match (session, PRIVSERVER_DIED_RULE, NULL); test_connection_shutdown (loop, session); dbus_connection_unref (session); test_connection_shutdown (loop, privconn); - dbus_connection_remove_filter (privconn, filter_private_message, loop); + dbus_connection_remove_filter (privconn, filter_private_message, + &private_conn_lost); dbus_connection_unref (privconn); _dbus_loop_unref (loop); -- 1.7.2.3