diff options
author | Simon McVittie <smcv@debian.org> | 2018-05-08 09:18:28 +0100 |
---|---|---|
committer | Simon McVittie <smcv@collabora.com> | 2018-05-09 08:53:34 +0100 |
commit | 62789b8dd79f2b29252f31c1f424cc43e4ca5ec5 (patch) | |
tree | 8714640bee744e561e9576cf0a9978b1498cf55b | |
parent | d4732fae047c2d6532ad8049ae0edc2fb3480fe2 (diff) |
cross-test-server: Avoid a race condition in the client
There is a race condition here between these chains of events, which as
far as I can tell has existed for at least 10 years:
* server receives Tests.Trigger() and schedules SignalTests.Triggered
* server returns to main loop
* server emits SignalTests.Triggered
* client receives SignalTests.Triggered
and
* server receives Tests.Trigger() and replies with success
* client receives success and emits SignalTests.Trigger
* server receives SignalTests.Trigger and calls CallbackTests.Response()
* client receives CallbackTests.Response() and calls Tests.Exit()
* server receives Tests.Exit() and replies with success
* client quits its main loop
If we don't reply to Tests.Trigger() until after the SignalTests.Triggered
signal has been sent, because the client called Tests.Trigger()
asynchronously, messages are not re-ordered and the reply arrives after
the signal; so the whole chain of events leading up to
"client receives SignalTests.Triggered" happens before
"client receives success and emits SignalTests.Trigger" and there is
no race condition.
Bug-Debian: https://bugs.debian.org/898158
-rwxr-xr-x | test/cross-test-server.py | 13 |
1 files changed, 9 insertions, 4 deletions
diff --git a/test/cross-test-server.py b/test/cross-test-server.py index 313a063..30edb1c 100755 --- a/test/cross-test-server.py +++ b/test/cross-test-server.py @@ -274,15 +274,18 @@ class TestsImpl(dbus.service.Object): @dbus.service.method(INTERFACE_TESTS, 'st', '', connection_keyword='conn', + async_callbacks=('reply_cb', 'error_cb'), **kwargs) - def Trigger(self, object, parameter, conn=None): + def Trigger(self, object, parameter, conn=None, reply_cb=None, + error_cb=None): assert isinstance(object, str) logger.info('method/signal: client wants me to emit Triggered(%r) from %r', parameter, object) tested_things.add(INTERFACE_TESTS + '.Trigger') gobject.idle_add(lambda: self.emit_Triggered_from(conn, object, - parameter)) - - def emit_Triggered_from(self, conn, object, parameter): + parameter, + reply_cb)) + + def emit_Triggered_from(self, conn, object, parameter, reply_cb): assert isinstance(object, str) logger.info('method/signal: Emitting Triggered(%r) from %r', parameter, object) obj = objects.get(object, None) @@ -291,6 +294,8 @@ class TestsImpl(dbus.service.Object): objects[object] = obj obj.Triggered(parameter) logger.info('method/signal: Emitted Triggered') + reply_cb() + logger.info('method/signal: Sent reply for Tests.Trigger()') @dbus.service.method(INTERFACE_TESTS, '', '') def Exit(self): |