Mir

Merge lp:~vanvugt/mir/fix-1339700-both-0.4 into lp:mir/0.4

Proposed by Daniel van Vugt
Status: Merged
Approved by: Daniel van Vugt
Approved revision: no longer in the source branch.
Merged at revision: 1743
Proposed branch: lp:~vanvugt/mir/fix-1339700-both-0.4
Merge into: lp:mir/0.4
Diff against target: 192 lines (+90/-7)
5 files modified
debian/changelog (+7/-0)
src/server/asio_main_loop.cpp (+27/-3)
src/server/compositor/buffer_queue.h (+4/-1)
src/server/compositor/timeout_frame_dropping_policy_factory.cpp (+6/-3)
tests/unit-tests/test_asio_main_loop.cpp (+46/-0)
To merge this branch: bzr merge lp:~vanvugt/mir/fix-1339700-both-0.4
Reviewer Review Type Date Requested Status
Alexandros Frantzis (community) Approve
Cemil Azizoglu (community) Approve
Review via email: mp+226629@code.launchpad.net

Commit message

Fix two potential deadlocks that could lead to the display freezing.
(LP: #1339700)

This is the combination of both fixes that have been approved upstream
for LP: #1339700.

To post a comment you must log in.
Revision history for this message
Cemil Azizoglu (cemil-azizoglu) wrote :

LGTM

review: Approve
Revision history for this message
Alexandros Frantzis (afrantzis) wrote :

Looks good.

review: Approve

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 2014-07-04 07:37:55 +0000
3+++ debian/changelog 2014-07-14 06:16:57 +0000
4@@ -1,3 +1,10 @@
5+mir (0.4.1-0ubuntu1) UNRELEASED; urgency=medium
6+
7+ * Bug fix release 0.4.1 (https://launchpad.net/mir/+milestone/0.4.1) fixes:
8+ - [regression] Device locks randomly on welcome screen (LP: #1339700)
9+
10+ -- Daniel van Vugt <daniel.van.vugt@canonical.com> Mon, 14 Jul 2014 14:10:21 +0800
11+
12 mir (0.4.0+14.10.20140701.1-0ubuntu1) utopic; urgency=medium
13
14 * New upstream release 0.4.0 (https://launchpad.net/mir/+milestone/0.4.0)
15
16=== modified file 'src/server/asio_main_loop.cpp'
17--- src/server/asio_main_loop.cpp 2014-06-27 07:07:35 +0000
18+++ src/server/asio_main_loop.cpp 2014-07-14 06:16:57 +0000
19@@ -344,15 +344,19 @@
20 bool reschedule_in(std::chrono::milliseconds delay) override;
21 bool reschedule_for(mir::time::Timestamp time_point) override;
22 private:
23+ void stop();
24+ bool cancel_unlocked();
25 void update_timer();
26 struct InternalState
27 {
28 explicit InternalState(std::function<void(void)> callback)
29- : callback{callback}
30+ : callback{callback}, state{pending}
31 {
32 }
33
34- std::recursive_mutex m;
35+ std::mutex m;
36+ int callbacks_running = 0;
37+ std::condition_variable callback_done;
38 std::function<void(void)> const callback;
39 State state;
40 };
41@@ -381,7 +385,12 @@
42 if (data->state == mir::time::Alarm::pending)
43 {
44 data->state = mir::time::Alarm::triggered;
45+ ++data->callbacks_running;
46+ lock.unlock();
47 data->callback();
48+ lock.lock();
49+ --data->callbacks_running;
50+ data->callback_done.notify_all();
51 }
52 }
53 }
54@@ -415,12 +424,27 @@
55
56 AlarmImpl::~AlarmImpl() noexcept
57 {
58- AlarmImpl::cancel();
59+ AlarmImpl::stop();
60+}
61+
62+void AlarmImpl::stop()
63+{
64+ std::unique_lock<decltype(data->m)> lock(data->m);
65+
66+ while (data->callbacks_running > 0)
67+ data->callback_done.wait(lock);
68+
69+ cancel_unlocked();
70 }
71
72 bool AlarmImpl::cancel()
73 {
74 std::lock_guard<decltype(data->m)> lock(data->m);
75+ return cancel_unlocked();
76+}
77+
78+bool AlarmImpl::cancel_unlocked()
79+{
80 if (data->state == triggered)
81 return false;
82
83
84=== modified file 'src/server/compositor/buffer_queue.h'
85--- src/server/compositor/buffer_queue.h 2014-06-12 15:35:08 +0000
86+++ src/server/compositor/buffer_queue.h 2014-07-14 06:16:57 +0000
87@@ -86,11 +86,14 @@
88
89 int nbuffers;
90 bool frame_dropping_enabled;
91- std::unique_ptr<FrameDroppingPolicy> framedrop_policy;
92 graphics::BufferProperties the_properties;
93
94 std::condition_variable snapshot_released;
95 std::shared_ptr<graphics::GraphicBufferAllocator> gralloc;
96+
97+ // Ensure framedrop_policy gets destroyed first so the callback installed
98+ // does not access dead objects.
99+ std::unique_ptr<FrameDroppingPolicy> framedrop_policy;
100 };
101
102 }
103
104=== modified file 'src/server/compositor/timeout_frame_dropping_policy_factory.cpp'
105--- src/server/compositor/timeout_frame_dropping_policy_factory.cpp 2014-06-25 16:30:46 +0000
106+++ src/server/compositor/timeout_frame_dropping_policy_factory.cpp 2014-07-14 06:16:57 +0000
107@@ -41,22 +41,25 @@
108
109 private:
110 std::chrono::milliseconds const timeout;
111+ std::atomic<unsigned int> pending_swaps;
112+
113+ // Ensure alarm gets destroyed first so its handler does not access dead
114+ // objects.
115 std::unique_ptr<mir::time::Alarm> const alarm;
116- std::atomic<unsigned int> pending_swaps;
117 };
118
119 TimeoutFrameDroppingPolicy::TimeoutFrameDroppingPolicy(std::shared_ptr<mir::time::Timer> const& timer,
120 std::chrono::milliseconds timeout,
121 std::function<void(void)> drop_frame)
122 : timeout{timeout},
123+ pending_swaps{0},
124 alarm{timer->create_alarm([this, drop_frame]
125 {
126 assert(pending_swaps.load() > 0);
127 drop_frame();
128 if (--pending_swaps > 0)
129 alarm->reschedule_in(this->timeout);
130- })},
131- pending_swaps{0}
132+ })}
133 {
134 }
135
136
137=== modified file 'tests/unit-tests/test_asio_main_loop.cpp'
138--- tests/unit-tests/test_asio_main_loop.cpp 2014-06-27 09:07:33 +0000
139+++ tests/unit-tests/test_asio_main_loop.cpp 2014-07-14 06:16:57 +0000
140@@ -631,6 +631,52 @@
141 EXPECT_EQ(1, call_count);
142 }
143
144+TEST_F(AsioMainLoopAlarmTest, alarm_callback_cannot_deadlock)
145+{ // Regression test for deadlock bug LP: #1339700
146+ std::mutex m;
147+ std::atomic_bool failed(false);
148+ int i = 0;
149+ int const loops = 5;
150+
151+ auto alarm = ml.notify_in(std::chrono::milliseconds{0}, [&]()
152+ {
153+ // From this angle, ensure we can lock m (alarm should be unlocked)
154+ int tries = 0;
155+ while (!m.try_lock() && tries < 100) // 100 x 100 = try for 10 seconds
156+ {
157+ ++tries;
158+ std::this_thread::sleep_for(std::chrono::milliseconds{100});
159+ }
160+ failed = (tries >= 100);
161+ ASSERT_FALSE(failed);
162+ ++i;
163+ m.unlock();
164+ });
165+
166+ std::thread t([&]()
167+ {
168+ m.lock();
169+ while (i < loops && !failed)
170+ {
171+ // From this angle, ensure we can lock alarm while holding m
172+ (void)alarm->state();
173+ m.unlock();
174+ std::this_thread::yield();
175+ m.lock();
176+ }
177+ m.unlock();
178+ });
179+
180+ UnblockMainLoop unblocker(ml);
181+ for (int j = 0; j < loops; ++j)
182+ {
183+ clock->advance_by(std::chrono::milliseconds{101}, ml);
184+ alarm->reschedule_in(std::chrono::milliseconds{100});
185+ }
186+
187+ t.join();
188+}
189+
190 TEST_F(AsioMainLoopAlarmTest, alarm_fires_at_correct_time_point)
191 {
192 mir::time::Timestamp real_soon = clock->sample() + std::chrono::milliseconds{120};

Subscribers

People subscribed via source and target branches