Merge lp:unity-system-compositor/0.1 into lp:unity-system-compositor/ubuntu
- 0.1
- Merge into ubuntu
Proposed by
Alexandros Frantzis
Status: | Merged |
---|---|
Approved by: | Alexandros Frantzis |
Approved revision: | 256 |
Merged at revision: | 219 |
Proposed branch: | lp:unity-system-compositor/0.1 |
Merge into: | lp:unity-system-compositor/ubuntu |
Diff against target: |
527 lines (+382/-18) (has conflicts) 6 files modified
debian/changelog (+16/-3) src/mir_screen.cpp (+47/-4) src/mir_screen.h (+9/-2) tests/integration-tests/CMakeLists.txt (+1/-0) tests/integration-tests/test_deadlock_lp1491566.cpp (+283/-0) tests/unit-tests/advanceable_timer.cpp (+26/-9) Text conflict in debian/changelog |
To merge this branch: | bzr merge lp:unity-system-compositor/0.1 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
PS Jenkins bot (community) | continuous-integration | Approve | |
Unity System Compositor Development Team | Pending | ||
Review via email: mp+272394@code.launchpad.net |
Commit message
Release 0.1.3
Description of the change
Release 0.1.3
To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : | # |
review:
Approve
(continuous-integration)
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'debian/changelog' |
2 | --- debian/changelog 2015-09-22 16:44:54 +0000 |
3 | +++ debian/changelog 2015-09-25 14:03:36 +0000 |
4 | @@ -1,6 +1,19 @@ |
5 | -unity-system-compositor (0.1.2+15.10.20150922-0ubuntu1) wily; urgency=medium |
6 | - |
7 | - [ Cemil Azizoglu ] |
8 | +<<<<<<< TREE |
9 | +unity-system-compositor (0.1.2+15.10.20150922-0ubuntu1) wily; urgency=medium |
10 | + |
11 | + [ Cemil Azizoglu ] |
12 | +======= |
13 | +unity-system-compositor (0.1.3+15.10.20150925-0ubuntu1) UNRELEASED; urgency=medium |
14 | + |
15 | + * Fix "unresponsive shell including power button doesn't blank/unblank |
16 | + display" (LP: #1491566) |
17 | + |
18 | + -- Alexandros Frantzis <alexandros.frantzis@canonical.com> Fri, 25 Sep 2015 16:53:27 +0300 |
19 | + |
20 | +unity-system-compositor (0.1.2+15.10.20150922-0ubuntu1) wily; urgency=medium |
21 | + |
22 | + [ Cemil Azizoglu ] |
23 | +>>>>>>> MERGE-SOURCE |
24 | * Rebuild for Mir 0.16 |
25 | |
26 | [ CI Train Bot ] |
27 | |
28 | === modified file 'src/mir_screen.cpp' |
29 | --- src/mir_screen.cpp 2015-08-24 18:14:36 +0000 |
30 | +++ src/mir_screen.cpp 2015-09-25 14:03:36 +0000 |
31 | @@ -18,6 +18,7 @@ |
32 | #include "clock.h" |
33 | |
34 | #include <mir/main_loop.h> |
35 | +#include <mir/lockable_callback.h> |
36 | #include <mir/time/alarm_factory.h> |
37 | #include <mir/compositor/compositor.h> |
38 | #include <mir/graphics/display.h> |
39 | @@ -32,6 +33,50 @@ |
40 | namespace mi = mir::input; |
41 | namespace mg = mir::graphics; |
42 | |
43 | +class usc::MirScreen::LockableCallback : public mir::LockableCallback |
44 | +{ |
45 | +public: |
46 | + LockableCallback(MirScreen* mir_screen) |
47 | + : mir_screen{mir_screen} |
48 | + { |
49 | + } |
50 | + |
51 | + void lock() override |
52 | + { |
53 | + guard_lock = std::unique_lock<std::mutex>{mir_screen->guard}; |
54 | + } |
55 | + |
56 | + void unlock() override |
57 | + { |
58 | + if (guard_lock.owns_lock()) |
59 | + guard_lock.unlock(); |
60 | + } |
61 | + |
62 | +protected: |
63 | + MirScreen* const mir_screen; |
64 | + std::unique_lock<std::mutex> guard_lock; |
65 | +}; |
66 | + |
67 | +class usc::MirScreen::PowerOffLockableCallback : public usc::MirScreen::LockableCallback |
68 | +{ |
69 | + using usc::MirScreen::LockableCallback::LockableCallback; |
70 | + |
71 | + void operator()() override |
72 | + { |
73 | + mir_screen->power_off_alarm_notification(); |
74 | + } |
75 | +}; |
76 | + |
77 | +class usc::MirScreen::DimmerLockableCallback : public usc::MirScreen::LockableCallback |
78 | +{ |
79 | + using usc::MirScreen::LockableCallback::LockableCallback; |
80 | + |
81 | + void operator()() override |
82 | + { |
83 | + mir_screen->dimmer_alarm_notification(); |
84 | + } |
85 | +}; |
86 | + |
87 | usc::MirScreen::MirScreen( |
88 | std::shared_ptr<usc::ScreenHardware> const& screen_hardware, |
89 | std::shared_ptr<mir::compositor::Compositor> const& compositor, |
90 | @@ -48,9 +93,9 @@ |
91 | alarm_factory{alarm_factory}, |
92 | clock{clock}, |
93 | power_off_alarm{alarm_factory->create_alarm( |
94 | - std::bind(&usc::MirScreen::power_off_alarm_notification, this))}, |
95 | + std::make_shared<PowerOffLockableCallback>(this))}, |
96 | dimmer_alarm{alarm_factory->create_alarm( |
97 | - std::bind(&usc::MirScreen::dimmer_alarm_notification, this))}, |
98 | + std::make_shared<DimmerLockableCallback>(this))}, |
99 | inactivity_timeouts(inactivity_timeouts), |
100 | notification_timeouts(notification_timeouts), |
101 | current_power_mode{MirPowerMode::mir_power_mode_on}, |
102 | @@ -313,14 +358,12 @@ |
103 | |
104 | void usc::MirScreen::power_off_alarm_notification() |
105 | { |
106 | - std::lock_guard<std::mutex> lock{guard}; |
107 | configure_display_l(MirPowerMode::mir_power_mode_off, PowerStateChangeReason::inactivity); |
108 | next_power_off = {}; |
109 | } |
110 | |
111 | void usc::MirScreen::dimmer_alarm_notification() |
112 | { |
113 | - std::lock_guard<std::mutex> lock{guard}; |
114 | screen_hardware->set_dim_backlight(); |
115 | next_dimming = {}; |
116 | } |
117 | |
118 | === modified file 'src/mir_screen.h' |
119 | --- src/mir_screen.h 2015-07-17 12:43:46 +0000 |
120 | +++ src/mir_screen.h 2015-09-25 14:03:36 +0000 |
121 | @@ -73,7 +73,16 @@ |
122 | void register_power_state_change_handler( |
123 | PowerStateChangeHandler const& power_state_change_handler) override; |
124 | |
125 | +protected: |
126 | + // These are protected virtual because we need to override them in tests |
127 | + virtual void power_off_alarm_notification(); |
128 | + virtual void dimmer_alarm_notification(); |
129 | + |
130 | private: |
131 | + class LockableCallback; |
132 | + class PowerOffLockableCallback; |
133 | + class DimmerLockableCallback; |
134 | + |
135 | void set_screen_power_mode_l(MirPowerMode mode, PowerStateChangeReason reason); |
136 | void configure_display_l(MirPowerMode mode, PowerStateChangeReason reason); |
137 | |
138 | @@ -84,8 +93,6 @@ |
139 | Timeouts timeouts_for(PowerStateChangeReason reason); |
140 | bool is_screen_change_allowed(MirPowerMode mode, PowerStateChangeReason reason); |
141 | |
142 | - void power_off_alarm_notification(); |
143 | - void dimmer_alarm_notification(); |
144 | void long_press_alarm_notification(); |
145 | |
146 | std::shared_ptr<usc::ScreenHardware> const screen_hardware; |
147 | |
148 | === modified file 'tests/integration-tests/CMakeLists.txt' |
149 | --- tests/integration-tests/CMakeLists.txt 2015-08-26 08:00:27 +0000 |
150 | +++ tests/integration-tests/CMakeLists.txt 2015-09-25 14:03:36 +0000 |
151 | @@ -38,6 +38,7 @@ |
152 | test_unity_input_service.cpp |
153 | test_external_spinner.cpp |
154 | test_powerd_mediator.cpp |
155 | + test_deadlock_lp1491566.cpp |
156 | ) |
157 | |
158 | target_link_libraries( |
159 | |
160 | === added file 'tests/integration-tests/test_deadlock_lp1491566.cpp' |
161 | --- tests/integration-tests/test_deadlock_lp1491566.cpp 1970-01-01 00:00:00 +0000 |
162 | +++ tests/integration-tests/test_deadlock_lp1491566.cpp 2015-09-25 14:03:36 +0000 |
163 | @@ -0,0 +1,283 @@ |
164 | +/* |
165 | + * Copyright © 2015 Canonical Ltd. |
166 | + * |
167 | + * This program is free software: you can redistribute it and/or modify |
168 | + * it under the terms of the GNU General Public License version 3 as |
169 | + * published by the Free Software Foundation. |
170 | + * |
171 | + * This program is distributed in the hope that it will be useful, |
172 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
173 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
174 | + * GNU General Public License for more details. |
175 | + * |
176 | + * You should have received a copy of the GNU General Public License |
177 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
178 | + * |
179 | + * Authored by: Alexandros Frantzis <alexandros.frantzis@canonical.com> |
180 | + */ |
181 | + |
182 | +#include "src/server.h" |
183 | +#include "src/mir_screen.h" |
184 | +#include "src/screen_hardware.h" |
185 | +#include "src/power_state_change_reason.h" |
186 | +#include "spin_wait.h" |
187 | + |
188 | +#include <mir/compositor/compositor.h> |
189 | +#include <mir/main_loop.h> |
190 | +#include <mir/graphics/display.h> |
191 | +#include <mir/graphics/display_configuration.h> |
192 | +#include <mir/graphics/gl_context.h> |
193 | +#include <mir/input/touch_visualizer.h> |
194 | + |
195 | +#include <gtest/gtest.h> |
196 | +#include <gmock/gmock.h> |
197 | + |
198 | +#include <thread> |
199 | +#include <future> |
200 | + |
201 | +namespace mg = mir::graphics; |
202 | + |
203 | +namespace |
204 | +{ |
205 | + |
206 | +struct NullCompositor : mir::compositor::Compositor |
207 | +{ |
208 | + void start() override {} |
209 | + void stop() override {} |
210 | +}; |
211 | + |
212 | +struct StubDisplayConfiguration : mg::DisplayConfiguration |
213 | +{ |
214 | + StubDisplayConfiguration() |
215 | + { |
216 | + conf_output.power_mode = MirPowerMode::mir_power_mode_on; |
217 | + } |
218 | + |
219 | + void for_each_card(std::function<void(mg::DisplayConfigurationCard const&)> f) const override |
220 | + { |
221 | + } |
222 | + |
223 | + void for_each_output(std::function<void(mg::DisplayConfigurationOutput const&)> f) const override |
224 | + { |
225 | + f(conf_output); |
226 | + } |
227 | + |
228 | + void for_each_output(std::function<void(mg::UserDisplayConfigurationOutput&)> f) |
229 | + { |
230 | + mg::UserDisplayConfigurationOutput user{conf_output}; |
231 | + f(user); |
232 | + } |
233 | + |
234 | + mg::DisplayConfigurationOutput conf_output; |
235 | +}; |
236 | + |
237 | +struct StubDisplay : mg::Display |
238 | +{ |
239 | + void for_each_display_sync_group(std::function<void(mg::DisplaySyncGroup&)> const& f) override |
240 | + { |
241 | + } |
242 | + |
243 | + std::unique_ptr<mg::DisplayConfiguration> configuration() const override |
244 | + { |
245 | + return std::unique_ptr<mg::DisplayConfiguration>{new StubDisplayConfiguration{}}; |
246 | + } |
247 | + |
248 | + void configure(mg::DisplayConfiguration const&) override {} |
249 | + |
250 | + void register_configuration_change_handler( |
251 | + mg::EventHandlerRegister& , |
252 | + mg::DisplayConfigurationChangeHandler const& ) override |
253 | + { |
254 | + } |
255 | + |
256 | + void register_pause_resume_handlers( |
257 | + mg::EventHandlerRegister&, |
258 | + mg::DisplayPauseHandler const&, |
259 | + mg::DisplayResumeHandler const&) override |
260 | + { |
261 | + } |
262 | + |
263 | + void pause() override {} |
264 | + void resume() override {} |
265 | + |
266 | + std::shared_ptr<mg::Cursor> create_hardware_cursor( |
267 | + std::shared_ptr<mg::CursorImage> const&) override |
268 | + { |
269 | + return{}; |
270 | + } |
271 | + |
272 | + std::unique_ptr<mg::GLContext> create_gl_context() override |
273 | + { |
274 | + return std::unique_ptr<mg::GLContext>{}; |
275 | + } |
276 | +}; |
277 | + |
278 | +struct StubScreenHardware : usc::ScreenHardware |
279 | +{ |
280 | + void set_dim_backlight() override {} |
281 | + void set_normal_backlight() override {} |
282 | + void turn_off_backlight() override {} |
283 | + |
284 | + void change_backlight_values(int dim_brightness, int normal_brightness) override {} |
285 | + |
286 | + void allow_suspend() override {} |
287 | + void disable_suspend() override {} |
288 | + |
289 | + void enable_auto_brightness(bool) override {} |
290 | + bool auto_brightness_supported() override { return true; } |
291 | + void set_brightness(int) override {} |
292 | + int min_brightness() override { return 100; } |
293 | + int max_brightness() override { return 0; } |
294 | + |
295 | + void enable_proximity(bool) override { } |
296 | +}; |
297 | + |
298 | +struct NullTouchVisualizer : mir::input::TouchVisualizer |
299 | +{ |
300 | + void enable() override {} |
301 | + void disable() override {} |
302 | + void visualize_touches(std::vector<Spot> const& touches) override {} |
303 | +}; |
304 | + |
305 | +class TestMirScreen : public usc::MirScreen |
306 | +{ |
307 | +public: |
308 | + using usc::MirScreen::MirScreen; |
309 | + |
310 | + void dimmer_alarm_notification() override |
311 | + { |
312 | + before_dimmer_alarm_func(); |
313 | + usc::MirScreen::dimmer_alarm_notification(); |
314 | + } |
315 | + |
316 | + void power_off_alarm_notification() override |
317 | + { |
318 | + before_power_off_alarm_func(); |
319 | + usc::MirScreen::power_off_alarm_notification(); |
320 | + } |
321 | + |
322 | + std::function<void()> before_dimmer_alarm_func = []{}; |
323 | + std::function<void()> before_power_off_alarm_func = []{}; |
324 | +}; |
325 | + |
326 | +struct DeadlockLP1491566 : public testing::Test |
327 | +{ |
328 | + DeadlockLP1491566() |
329 | + { |
330 | + main_loop_thread = std::thread{[this] { main_loop->run(); }}; |
331 | + } |
332 | + |
333 | + ~DeadlockLP1491566() |
334 | + { |
335 | + main_loop->stop(); |
336 | + main_loop_thread.join(); |
337 | + } |
338 | + |
339 | + std::future<void> async_set_screen_power_mode() |
340 | + { |
341 | + return std::async( |
342 | + std::launch::async, |
343 | + [this] |
344 | + { |
345 | + mir_screen.set_screen_power_mode( |
346 | + MirPowerMode::mir_power_mode_on, |
347 | + PowerStateChangeReason::power_key); |
348 | + }); |
349 | + } |
350 | + |
351 | + void schedule_inactivity_handlers() |
352 | + { |
353 | + // We set the screen power mode to on, which will |
354 | + // schedule inactivity handlers |
355 | + mir_screen.set_screen_power_mode( |
356 | + MirPowerMode::mir_power_mode_on, |
357 | + PowerStateChangeReason::power_key); |
358 | + } |
359 | + |
360 | + void wait_for_async_operation(std::future<void>& future) |
361 | + { |
362 | + if (!usc::test::spin_wait_for_condition_or_timeout( |
363 | + [&future] { return future.valid(); }, |
364 | + std::chrono::seconds{3})) |
365 | + { |
366 | + throw std::runtime_error{"Future is not valid!"}; |
367 | + } |
368 | + |
369 | + if (future.wait_for(std::chrono::seconds{3}) != std::future_status::ready) |
370 | + { |
371 | + std::cerr << "Deadlock detected. Aborting." << std::endl; |
372 | + abort(); |
373 | + } |
374 | + } |
375 | + |
376 | + char *argv[1] = {nullptr}; |
377 | + usc::Server server{0, argv}; |
378 | + std::shared_ptr<mir::MainLoop> const main_loop{server.the_main_loop()}; |
379 | + std::chrono::milliseconds const power_off_timeout{200}; |
380 | + std::chrono::milliseconds const dimmer_timeout{100}; |
381 | + |
382 | + TestMirScreen mir_screen{ |
383 | + std::make_shared<StubScreenHardware>(), |
384 | + std::make_shared<NullCompositor>(), |
385 | + std::make_shared<StubDisplay>(), |
386 | + std::make_shared<NullTouchVisualizer>(), |
387 | + main_loop, |
388 | + server.the_clock(), |
389 | + {power_off_timeout, dimmer_timeout}, |
390 | + {power_off_timeout, dimmer_timeout}}; |
391 | + |
392 | + std::thread main_loop_thread; |
393 | +}; |
394 | + |
395 | +} |
396 | + |
397 | +// The following tests reproduce the situation we are seeing in bug 1491566, |
398 | +// where a set_screen_power_mode request tries to run concurrently with either |
399 | +// the dimmer or power-off timeout handlers. The deadlock is caused by two |
400 | +// threads trying to acquire the internal alarm lock and the MirScreen lock in |
401 | +// opposite orders. |
402 | +// |
403 | +// To reproduce the race in these tests, we need to run the |
404 | +// set_screen_power_mode request just before the timeout handlers are invoked, |
405 | +// while the thread invoking the timeout handlers holds the internal alarm |
406 | +// lock, but before it has acquired the MirScreen lock. The thread calling |
407 | +// set_screen_power_mode will then first acquire the MirScreen lock and then |
408 | +// try to acquire the internal alarm clock and block. The timeout handler |
409 | +// thread will eventually resume and try to get the MirScreen lock, leading to |
410 | +// a deadlock. |
411 | + |
412 | +TEST_F(DeadlockLP1491566, between_dimmer_handler_and_screen_power_mode_request_is_averted) |
413 | +{ |
414 | + std::future<void> future; |
415 | + |
416 | + mir_screen.before_dimmer_alarm_func = |
417 | + [this, &future] |
418 | + { |
419 | + future = async_set_screen_power_mode(); |
420 | + // Wait a bit for async operation to get processed |
421 | + std::this_thread::sleep_for( |
422 | + std::chrono::milliseconds{500}); |
423 | + }; |
424 | + |
425 | + schedule_inactivity_handlers(); |
426 | + |
427 | + wait_for_async_operation(future); |
428 | +} |
429 | + |
430 | +TEST_F(DeadlockLP1491566, between_power_off_handler_and_screen_power_mode_request_is_averted) |
431 | +{ |
432 | + std::future<void> future; |
433 | + |
434 | + mir_screen.before_power_off_alarm_func = |
435 | + [this, &future] |
436 | + { |
437 | + future = async_set_screen_power_mode(); |
438 | + // Wait a bit for async operation to get processed |
439 | + std::this_thread::sleep_for( |
440 | + std::chrono::milliseconds{500}); |
441 | + }; |
442 | + |
443 | + schedule_inactivity_handlers(); |
444 | + |
445 | + wait_for_async_operation(future); |
446 | +} |
447 | |
448 | === modified file 'tests/unit-tests/advanceable_timer.cpp' |
449 | --- tests/unit-tests/advanceable_timer.cpp 2015-07-15 13:48:30 +0000 |
450 | +++ tests/unit-tests/advanceable_timer.cpp 2015-09-25 14:03:36 +0000 |
451 | @@ -17,6 +17,7 @@ |
452 | */ |
453 | |
454 | #include "advanceable_timer.h" |
455 | +#include <mir/lockable_callback.h> |
456 | #include <algorithm> |
457 | |
458 | namespace |
459 | @@ -59,7 +60,7 @@ |
460 | { |
461 | AdvanceableAlarm( |
462 | mir::time::Timestamp now, |
463 | - std::function<void(void)> const& callback) |
464 | + std::shared_ptr<mir::LockableCallback> const& callback) |
465 | : now{now}, callback{callback} |
466 | { |
467 | } |
468 | @@ -101,7 +102,9 @@ |
469 | { |
470 | state_ = mir::time::Alarm::triggered; |
471 | lock.unlock(); |
472 | - callback(); |
473 | + callback->lock(); |
474 | + (*callback)(); |
475 | + callback->unlock(); |
476 | } |
477 | } |
478 | |
479 | @@ -113,7 +116,7 @@ |
480 | |
481 | private: |
482 | mir::time::Timestamp now; |
483 | - std::function<void()> const callback; |
484 | + std::shared_ptr<mir::LockableCallback> const callback; |
485 | mir::time::Timestamp next_trigger_; |
486 | mutable std::mutex mutex; |
487 | mir::time::Alarm::State state_ = mir::time::Alarm::triggered; |
488 | @@ -123,6 +126,26 @@ |
489 | std::unique_ptr<mir::time::Alarm> AdvanceableTimer::create_alarm( |
490 | std::function<void()> const& callback) |
491 | { |
492 | + struct SimpleLockableCallback : public mir::LockableCallback |
493 | + { |
494 | + SimpleLockableCallback(std::function<void()> const& callback) |
495 | + : callback{callback} |
496 | + { |
497 | + } |
498 | + |
499 | + void operator()() override { callback(); } |
500 | + void lock() override {} |
501 | + void unlock() override {} |
502 | + |
503 | + std::function<void()> const callback; |
504 | + }; |
505 | + |
506 | + return create_alarm(std::make_shared<SimpleLockableCallback>(callback)); |
507 | +} |
508 | + |
509 | +std::unique_ptr<mir::time::Alarm> AdvanceableTimer::create_alarm( |
510 | + std::shared_ptr<mir::LockableCallback> const& callback) |
511 | +{ |
512 | auto const adv_alarm = |
513 | std::make_shared<detail::AdvanceableAlarm>(now(), callback); |
514 | |
515 | @@ -131,12 +154,6 @@ |
516 | return std::unique_ptr<AlarmWrapper>(new AlarmWrapper{adv_alarm}); |
517 | } |
518 | |
519 | -std::unique_ptr<mir::time::Alarm> AdvanceableTimer::create_alarm( |
520 | - std::shared_ptr<mir::LockableCallback> const&) |
521 | -{ |
522 | - throw std::runtime_error("Not implemented"); |
523 | -} |
524 | - |
525 | void AdvanceableTimer::advance_by(std::chrono::milliseconds advance) |
526 | { |
527 | { |
PASSED: Continuous integration, rev:256 jenkins. qa.ubuntu. com/job/ unity-system- compositor- ubuntu- ci/27/ jenkins. qa.ubuntu. com/job/ unity-system- compositor- ubuntu- wily-amd64- ci/25 jenkins. qa.ubuntu. com/job/ unity-system- compositor- ubuntu- wily-armhf- ci/25
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild: s-jenkins. ubuntu- ci:8080/ job/unity- system- compositor- ubuntu- ci/27/rebuild
http://