Package: dbus-python / 1.2.8-3

cross-test-server-Avoid-a-race-condition-in-the-client.patch Patch series | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
From: Simon McVittie <smcv@debian.org>
Date: Tue, 8 May 2018 09:18:28 +0100
Subject: 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
Applied-upstream: 1.2.10, commit:62789b8dd79f2b29252f31c1f424cc43e4ca5ec5
---
 test/cross-test-server.py | 13 +++++++++----
 1 file 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):