Merge lp:~albaguirre/mir/fix-tsan-findings into lp:mir
- fix-tsan-findings
- Merge into development-branch
Status: | Merged |
---|---|
Approved by: | Alberto Aguirre |
Approved revision: | no longer in the source branch. |
Merged at revision: | 3199 |
Proposed branch: | lp:~albaguirre/mir/fix-tsan-findings |
Merge into: | lp:mir |
Diff against target: |
1121 lines (+232/-340) 16 files modified
cmake/MirCommon.cmake (+3/-1) src/server/compositor/buffer_stream_surfaces.cpp (+10/-7) src/server/compositor/multi_threaded_compositor.cpp (+16/-11) src/server/scene/surface_stack.cpp (+2/-1) src/server/scene/surface_stack.h (+4/-3) tests/acceptance-tests/test_unresponsive_client.cpp (+12/-3) tests/include/mir/test/stub_server_tool.h (+24/-7) tests/include/mir/test/test_protobuf_client.h (+26/-50) tests/include/mir_test_framework/stub_input_platform.h (+2/-0) tests/mir_test_doubles/test_protobuf_client.cpp (+86/-133) tests/mir_test_framework/stub_input_platform.cpp (+4/-0) tests/unit-tests/client/test_client_mir_surface.cpp (+5/-1) tests/unit-tests/frontend/test_protobuf_reports_errors.cpp (+1/-1) tests/unit-tests/frontend/test_protobuf_surface_apis.cpp (+3/-7) tests/unit-tests/frontend/test_published_socket_connector.cpp (+32/-114) tests/unit-tests/thread/test_basic_thread_pool.cpp (+2/-1) |
To merge this branch: | bzr merge lp:~albaguirre/mir/fix-tsan-findings |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Alan Griffiths | Approve | ||
PS Jenkins bot (community) | continuous-integration | Approve | |
Daniel van Vugt | Abstain | ||
Review via email: mp+279816@code.launchpad.net |
Commit message
Fix TSan findings
Description of the change
Fix TSan findings
PS Jenkins bot (ps-jenkins) wrote : | # |
Alberto Aguirre (albaguirre) wrote : | # |
Umm unsure if I introduced an issue or uncovered one...I'll check tomorrow.
Alan Griffiths (alan-griffiths) wrote : | # |
Changes look sensible, but from multiple motivations which makes reviewing harder.
Triggering a rebuild to get another datapoint
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:3183
http://
Executed test runs:
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
FAILURE: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Alberto Aguirre (albaguirre) wrote : | # |
^-- the xenial-amd64 failure also happens with lp:mir, it's lp:1523965
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:3185
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
Daniel van Vugt (vanvugt) wrote : | # |
Sounds good.
Hopefully we'll reach a point where we're clean enough to automate this in CI...
Alberto Aguirre (albaguirre) wrote : | # |
We had a CI job that ran Thread Sanitizer with a clang build. I believe it got axed after the GCC5/clang fiasco.
So now with Jenkass we should setup a GCC TSan job.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Autolanding.
More details in the following jenkins job:
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Daniel van Vugt (vanvugt) wrote : | # |
Failed due to lots of FD leaks. Is that right?
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:3188
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
Alan Griffiths (alan-griffiths) wrote : | # |
I'd really like to approve a lot of these changes as they are obviously correct.
But the rework of CompositingFunc
~~~~
+ //Appease TSan, avoid destructor and this thread accessing the same shared_ptr instance
+ auto disp_listener = std::move(
As display_listener is const, isn't this simpler as:
auto const disp_listener = display_listener;
Or even better, just make it a value capture in the lines below? Vis:
auto display_
{ display_
{ display_
~~~~
- auto on_startup_failure = on_unwind(
- [this]
- {
- if (started_
- started.
- });
-
...
catch(...)
{
+ try
+ {
+ //Move the promise so that the promise destructor occurs here rather than in the thread
+ //destroying CompositingFunctor, mostly to appease TSan
+ auto promise = std::move(started);
+ promise.
+ }
+ catch(...)
+ {
+ }
So we no longer use "on_unwind()" because the destructor of the moved promise will throw after we set_exception()? And then we eat the exception anyway? That seems an overly complex mechanism to destroy CompositingFunc
Alberto Aguirre (albaguirre) wrote : | # |
>As display_listener is const, isn't this simpler as:
> auto const disp_listener = display_listener;
The MP code I propose avoids an unnecessary ref count increase, but sure I can make that change.
>Or even better, just make it a value capture in the lines below? Vis:
You cannot capture a member variable directly; you can only through access through "this" (or by creating a local reference that the lambda can then capture).
> So we no longer use "on_unwind()" because the destructor of the moved promise
> will throw after we set_exception()? And then we eat the exception anyway?
> That seems an overly complex mechanism to destroy CompositingFunc
No. I didn't see a need for unwind helper since we already have a catch block.
The main motivation is not removing the unwind helper, it's removing the query of std::future since it's not threadsafe (std::future sate would be accessed by two threads). Rather than synchronizing that access, I avoid querying the std::future at all. Since I won't check its status, then set_exception may throw if it already has a value and so we eat the exception.
The move of the std::promise is also to avoid two threads access std::promise state, the thread calling the destructor and the thread accessing the promise (the compositing thread).
Alan Griffiths (alan-griffiths) wrote : | # |
> >As display_listener is const, isn't this simpler as:
>
> > auto const disp_listener = display_listener;
>
> The MP code I propose avoids an unnecessary ref count increase, but sure I can
> make that change.
Don't we get a single ref count increment in both cases? The proposed version can't move from a const display_listener so an unnamed temporary is created for the move.
> >Or even better, just make it a value capture in the lines below? Vis:
>
> You cannot capture a member variable directly; you can only through access
> through "this" (or by creating a local reference that the lambda can then
> capture).
I gave the syntax I was thinking of. Admittedly, that does create two copies of display_listener.
~~~~
> > So we no longer use "on_unwind()" because the destructor of the moved
> promise
> > will throw after we set_exception()? And then we eat the exception anyway?
> > That seems an overly complex mechanism to destroy
> CompositingFunc
>
> No. I didn't see a need for unwind helper since we already have a catch block.
>
> The main motivation is not removing the unwind helper, it's removing the query
> of std::future since it's not threadsafe (std::future sate would be accessed
> by two threads). Rather than synchronizing that access, I avoid querying the
> std::future at all. Since I won't check its status, then set_exception may
> throw if it already has a value and so we eat the exception.
>
> The move of the std::promise is also to avoid two threads access std::promise
> state, the thread calling the destructor and the thread accessing the promise
> (the compositing thread).
I need to think about this - it sounds like the wrong synchronization objects are being used.
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:3189
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
FAILURE: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Alan Griffiths (alan-griffiths) wrote : | # |
OK, I still think the logic around started/
Preview Diff
1 | === modified file 'cmake/MirCommon.cmake' |
2 | --- cmake/MirCommon.cmake 2015-12-14 06:21:46 +0000 |
3 | +++ cmake/MirCommon.cmake 2015-12-14 15:38:49 +0000 |
4 | @@ -74,7 +74,9 @@ |
5 | endif() |
6 | endif() |
7 | # Space after ${TSAN_EXTRA_OPTIONS} works around bug in TSAN env. variable parsing |
8 | - list(APPEND test_env "TSAN_OPTIONS=\"suppressions=${CMAKE_SOURCE_DIR}/tools/tsan-suppressions second_deadlock_stack=1 halt_on_error=1 history_size=7 ${TSAN_EXTRA_OPTIONS} \"") |
9 | + list(APPEND test_env "TSAN_OPTIONS=\"suppressions=${CMAKE_SOURCE_DIR}/tools/tsan-suppressions second_deadlock_stack=1 halt_on_error=1 history_size=7 die_after_fork=0 ${TSAN_EXTRA_OPTIONS} \"") |
10 | + # TSan does not support starting threads after fork |
11 | + set(test_exclusion_filter "ThreadedDispatcherSignalTest.keeps_dispatching_after_signal_interruption") |
12 | endif() |
13 | |
14 | if(SYSTEM_SUPPORTS_O_TMPFILE EQUAL 1) |
15 | |
16 | === modified file 'src/server/compositor/buffer_stream_surfaces.cpp' |
17 | --- src/server/compositor/buffer_stream_surfaces.cpp 2015-11-21 00:23:00 +0000 |
18 | +++ src/server/compositor/buffer_stream_surfaces.cpp 2015-12-14 15:38:49 +0000 |
19 | @@ -59,20 +59,20 @@ |
20 | { |
21 | buffer_bundle->client_release(buf); |
22 | { |
23 | - std::unique_lock<std::mutex> lk(mutex); |
24 | + std::lock_guard<decltype(mutex)> lk(mutex); |
25 | first_frame_posted = true; |
26 | } |
27 | } |
28 | |
29 | geom::Size mc::BufferStreamSurfaces::stream_size() |
30 | { |
31 | - std::unique_lock<std::mutex> lk(mutex); |
32 | + std::lock_guard<decltype(mutex)> lk(mutex); |
33 | return logical_size; |
34 | } |
35 | |
36 | void mc::BufferStreamSurfaces::resize(geom::Size const& size) |
37 | { |
38 | - std::unique_lock<std::mutex> lk(mutex); |
39 | + std::lock_guard<decltype(mutex)> lk(mutex); |
40 | logical_size = size; |
41 | buffer_bundle->resize(logical_size * scale); |
42 | } |
43 | @@ -117,14 +117,17 @@ |
44 | |
45 | bool mc::BufferStreamSurfaces::has_submitted_buffer() const |
46 | { |
47 | - std::unique_lock<std::mutex> lk(mutex); |
48 | + std::lock_guard<decltype(mutex)> lk(mutex); |
49 | return first_frame_posted; |
50 | } |
51 | |
52 | void mc::BufferStreamSurfaces::with_most_recent_buffer_do(std::function<void(graphics::Buffer&)> const& exec) |
53 | { |
54 | - if (!first_frame_posted) |
55 | - BOOST_THROW_EXCEPTION(std::runtime_error("No frame posted yet")); |
56 | + { |
57 | + std::lock_guard<decltype(mutex)> lk(mutex); |
58 | + if (!first_frame_posted) |
59 | + BOOST_THROW_EXCEPTION(std::runtime_error("No frame posted yet")); |
60 | + } |
61 | exec(*std::make_shared<mc::TemporarySnapshotBuffer>(buffer_bundle)); |
62 | } |
63 | |
64 | @@ -164,7 +167,7 @@ |
65 | if (new_scale <= 0.0f) |
66 | BOOST_THROW_EXCEPTION(std::logic_error("invalid scale (must be greater than zero)")); |
67 | |
68 | - std::unique_lock<std::mutex> lk(mutex); |
69 | + std::lock_guard<decltype(mutex)> lk(mutex); |
70 | scale = new_scale; |
71 | buffer_bundle->resize(logical_size * scale); |
72 | } |
73 | |
74 | === modified file 'src/server/compositor/multi_threaded_compositor.cpp' |
75 | --- src/server/compositor/multi_threaded_compositor.cpp 2015-09-22 14:53:26 +0000 |
76 | +++ src/server/compositor/multi_threaded_compositor.cpp 2015-12-14 15:38:49 +0000 |
77 | @@ -73,13 +73,6 @@ |
78 | void operator()() noexcept // noexcept is important! (LP: #1237332) |
79 | try |
80 | { |
81 | - auto on_startup_failure = on_unwind( |
82 | - [this] |
83 | - { |
84 | - if (started_future.wait_for(0s) != std::future_status::ready) |
85 | - started.set_exception(std::current_exception()); |
86 | - }); |
87 | - |
88 | mir::set_thread_name("Mir/Comp"); |
89 | |
90 | std::vector<std::tuple<mg::DisplayBuffer*, std::unique_ptr<mc::DisplayBufferCompositor>>> compositors; |
91 | @@ -96,11 +89,13 @@ |
92 | CompositorReport::SubCompositorId{comp_id}); |
93 | }); |
94 | |
95 | + //Appease TSan, avoid destructor and this thread accessing the same shared_ptr instance |
96 | + auto const disp_listener = display_listener; |
97 | auto display_registration = mir::raii::paired_calls( |
98 | - [this]{group.for_each_display_buffer([this](mg::DisplayBuffer& buffer) |
99 | - { display_listener->add_display(buffer.view_area()); });}, |
100 | - [this]{group.for_each_display_buffer([this](mg::DisplayBuffer& buffer) |
101 | - { display_listener->remove_display(buffer.view_area()); });}); |
102 | + [this, &disp_listener]{group.for_each_display_buffer([&disp_listener](mg::DisplayBuffer& buffer) |
103 | + { disp_listener->add_display(buffer.view_area()); });}, |
104 | + [this, &disp_listener]{group.for_each_display_buffer([&disp_listener](mg::DisplayBuffer& buffer) |
105 | + { disp_listener->remove_display(buffer.view_area()); });}); |
106 | |
107 | auto compositor_registration = mir::raii::paired_calls( |
108 | [this,&compositors] |
109 | @@ -179,6 +174,16 @@ |
110 | } |
111 | catch(...) |
112 | { |
113 | + try |
114 | + { |
115 | + //Move the promise so that the promise destructor occurs here rather than in the thread |
116 | + //destroying CompositingFunctor, mostly to appease TSan |
117 | + auto promise = std::move(started); |
118 | + promise.set_exception(std::current_exception()); |
119 | + } |
120 | + catch(...) |
121 | + { |
122 | + } |
123 | mir::terminate_with_current_exception(); |
124 | } |
125 | |
126 | |
127 | === modified file 'src/server/scene/surface_stack.cpp' |
128 | --- src/server/scene/surface_stack.cpp 2015-12-03 23:57:09 +0000 |
129 | +++ src/server/scene/surface_stack.cpp 2015-12-14 15:38:49 +0000 |
130 | @@ -121,7 +121,8 @@ |
131 | |
132 | ms::SurfaceStack::SurfaceStack( |
133 | std::shared_ptr<SceneReport> const& report) : |
134 | - report{report} |
135 | + report{report}, |
136 | + scene_changed{false} |
137 | { |
138 | } |
139 | |
140 | |
141 | === modified file 'src/server/scene/surface_stack.h' |
142 | --- src/server/scene/surface_stack.h 2015-12-03 10:28:45 +0000 |
143 | +++ src/server/scene/surface_stack.h 2015-12-14 15:38:49 +0000 |
144 | @@ -28,11 +28,12 @@ |
145 | |
146 | #include "mir/basic_observers.h" |
147 | |
148 | +#include <atomic> |
149 | +#include <map> |
150 | #include <memory> |
151 | -#include <vector> |
152 | #include <mutex> |
153 | -#include <map> |
154 | #include <set> |
155 | +#include <vector> |
156 | |
157 | namespace mir |
158 | { |
159 | @@ -119,7 +120,7 @@ |
160 | std::vector<std::shared_ptr<graphics::Renderable>> overlays; |
161 | |
162 | Observers observers; |
163 | - bool scene_changed = false; |
164 | + std::atomic<bool> scene_changed; |
165 | }; |
166 | |
167 | } |
168 | |
169 | === modified file 'tests/acceptance-tests/test_unresponsive_client.cpp' |
170 | --- tests/acceptance-tests/test_unresponsive_client.cpp 2015-07-28 09:09:00 +0000 |
171 | +++ tests/acceptance-tests/test_unresponsive_client.cpp 2015-12-14 15:38:49 +0000 |
172 | @@ -32,8 +32,9 @@ |
173 | #include <gtest/gtest.h> |
174 | #include <gmock/gmock.h> |
175 | |
176 | +#include <future> |
177 | +#include <mutex> |
178 | #include <string> |
179 | -#include <future> |
180 | |
181 | namespace ms = mir::scene; |
182 | namespace mt = mir::test; |
183 | @@ -45,19 +46,27 @@ |
184 | { |
185 | struct SessionListener : ms::NullSessionListener |
186 | { |
187 | + ~SessionListener() |
188 | + { |
189 | + std::lock_guard<decltype(guard)> lk{guard}; |
190 | + sessions.clear(); |
191 | + } |
192 | + |
193 | void starting(std::shared_ptr<ms::Session> const& session) override |
194 | - { sessions.insert(session); } |
195 | + { std::lock_guard<decltype(guard)> lk{guard}; sessions.insert(session); } |
196 | |
197 | void stopping(std::shared_ptr<ms::Session> const& session) override |
198 | - { sessions.erase(session); } |
199 | + { std::lock_guard<decltype(guard)> lk{guard}; sessions.erase(session); } |
200 | |
201 | void for_each(std::function<void(std::shared_ptr<ms::Session> const&)> f) const |
202 | { |
203 | + std::lock_guard<decltype(guard)> lk{guard}; |
204 | for (auto& session : sessions) |
205 | f(session); |
206 | } |
207 | |
208 | private: |
209 | + std::mutex mutable guard; |
210 | std::set<std::shared_ptr<ms::Session>> sessions; |
211 | }; |
212 | } |
213 | |
214 | === modified file 'tests/include/mir/test/stub_server_tool.h' |
215 | --- tests/include/mir/test/stub_server_tool.h 2015-09-18 14:44:59 +0000 |
216 | +++ tests/include/mir/test/stub_server_tool.h 2015-12-14 15:38:49 +0000 |
217 | @@ -44,8 +44,8 @@ |
218 | response->set_pixel_format(request->pixel_format()); |
219 | response->mutable_buffer()->set_buffer_id(22); |
220 | |
221 | - std::unique_lock<std::mutex> lock(guard); |
222 | - surface_name = request->surface_name(); |
223 | + std::lock_guard<std::mutex> lock(guard); |
224 | + surf_name = request->surface_name(); |
225 | wait_condition.notify_one(); |
226 | |
227 | done->Run(); |
228 | @@ -58,7 +58,8 @@ |
229 | { |
230 | response->set_buffer_id(22); |
231 | |
232 | - std::unique_lock<std::mutex> lock(guard); |
233 | + std::lock_guard<std::mutex> lock(guard); |
234 | + //FIXME: huh? What's the condition here? |
235 | wait_condition.notify_one(); |
236 | done->Run(); |
237 | } |
238 | @@ -78,7 +79,10 @@ |
239 | mir::protobuf::Connection* connect_msg, |
240 | google::protobuf::Closure* done) override |
241 | { |
242 | - app_name = request->application_name(); |
243 | + { |
244 | + std::lock_guard<std::mutex> lock(guard); |
245 | + app_name = request->application_name(); |
246 | + } |
247 | // If you check out MirConnection::connected either the platform and display_configuration |
248 | // have to be set or the error has to be set, otherwise we die and fail to callback. |
249 | // |
250 | @@ -95,7 +99,8 @@ |
251 | mir::protobuf::Void* /*response*/, |
252 | google::protobuf::Closure* done) override |
253 | { |
254 | - std::unique_lock<std::mutex> lock(guard); |
255 | + std::lock_guard<std::mutex> lock(guard); |
256 | + //FIXME: huh? What's the condition here? |
257 | wait_condition.notify_one(); |
258 | done->Run(); |
259 | } |
260 | @@ -108,8 +113,20 @@ |
261 | done->Run(); |
262 | } |
263 | |
264 | - std::mutex guard; |
265 | - std::string surface_name; |
266 | + std::string application_name() const |
267 | + { |
268 | + std::lock_guard<std::mutex> lock(guard); |
269 | + return app_name; |
270 | + } |
271 | + |
272 | + std::string surface_name() const |
273 | + { |
274 | + std::lock_guard<std::mutex> lock(guard); |
275 | + return surf_name; |
276 | + } |
277 | + |
278 | + std::mutex mutable guard; |
279 | + std::string surf_name; |
280 | std::condition_variable wait_condition; |
281 | std::string app_name; |
282 | }; |
283 | |
284 | === modified file 'tests/include/mir/test/test_protobuf_client.h' |
285 | --- tests/include/mir/test/test_protobuf_client.h 2015-09-18 14:44:59 +0000 |
286 | +++ tests/include/mir/test/test_protobuf_client.h 2015-12-14 15:38:49 +0000 |
287 | @@ -26,8 +26,10 @@ |
288 | |
289 | #include <gmock/gmock.h> |
290 | |
291 | -#include <memory> |
292 | -#include <atomic> |
293 | +#include <condition_variable> |
294 | +#include <functional> |
295 | +#include <mutex> |
296 | +#include <string> |
297 | |
298 | namespace mir |
299 | { |
300 | @@ -63,69 +65,43 @@ |
301 | MOCK_METHOD0(connect_done, void()); |
302 | MOCK_METHOD0(create_surface_done, void()); |
303 | MOCK_METHOD0(next_buffer_done, void()); |
304 | - MOCK_METHOD0(exchange_buffer_done, void()); |
305 | - MOCK_METHOD0(release_surface_done, void()); |
306 | MOCK_METHOD0(disconnect_done, void()); |
307 | MOCK_METHOD0(display_configure_done, void()); |
308 | - MOCK_METHOD0(prompt_session_start_done, void()); |
309 | - MOCK_METHOD0(prompt_session_stop_done, void()); |
310 | |
311 | void on_connect_done(); |
312 | - |
313 | void on_create_surface_done(); |
314 | - |
315 | void on_next_buffer_done(); |
316 | - |
317 | - void on_exchange_buffer_done(); |
318 | - |
319 | - void on_release_surface_done(); |
320 | - |
321 | void on_disconnect_done(); |
322 | - |
323 | void on_configure_display_done(); |
324 | |
325 | + void connect(); |
326 | + void disconnect(); |
327 | + void create_surface(); |
328 | + void next_buffer(); |
329 | + void configure_display(); |
330 | + |
331 | void wait_for_connect_done(); |
332 | - |
333 | void wait_for_create_surface(); |
334 | - |
335 | void wait_for_next_buffer(); |
336 | - |
337 | - void wait_for_exchange_buffer(); |
338 | - |
339 | - void wait_for_release_surface(); |
340 | - |
341 | void wait_for_disconnect_done(); |
342 | - |
343 | + void wait_for_configure_display_done(); |
344 | void wait_for_surface_count(int count); |
345 | |
346 | - void wait_for_disconnect_count(int count); |
347 | - |
348 | - void tfd_done(); |
349 | - |
350 | - void wait_for_tfd_done(); |
351 | - |
352 | - void wait_for_configure_display_done(); |
353 | - |
354 | - void wait_for_prompt_session_start_done(); |
355 | - |
356 | - void wait_for_prompt_session_stop_done(); |
357 | - |
358 | - const int maxwait; |
359 | - std::atomic<bool> connect_done_called; |
360 | - std::atomic<bool> create_surface_called; |
361 | - std::atomic<bool> next_buffer_called; |
362 | - std::atomic<bool> exchange_buffer_called; |
363 | - std::atomic<bool> release_surface_called; |
364 | - std::atomic<bool> disconnect_done_called; |
365 | - std::atomic<bool> configure_display_done_called; |
366 | - std::atomic<bool> tfd_done_called; |
367 | - |
368 | - WaitCondition wc_prompt_session_start; |
369 | - WaitCondition wc_prompt_session_stop; |
370 | - |
371 | - std::atomic<int> connect_done_count; |
372 | - std::atomic<int> create_surface_done_count; |
373 | - std::atomic<int> disconnect_done_count; |
374 | + void wait_for(std::function<bool()> const& predicate, std::string const& error_message); |
375 | + void signal_condition(bool& condition); |
376 | + void reset_condition(bool& condition); |
377 | + |
378 | + int const maxwait; |
379 | + bool connect_done_called; |
380 | + bool create_surface_called; |
381 | + bool next_buffer_called; |
382 | + bool exchange_buffer_called; |
383 | + bool disconnect_done_called; |
384 | + bool configure_display_done_called; |
385 | + int create_surface_done_count; |
386 | + |
387 | + std::mutex mutable guard; |
388 | + std::condition_variable cv; |
389 | }; |
390 | } |
391 | } |
392 | |
393 | === modified file 'tests/include/mir_test_framework/stub_input_platform.h' |
394 | --- tests/include/mir_test_framework/stub_input_platform.h 2015-10-14 15:22:39 +0000 |
395 | +++ tests/include/mir_test_framework/stub_input_platform.h 2015-12-14 15:38:49 +0000 |
396 | @@ -21,6 +21,7 @@ |
397 | #include "mir/input/platform.h" |
398 | #include <atomic> |
399 | #include <memory> |
400 | +#include <mutex> |
401 | #include <vector> |
402 | |
403 | namespace mir |
404 | @@ -59,6 +60,7 @@ |
405 | std::shared_ptr<mir::input::InputDeviceRegistry> const registry; |
406 | static std::atomic<StubInputPlatform*> stub_input_platform; |
407 | static std::vector<std::weak_ptr<mir::input::InputDevice>> device_store; |
408 | + static std::mutex device_store_guard; |
409 | }; |
410 | |
411 | } |
412 | |
413 | === modified file 'tests/mir_test_doubles/test_protobuf_client.cpp' |
414 | --- tests/mir_test_doubles/test_protobuf_client.cpp 2015-09-18 14:44:59 +0000 |
415 | +++ tests/mir_test_doubles/test_protobuf_client.cpp 2015-12-14 15:38:49 +0000 |
416 | @@ -29,15 +29,16 @@ |
417 | #include "mir/dispatch/threaded_dispatcher.h" |
418 | #include "mir/events/event_private.h" |
419 | |
420 | +#include <boost/throw_exception.hpp> |
421 | + |
422 | +#include <stdexcept> |
423 | #include <thread> |
424 | |
425 | namespace mtd = mir::test::doubles; |
426 | namespace mclr = mir::client::rpc; |
427 | namespace md = mir::dispatch; |
428 | |
429 | -mir::test::TestProtobufClient::TestProtobufClient( |
430 | - std::string socket_file, |
431 | - int timeout_ms) : |
432 | +mir::test::TestProtobufClient::TestProtobufClient(std::string socket_file, int timeout_ms) : |
433 | rpc_report(std::make_shared<testing::NiceMock<doubles::MockRpcReport>>()), |
434 | channel(mclr::make_rpc_channel( |
435 | socket_file, |
436 | @@ -54,13 +55,9 @@ |
437 | create_surface_called(false), |
438 | next_buffer_called(false), |
439 | exchange_buffer_called(false), |
440 | - release_surface_called(false), |
441 | disconnect_done_called(false), |
442 | configure_display_done_called(false), |
443 | - tfd_done_called(false), |
444 | - connect_done_count(0), |
445 | - create_surface_done_count(0), |
446 | - disconnect_done_count(0) |
447 | + create_surface_done_count(0) |
448 | { |
449 | surface_parameters.set_width(640); |
450 | surface_parameters.set_height(480); |
451 | @@ -76,177 +73,133 @@ |
452 | .WillByDefault(testing::Invoke(this, &TestProtobufClient::on_create_surface_done)); |
453 | ON_CALL(*this, next_buffer_done()) |
454 | .WillByDefault(testing::Invoke(this, &TestProtobufClient::on_next_buffer_done)); |
455 | - ON_CALL(*this, exchange_buffer_done()) |
456 | - .WillByDefault(testing::Invoke(this, &TestProtobufClient::on_exchange_buffer_done)); |
457 | - ON_CALL(*this, release_surface_done()) |
458 | - .WillByDefault(testing::Invoke(this, &TestProtobufClient::on_release_surface_done)); |
459 | ON_CALL(*this, disconnect_done()) |
460 | .WillByDefault(testing::Invoke(this, &TestProtobufClient::on_disconnect_done)); |
461 | ON_CALL(*this, display_configure_done()) |
462 | .WillByDefault(testing::Invoke(this, &TestProtobufClient::on_configure_display_done)); |
463 | - ON_CALL(*this, prompt_session_start_done()) |
464 | - .WillByDefault(testing::Invoke(&wc_prompt_session_start, &WaitCondition::wake_up_everyone)); |
465 | - ON_CALL(*this, prompt_session_stop_done()) |
466 | - .WillByDefault(testing::Invoke(&wc_prompt_session_stop, &WaitCondition::wake_up_everyone)); |
467 | +} |
468 | + |
469 | +void mir::test::TestProtobufClient::signal_condition(bool& condition) |
470 | +{ |
471 | + std::lock_guard<decltype(guard)> lk{guard}; |
472 | + condition = true; |
473 | + cv.notify_all(); |
474 | +} |
475 | + |
476 | +void mir::test::TestProtobufClient::reset_condition(bool& condition) |
477 | +{ |
478 | + std::lock_guard<decltype(guard)> lk{guard}; |
479 | + condition = false; |
480 | } |
481 | |
482 | void mir::test::TestProtobufClient::on_connect_done() |
483 | { |
484 | - connect_done_called.store(true); |
485 | - |
486 | - auto old = connect_done_count.load(); |
487 | - |
488 | - while (!connect_done_count.compare_exchange_weak(old, old+1)); |
489 | + signal_condition(connect_done_called); |
490 | } |
491 | |
492 | void mir::test::TestProtobufClient::on_create_surface_done() |
493 | { |
494 | - create_surface_called.store(true); |
495 | - |
496 | - auto old = create_surface_done_count.load(); |
497 | - |
498 | - while (!create_surface_done_count.compare_exchange_weak(old, old+1)); |
499 | + std::lock_guard<decltype(guard)> lk{guard}; |
500 | + create_surface_called = true; |
501 | + create_surface_done_count++; |
502 | + cv.notify_all(); |
503 | } |
504 | |
505 | void mir::test::TestProtobufClient::on_next_buffer_done() |
506 | { |
507 | - next_buffer_called.store(true); |
508 | -} |
509 | - |
510 | -void mir::test::TestProtobufClient::on_exchange_buffer_done() |
511 | -{ |
512 | - exchange_buffer_called.store(true); |
513 | -} |
514 | - |
515 | -void mir::test::TestProtobufClient::on_release_surface_done() |
516 | -{ |
517 | - release_surface_called.store(true); |
518 | + signal_condition(next_buffer_called); |
519 | } |
520 | |
521 | void mir::test::TestProtobufClient::on_disconnect_done() |
522 | { |
523 | - disconnect_done_called.store(true); |
524 | - |
525 | - auto old = disconnect_done_count.load(); |
526 | - |
527 | - while (!disconnect_done_count.compare_exchange_weak(old, old+1)); |
528 | + signal_condition(disconnect_done_called); |
529 | } |
530 | |
531 | void mir::test::TestProtobufClient::on_configure_display_done() |
532 | { |
533 | - configure_display_done_called.store(true); |
534 | + signal_condition(configure_display_done_called); |
535 | +} |
536 | + |
537 | +void mir::test::TestProtobufClient::connect() |
538 | +{ |
539 | + reset_condition(connect_done_called); |
540 | + display_server.connect( |
541 | + &connect_parameters, |
542 | + &connection, |
543 | + google::protobuf::NewCallback(this, &TestProtobufClient::connect_done)); |
544 | +} |
545 | + |
546 | +void mir::test::TestProtobufClient::disconnect() |
547 | +{ |
548 | + reset_condition(disconnect_done_called); |
549 | + display_server.disconnect( |
550 | + &ignored, |
551 | + &ignored, |
552 | + google::protobuf::NewCallback(this, &TestProtobufClient::disconnect_done)); |
553 | +} |
554 | + |
555 | +void mir::test::TestProtobufClient::create_surface() |
556 | +{ |
557 | + reset_condition(create_surface_called); |
558 | + display_server.create_surface( |
559 | + &surface_parameters, |
560 | + &surface, |
561 | + google::protobuf::NewCallback(this, &TestProtobufClient::create_surface_done)); |
562 | +} |
563 | + |
564 | +void mir::test::TestProtobufClient::next_buffer() |
565 | +{ |
566 | + reset_condition(next_buffer_called); |
567 | + display_server.next_buffer( |
568 | + &surface.id(), |
569 | + surface.mutable_buffer(), |
570 | + google::protobuf::NewCallback(this, &TestProtobufClient::next_buffer_done)); |
571 | +} |
572 | + |
573 | +void mir::test::TestProtobufClient::configure_display() |
574 | +{ |
575 | + reset_condition(configure_display_done_called); |
576 | + display_server.configure_display( |
577 | + &disp_config, |
578 | + &disp_config_response, |
579 | + google::protobuf::NewCallback(this, &TestProtobufClient::display_configure_done)); |
580 | } |
581 | |
582 | void mir::test::TestProtobufClient::wait_for_configure_display_done() |
583 | { |
584 | - for (int i = 0; !configure_display_done_called.load() && i < maxwait; ++i) |
585 | - { |
586 | - std::this_thread::sleep_for(std::chrono::milliseconds(1)); |
587 | - std::this_thread::yield(); |
588 | - } |
589 | - |
590 | - configure_display_done_called.store(false); |
591 | + wait_for([this]{ return configure_display_done_called; }, "Timed out waiting to configure display"); |
592 | } |
593 | |
594 | void mir::test::TestProtobufClient::wait_for_connect_done() |
595 | { |
596 | - for (int i = 0; !connect_done_called.load() && i < maxwait; ++i) |
597 | - { |
598 | - std::this_thread::sleep_for(std::chrono::milliseconds(1)); |
599 | - std::this_thread::yield(); |
600 | - } |
601 | - |
602 | - connect_done_called.store(false); |
603 | + wait_for([this]{ return connect_done_called; }, "Timed out waiting to connect"); |
604 | } |
605 | |
606 | void mir::test::TestProtobufClient::wait_for_create_surface() |
607 | { |
608 | - for (int i = 0; !create_surface_called.load() && i < maxwait; ++i) |
609 | - { |
610 | - std::this_thread::sleep_for(std::chrono::milliseconds(1)); |
611 | - std::this_thread::yield(); |
612 | - } |
613 | - create_surface_called.store(false); |
614 | + wait_for([this]{ return create_surface_called; }, "Timed out waiting create surface"); |
615 | } |
616 | |
617 | void mir::test::TestProtobufClient::wait_for_next_buffer() |
618 | { |
619 | - for (int i = 0; !next_buffer_called.load() && i < maxwait; ++i) |
620 | - { |
621 | - std::this_thread::sleep_for(std::chrono::milliseconds(1)); |
622 | - std::this_thread::yield(); |
623 | - } |
624 | - next_buffer_called.store(false); |
625 | -} |
626 | - |
627 | -void mir::test::TestProtobufClient::wait_for_exchange_buffer() |
628 | -{ |
629 | - for (int i = 0; !exchange_buffer_called.load() && i < maxwait; ++i) |
630 | - { |
631 | - std::this_thread::sleep_for(std::chrono::milliseconds(1)); |
632 | - std::this_thread::yield(); |
633 | - } |
634 | - exchange_buffer_called.store(false); |
635 | -} |
636 | - |
637 | -void mir::test::TestProtobufClient::wait_for_release_surface() |
638 | -{ |
639 | - for (int i = 0; !release_surface_called.load() && i < maxwait; ++i) |
640 | - { |
641 | - std::this_thread::sleep_for(std::chrono::milliseconds(1)); |
642 | - std::this_thread::yield(); |
643 | - } |
644 | - release_surface_called.store(false); |
645 | + wait_for([this] { return next_buffer_called; }, "Timed out waiting for next buffer"); |
646 | } |
647 | |
648 | void mir::test::TestProtobufClient::wait_for_disconnect_done() |
649 | { |
650 | - for (int i = 0; !disconnect_done_called.load() && i < maxwait; ++i) |
651 | - { |
652 | - std::this_thread::sleep_for(std::chrono::milliseconds(1)); |
653 | - std::this_thread::yield(); |
654 | - } |
655 | - disconnect_done_called.store(false); |
656 | + wait_for([this] { return disconnect_done_called; }, "Timed out waiting to disconnect"); |
657 | } |
658 | |
659 | void mir::test::TestProtobufClient::wait_for_surface_count(int count) |
660 | { |
661 | - for (int i = 0; count != create_surface_done_count.load() && i < 10000; ++i) |
662 | - { |
663 | - std::this_thread::sleep_for(std::chrono::milliseconds(10)); |
664 | - std::this_thread::yield(); |
665 | - } |
666 | -} |
667 | - |
668 | -void mir::test::TestProtobufClient::wait_for_disconnect_count(int count) |
669 | -{ |
670 | - for (int i = 0; count != disconnect_done_count.load() && i < 10000; ++i) |
671 | - { |
672 | - std::this_thread::sleep_for(std::chrono::milliseconds(10)); |
673 | - std::this_thread::yield(); |
674 | - } |
675 | -} |
676 | - |
677 | -void mir::test::TestProtobufClient::tfd_done() |
678 | -{ |
679 | - tfd_done_called.store(true); |
680 | -} |
681 | - |
682 | -void mir::test::TestProtobufClient::wait_for_tfd_done() |
683 | -{ |
684 | - for (int i = 0; !tfd_done_called.load() && i < maxwait; ++i) |
685 | - { |
686 | - std::this_thread::sleep_for(std::chrono::milliseconds(1)); |
687 | - } |
688 | - tfd_done_called.store(false); |
689 | -} |
690 | - |
691 | -void mir::test::TestProtobufClient::wait_for_prompt_session_start_done() |
692 | -{ |
693 | - wc_prompt_session_start.wait_for_at_most_seconds(maxwait); |
694 | -} |
695 | - |
696 | -void mir::test::TestProtobufClient::wait_for_prompt_session_stop_done() |
697 | -{ |
698 | - wc_prompt_session_stop.wait_for_at_most_seconds(maxwait); |
699 | + wait_for([this, count] { return create_surface_done_count == count; }, "Timed out waiting for surface count"); |
700 | +} |
701 | + |
702 | +void mir::test::TestProtobufClient::wait_for(std::function<bool()> const& predicate, std::string const& error_message) |
703 | +{ |
704 | + std::unique_lock<decltype(guard)> lk{guard}; |
705 | + if (!cv.wait_for(lk, std::chrono::milliseconds(maxwait), predicate)) |
706 | + { |
707 | + BOOST_THROW_EXCEPTION(std::runtime_error(error_message)); |
708 | + } |
709 | } |
710 | |
711 | === modified file 'tests/mir_test_framework/stub_input_platform.cpp' |
712 | --- tests/mir_test_framework/stub_input_platform.cpp 2015-10-14 15:22:39 +0000 |
713 | +++ tests/mir_test_framework/stub_input_platform.cpp 2015-12-14 15:38:49 +0000 |
714 | @@ -40,12 +40,14 @@ |
715 | |
716 | mtf::StubInputPlatform::~StubInputPlatform() |
717 | { |
718 | + std::lock_guard<decltype(device_store_guard)> lk{device_store_guard}; |
719 | device_store.clear(); |
720 | stub_input_platform = nullptr; |
721 | } |
722 | |
723 | void mtf::StubInputPlatform::start() |
724 | { |
725 | + std::lock_guard<decltype(device_store_guard)> lk{device_store_guard}; |
726 | for (auto const& dev : device_store) |
727 | { |
728 | auto device = dev.lock(); |
729 | @@ -74,6 +76,7 @@ |
730 | auto input_platform = stub_input_platform.load(); |
731 | if (!input_platform) |
732 | { |
733 | + std::lock_guard<decltype(device_store_guard)> lk{device_store_guard}; |
734 | device_store.push_back(dev); |
735 | return; |
736 | } |
737 | @@ -118,3 +121,4 @@ |
738 | |
739 | std::atomic<mtf::StubInputPlatform*> mtf::StubInputPlatform::stub_input_platform{nullptr}; |
740 | std::vector<std::weak_ptr<mir::input::InputDevice>> mtf::StubInputPlatform::device_store; |
741 | +std::mutex mtf::StubInputPlatform::device_store_guard; |
742 | |
743 | === modified file 'tests/unit-tests/client/test_client_mir_surface.cpp' |
744 | --- tests/unit-tests/client/test_client_mir_surface.cpp 2015-12-08 15:02:49 +0000 |
745 | +++ tests/unit-tests/client/test_client_mir_surface.cpp 2015-12-14 15:38:49 +0000 |
746 | @@ -98,7 +98,11 @@ |
747 | google::protobuf::Closure* done) override |
748 | { |
749 | create_surface_response(response); |
750 | - surface_name = request->surface_name(); |
751 | + { |
752 | + std::lock_guard<std::mutex> lock(guard); |
753 | + surf_name = request->surface_name(); |
754 | + } |
755 | + |
756 | done->Run(); |
757 | } |
758 | |
759 | |
760 | === modified file 'tests/unit-tests/frontend/test_protobuf_reports_errors.cpp' |
761 | --- tests/unit-tests/frontend/test_protobuf_reports_errors.cpp 2015-07-28 20:51:25 +0000 |
762 | +++ tests/unit-tests/frontend/test_protobuf_reports_errors.cpp 2015-12-14 15:38:49 +0000 |
763 | @@ -81,7 +81,7 @@ |
764 | { |
765 | stub_services = std::make_shared<mt::ErrorServer>(); |
766 | server = std::make_shared<mt::TestProtobufServer>("./test_error_fixture", stub_services); |
767 | - client = std::make_shared<mt::TestProtobufClient>("./test_error_fixture", 100); |
768 | + client = std::make_shared<mt::TestProtobufClient>("./test_error_fixture", 10000); |
769 | server->comm->start(); |
770 | } |
771 | |
772 | |
773 | === modified file 'tests/unit-tests/frontend/test_protobuf_surface_apis.cpp' |
774 | --- tests/unit-tests/frontend/test_protobuf_surface_apis.cpp 2015-07-28 20:51:25 +0000 |
775 | +++ tests/unit-tests/frontend/test_protobuf_surface_apis.cpp 2015-12-14 15:38:49 +0000 |
776 | @@ -85,7 +85,7 @@ |
777 | |
778 | stub_server->comm->start(); |
779 | |
780 | - stub_client = std::make_shared<mt::TestProtobufClient>(mtf::test_socket_file(), 100); |
781 | + stub_client = std::make_shared<mt::TestProtobufClient>(mtf::test_socket_file(), 10000); |
782 | stub_client->connect_parameters.set_application_name(__PRETTY_FUNCTION__); |
783 | } |
784 | |
785 | @@ -136,11 +136,7 @@ |
786 | |
787 | for (int i = 0; i != surface_count; ++i) |
788 | { |
789 | - stub_client->display_server.create_surface( |
790 | - &stub_client->surface_parameters, |
791 | - &stub_client->surface, |
792 | - google::protobuf::NewCallback(stub_client.get(), &mt::TestProtobufClient::create_surface_done)); |
793 | - |
794 | + stub_client->create_surface(); |
795 | stub_client->wait_for_create_surface(); |
796 | } |
797 | |
798 | @@ -182,7 +178,7 @@ |
799 | |
800 | for(int i=0; i<number_of_clients; i++) |
801 | { |
802 | - auto client_tmp = std::make_shared<mt::TestProtobufClient>(mtf::test_socket_file(), 100); |
803 | + auto client_tmp = std::make_shared<mt::TestProtobufClient>(mtf::test_socket_file(), 10000); |
804 | clients.push_back(client_tmp); |
805 | } |
806 | } |
807 | |
808 | === modified file 'tests/unit-tests/frontend/test_published_socket_connector.cpp' |
809 | --- tests/unit-tests/frontend/test_published_socket_connector.cpp 2015-09-18 14:44:59 +0000 |
810 | +++ tests/unit-tests/frontend/test_published_socket_connector.cpp 2015-12-14 15:38:49 +0000 |
811 | @@ -29,20 +29,21 @@ |
812 | |
813 | #include "mir_protobuf.pb.h" |
814 | |
815 | -#include "mir/test/doubles/stub_ipc_factory.h" |
816 | -#include "mir/test/doubles/stub_session_authorizer.h" |
817 | -#include "mir/test/doubles/mock_rpc_report.h" |
818 | #include "mir/test/stub_server_tool.h" |
819 | #include "mir/test/test_protobuf_client.h" |
820 | #include "mir/test/test_protobuf_server.h" |
821 | +#include "mir/test/wait_condition.h" |
822 | +#include "mir/test/doubles/stub_ipc_factory.h" |
823 | +#include "mir/test/doubles/stub_session_authorizer.h" |
824 | +#include "mir/test/doubles/mock_rpc_report.h" |
825 | #include "mir/test/doubles/stub_ipc_factory.h" |
826 | #include "mir_test_framework/testing_server_configuration.h" |
827 | |
828 | #include <gtest/gtest.h> |
829 | #include <gmock/gmock.h> |
830 | |
831 | +#include <memory> |
832 | #include <stdexcept> |
833 | -#include <memory> |
834 | #include <string> |
835 | |
836 | namespace mf = mir::frontend; |
837 | @@ -139,11 +140,7 @@ |
838 | { |
839 | EXPECT_CALL(*client, create_surface_done()).Times(1); |
840 | |
841 | - client->display_server.create_surface( |
842 | - &client->surface_parameters, |
843 | - &client->surface, |
844 | - google::protobuf::NewCallback(client.get(), &mt::TestProtobufClient::create_surface_done)); |
845 | - |
846 | + client->create_surface(); |
847 | client->wait_for_create_surface(); |
848 | } |
849 | |
850 | @@ -153,14 +150,10 @@ |
851 | |
852 | client->connect_parameters.set_application_name(__PRETTY_FUNCTION__); |
853 | |
854 | - client->display_server.connect( |
855 | - &client->connect_parameters, |
856 | - &client->connection, |
857 | - google::protobuf::NewCallback(client.get(), &mt::TestProtobufClient::connect_done)); |
858 | - |
859 | + client->connect(); |
860 | client->wait_for_connect_done(); |
861 | |
862 | - EXPECT_EQ(__PRETTY_FUNCTION__, stub_server_tool->app_name); |
863 | + EXPECT_EQ(__PRETTY_FUNCTION__, stub_server_tool->application_name()); |
864 | } |
865 | |
866 | TEST_F(PublishedSocketConnector, create_surface_sets_surface_name) |
867 | @@ -170,36 +163,23 @@ |
868 | |
869 | client->connect_parameters.set_application_name(__PRETTY_FUNCTION__); |
870 | |
871 | - client->display_server.connect( |
872 | - &client->connect_parameters, |
873 | - &client->connection, |
874 | - google::protobuf::NewCallback(client.get(), &mt::TestProtobufClient::connect_done)); |
875 | - |
876 | + client->connect(); |
877 | client->wait_for_connect_done(); |
878 | |
879 | client->surface_parameters.set_surface_name(__PRETTY_FUNCTION__); |
880 | |
881 | - client->display_server.create_surface( |
882 | - &client->surface_parameters, |
883 | - &client->surface, |
884 | - google::protobuf::NewCallback(client.get(), &mt::TestProtobufClient::create_surface_done)); |
885 | - |
886 | + client->create_surface(); |
887 | client->wait_for_create_surface(); |
888 | |
889 | - EXPECT_EQ(__PRETTY_FUNCTION__, stub_server_tool->surface_name); |
890 | + EXPECT_EQ(__PRETTY_FUNCTION__, stub_server_tool->surface_name()); |
891 | } |
892 | |
893 | - |
894 | TEST_F(PublishedSocketConnector, |
895 | create_surface_results_in_a_surface_being_created) |
896 | { |
897 | EXPECT_CALL(*client, create_surface_done()).Times(1); |
898 | |
899 | - client->display_server.create_surface( |
900 | - &client->surface_parameters, |
901 | - &client->surface, |
902 | - google::protobuf::NewCallback(client.get(), &mt::TestProtobufClient::create_surface_done)); |
903 | - |
904 | + client->create_surface(); |
905 | client->wait_for_create_surface(); |
906 | } |
907 | |
908 | @@ -218,19 +198,11 @@ |
909 | using namespace testing; |
910 | |
911 | EXPECT_CALL(*client, create_surface_done()).Times(1); |
912 | - client->display_server.create_surface( |
913 | - &client->surface_parameters, |
914 | - &client->surface, |
915 | - google::protobuf::NewCallback(client.get(), &mt::TestProtobufClient::create_surface_done)); |
916 | - |
917 | + client->create_surface(); |
918 | client->wait_for_create_surface(); |
919 | |
920 | EXPECT_CALL(*client, disconnect_done()).Times(1); |
921 | - client->display_server.disconnect( |
922 | - &client->ignored, |
923 | - &client->ignored, |
924 | - google::protobuf::NewCallback(client.get(), &mt::TestProtobufClient::disconnect_done)); |
925 | - |
926 | + client->disconnect(); |
927 | client->wait_for_disconnect_done(); |
928 | |
929 | Mock::VerifyAndClearExpectations(client.get()); |
930 | @@ -247,11 +219,7 @@ |
931 | |
932 | try |
933 | { |
934 | - client->display_server.disconnect( |
935 | - &client->ignored, |
936 | - &client->ignored, |
937 | - google::protobuf::NewCallback(client.get(), &mt::TestProtobufClient::disconnect_done)); |
938 | - |
939 | + client->disconnect(); |
940 | // the write beat the socket closing |
941 | } |
942 | catch (std::runtime_error const& x) |
943 | @@ -268,11 +236,7 @@ |
944 | EXPECT_CALL(*client, create_surface_done()).Times(testing::AtLeast(0)); |
945 | EXPECT_CALL(*client, disconnect_done()).Times(testing::AtLeast(0)); |
946 | |
947 | - client->display_server.create_surface( |
948 | - &client->surface_parameters, |
949 | - &client->surface, |
950 | - google::protobuf::NewCallback(client.get(), &mt::TestProtobufClient::create_surface_done)); |
951 | - |
952 | + client->create_surface(); |
953 | client->wait_for_create_surface(); |
954 | |
955 | EXPECT_TRUE(client->surface.has_buffer()); |
956 | @@ -280,20 +244,12 @@ |
957 | |
958 | for (int i = 0; i != 8; ++i) |
959 | { |
960 | - client->display_server.next_buffer( |
961 | - &client->surface.id(), |
962 | - client->surface.mutable_buffer(), |
963 | - google::protobuf::NewCallback(client.get(), &mt::TestProtobufClient::next_buffer_done)); |
964 | - |
965 | + client->next_buffer(); |
966 | client->wait_for_next_buffer(); |
967 | EXPECT_TRUE(client->surface.has_buffer()); |
968 | } |
969 | |
970 | - client->display_server.disconnect( |
971 | - &client->ignored, |
972 | - &client->ignored, |
973 | - google::protobuf::NewCallback(client.get(), &mt::TestProtobufClient::disconnect_done)); |
974 | - |
975 | + client->disconnect(); |
976 | client->wait_for_disconnect_done(); |
977 | } |
978 | |
979 | @@ -301,19 +257,11 @@ |
980 | connect_create_surface_then_disconnect_a_session) |
981 | { |
982 | EXPECT_CALL(*client, create_surface_done()).Times(1); |
983 | - client->display_server.create_surface( |
984 | - &client->surface_parameters, |
985 | - &client->surface, |
986 | - google::protobuf::NewCallback(client.get(), &mt::TestProtobufClient::create_surface_done)); |
987 | - |
988 | + client->create_surface(); |
989 | client->wait_for_create_surface(); |
990 | |
991 | EXPECT_CALL(*client, disconnect_done()).Times(1); |
992 | - client->display_server.disconnect( |
993 | - &client->ignored, |
994 | - &client->ignored, |
995 | - google::protobuf::NewCallback(client.get(), &mt::TestProtobufClient::disconnect_done)); |
996 | - |
997 | + client->disconnect(); |
998 | client->wait_for_disconnect_done(); |
999 | } |
1000 | |
1001 | @@ -322,33 +270,22 @@ |
1002 | using namespace testing; |
1003 | |
1004 | EXPECT_CALL(*client, create_surface_done()).Times(AnyNumber()); |
1005 | - client->display_server.create_surface( |
1006 | - &client->surface_parameters, |
1007 | - &client->surface, |
1008 | - google::protobuf::NewCallback(client.get(), &mt::TestProtobufClient::create_surface_done)); |
1009 | - |
1010 | + client->create_surface(); |
1011 | client->wait_for_create_surface(); |
1012 | |
1013 | - std::mutex m; |
1014 | - std::condition_variable cv; |
1015 | - bool done = false; |
1016 | + mt::WaitCondition wc; |
1017 | |
1018 | - ON_CALL(*communicator_report, error(_)).WillByDefault(Invoke([&] (std::exception const&) |
1019 | + ON_CALL(*communicator_report, error(_)).WillByDefault(Invoke([&wc] (std::exception const&) |
1020 | { |
1021 | - std::unique_lock<std::mutex> lock(m); |
1022 | - |
1023 | - done = true; |
1024 | - cv.notify_all(); |
1025 | + wc.wake_up_everyone(); |
1026 | })); |
1027 | |
1028 | EXPECT_CALL(*communicator_report, error(_)).Times(1); |
1029 | |
1030 | client.reset(); |
1031 | |
1032 | - std::unique_lock<std::mutex> lock(m); |
1033 | - |
1034 | - auto const deadline = std::chrono::steady_clock::now() + std::chrono::seconds(1); |
1035 | - while (!done && cv.wait_until(lock, deadline) != std::cv_status::timeout); |
1036 | + wc.wait_for_at_most_seconds(1); |
1037 | + EXPECT_TRUE(wc.woken()); |
1038 | } |
1039 | |
1040 | TEST_F(PublishedSocketConnector, configure_display) |
1041 | @@ -356,11 +293,7 @@ |
1042 | EXPECT_CALL(*client, display_configure_done()) |
1043 | .Times(1); |
1044 | |
1045 | - client->display_server.configure_display( |
1046 | - &client->disp_config, |
1047 | - &client->disp_config_response, |
1048 | - google::protobuf::NewCallback(client.get(), &mt::TestProtobufClient::display_configure_done)); |
1049 | - |
1050 | + client->configure_display(); |
1051 | client->wait_for_configure_display_done(); |
1052 | } |
1053 | |
1054 | @@ -373,20 +306,13 @@ |
1055 | client->connect_parameters.set_application_name(__PRETTY_FUNCTION__); |
1056 | |
1057 | EXPECT_CALL(*client, connect_done()).Times(1); |
1058 | - |
1059 | - client->display_server.connect( |
1060 | - &client->connect_parameters, |
1061 | - &client->connection, |
1062 | - google::protobuf::NewCallback(client.get(), &mt::TestProtobufClient::connect_done)); |
1063 | + client->connect(); |
1064 | + client->wait_for_connect_done(); |
1065 | |
1066 | EXPECT_CALL(*client, create_surface_done()).Times(testing::AtLeast(0)); |
1067 | EXPECT_CALL(*client, disconnect_done()).Times(testing::AtLeast(0)); |
1068 | |
1069 | - client->display_server.create_surface( |
1070 | - &client->surface_parameters, |
1071 | - &client->surface, |
1072 | - google::protobuf::NewCallback(client.get(), &mt::TestProtobufClient::create_surface_done)); |
1073 | - |
1074 | + client->create_surface(); |
1075 | client->wait_for_create_surface(); |
1076 | |
1077 | EXPECT_TRUE(client->surface.has_buffer()); |
1078 | @@ -394,20 +320,12 @@ |
1079 | |
1080 | for (int i = 0; i != next_buffer_calls; ++i) |
1081 | { |
1082 | - client->display_server.next_buffer( |
1083 | - &client->surface.id(), |
1084 | - client->surface.mutable_buffer(), |
1085 | - google::protobuf::NewCallback(client.get(), &mt::TestProtobufClient::next_buffer_done)); |
1086 | - |
1087 | + client->next_buffer(); |
1088 | client->wait_for_next_buffer(); |
1089 | EXPECT_TRUE(client->surface.has_buffer()); |
1090 | } |
1091 | |
1092 | - client->display_server.disconnect( |
1093 | - &client->ignored, |
1094 | - &client->ignored, |
1095 | - google::protobuf::NewCallback(client.get(), &mt::TestProtobufClient::disconnect_done)); |
1096 | - |
1097 | + client->disconnect(); |
1098 | client->wait_for_disconnect_done(); |
1099 | |
1100 | EXPECT_EQ(__PRETTY_FUNCTION__, stub_server_tool->app_name); |
1101 | |
1102 | === modified file 'tests/unit-tests/thread/test_basic_thread_pool.cpp' |
1103 | --- tests/unit-tests/thread/test_basic_thread_pool.cpp 2015-06-25 03:00:08 +0000 |
1104 | +++ tests/unit-tests/thread/test_basic_thread_pool.cpp 2015-12-14 15:38:49 +0000 |
1105 | @@ -22,6 +22,7 @@ |
1106 | #include "mir/test/current_thread_name.h" |
1107 | #include "mir/test/signal.h" |
1108 | |
1109 | +#include <atomic> |
1110 | #include <memory> |
1111 | |
1112 | #include <gmock/gmock.h> |
1113 | @@ -100,7 +101,7 @@ |
1114 | } |
1115 | |
1116 | private: |
1117 | - bool called; |
1118 | + std::atomic<bool> called; |
1119 | bool block; |
1120 | std::string name; |
1121 | mt::Signal signal; |
FAILED: Continuous integration, rev:3183 jenkins. qa.ubuntu. com/job/ mir-ci/ 5789/ jenkins. qa.ubuntu. com/job/ mir-android- vivid-i386- build/5224 jenkins. qa.ubuntu. com/job/ mir-clang- vivid-amd64- build/4130/ console jenkins. qa.ubuntu. com/job/ mir-mediumtests -vivid- touch/5172 jenkins. qa.ubuntu. com/job/ mir-xenial- amd64-ci/ 118 jenkins. qa.ubuntu. com/job/ mir-xenial- amd64-ci/ 118/artifact/ work/output/ *zip*/output. zip jenkins. qa.ubuntu. com/job/ mir-xenial- i386-ci/ 118/console jenkins. qa.ubuntu. com/job/ mir-mediumtests -builder- vivid-armhf/ 5172 jenkins. qa.ubuntu. com/job/ mir-mediumtests -builder- vivid-armhf/ 5172/artifact/ work/output/ *zip*/output. zip jenkins. qa.ubuntu. com/job/ mir-mediumtests -runner- touch/7701 s-jenkins. ubuntu- ci:8080/ job/touch- flash-device/ 25856
http://
Executed test runs:
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild: s-jenkins. ubuntu- ci:8080/ job/mir- ci/5789/ rebuild
http://