Mir

Merge lp:~vanvugt/mir/fix-1319765 into lp:mir

Proposed by Daniel van Vugt
Status: Merged
Approved by: Daniel van Vugt
Approved revision: no longer in the source branch.
Merged at revision: 1641
Proposed branch: lp:~vanvugt/mir/fix-1319765
Merge into: lp:mir
Diff against target: 111 lines (+83/-5)
2 files modified
src/server/compositor/buffer_queue.cpp (+21/-5)
tests/unit-tests/compositor/test_buffer_queue.cpp (+62/-0)
To merge this branch: bzr merge lp:~vanvugt/mir/fix-1319765
Reviewer Review Type Date Requested Status
Kevin DuBois (community) Approve
Alberto Aguirre (community) Approve
PS Jenkins bot (community) continuous-integration Approve
Review via email: mp+219806@code.launchpad.net

Commit message

Fix deadlocked (frozen) clients when nbuffers==2 (LP: #1319765)

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Alberto Aguirre (albaguirre) wrote :

Indeed.

review: Approve
Revision history for this message
Kevin DuBois (kdub) wrote :

looks good, and what the code is accomplishing makes sense to me. Suggestion and a question:

composite_on_demand_never_deadlocks_with_2_buffers is a short test to run, but wouldn't the same lines be hit if we just ran once or twice? Its hard as someone looking at the code for the first time to tease out what the expectations are.

Could having a smarter callback system also avert the problem? (I think the composition scheduling system has some improvements that are needed, curious if the root cause is related)

review: Approve
Revision history for this message
Daniel van Vugt (vanvugt) wrote :

kdub:

Yeah it's a complicated (and redundant) test that is mostly just a repeatable copy of the simple test before it. I wanted to iterate it many times to verify the fix didn't just work on the first iteration, and stress it a bit.

Not sure what you mean by "smarter callback system". This proposal ensures all callbacks are made as soon as logically possible (catching the one(?) case where that wasn't already guaranteed). Although I suspect you might be referring to an automatic callback system where callbacks happen implicitly from queue changes...? That would be interesting if it simplified the algorithm (not interesting otherwise :). But that's also not a task for right now.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/server/compositor/buffer_queue.cpp'
2--- src/server/compositor/buffer_queue.cpp 2014-05-15 03:53:45 +0000
3+++ src/server/compositor/buffer_queue.cpp 2014-05-19 07:45:18 +0000
4@@ -239,13 +239,29 @@
5 if (contains(buffer.get(), buffers_sent_to_compositor))
6 return;
7
8+ if (nbuffers <= 1)
9+ return;
10+
11 /*
12- * This buffer is not owned by compositor anymore. If the queue is supposed
13- * to only own a single buffer (nbuffers == 1), then this is a buffer that
14- * is no longer used (i.e. replaced by a new resized buffer), so just
15- * discard it.
16+ * We can't release the current_compositor_buffer because we need to keep
17+ * a compositor buffer always-available. But there might be a new
18+ * compositor buffer available to take its place immediately. Moving to
19+ * that one immediately will free up the old compositor buffer, allowing
20+ * us to call back the client with a buffer where otherwise we couldn't.
21 */
22- if (current_compositor_buffer != buffer.get() && nbuffers > 1)
23+ if (current_compositor_buffer == buffer.get() &&
24+ !ready_to_composite_queue.empty())
25+ {
26+ current_compositor_buffer = pop(ready_to_composite_queue);
27+
28+ // Ensure current_compositor_buffer gets reused by the next
29+ // compositor_acquire:
30+ current_buffer_users.clear();
31+ void const* const impossible_user_id = this;
32+ current_buffer_users.push_back(impossible_user_id);
33+ }
34+
35+ if (current_compositor_buffer != buffer.get())
36 release(buffer.get(), std::move(lock));
37 }
38
39
40=== modified file 'tests/unit-tests/compositor/test_buffer_queue.cpp'
41--- tests/unit-tests/compositor/test_buffer_queue.cpp 2014-05-15 03:20:25 +0000
42+++ tests/unit-tests/compositor/test_buffer_queue.cpp 2014-05-19 07:45:18 +0000
43@@ -1068,6 +1068,68 @@
44 q.compositor_release(buf);
45 }
46
47+TEST_F(BufferQueueTest, double_buffered_client_is_not_blocked_prematurely)
48+{ // Regression test for LP: #1319765
49+ using namespace testing;
50+
51+ mc::BufferQueue q{2, allocator, basic_properties};
52+
53+ q.client_release(client_acquire_sync(q));
54+ auto a = q.compositor_acquire(this);
55+ q.client_release(client_acquire_sync(q));
56+ auto b = q.compositor_acquire(this);
57+
58+ ASSERT_NE(a.get(), b.get());
59+
60+ q.compositor_release(a);
61+ q.client_release(client_acquire_sync(q));
62+
63+ q.compositor_release(b);
64+ auto handle = client_acquire_async(q);
65+ // With the fix, a buffer will be available instantaneously:
66+ ASSERT_TRUE(handle->has_acquired_buffer());
67+ handle->release_buffer();
68+}
69+
70+TEST_F(BufferQueueTest, composite_on_demand_never_deadlocks_with_2_buffers)
71+{ // Extended regression test for LP: #1319765
72+ using namespace testing;
73+
74+ mc::BufferQueue q{2, allocator, basic_properties};
75+
76+ for (int i = 0; i < 100; ++i)
77+ {
78+ auto x = client_acquire_async(q);
79+ ASSERT_TRUE(x->has_acquired_buffer());
80+ x->release_buffer();
81+
82+ auto a = q.compositor_acquire(this);
83+
84+ auto y = client_acquire_async(q);
85+ ASSERT_TRUE(y->has_acquired_buffer());
86+ y->release_buffer();
87+
88+ auto b = q.compositor_acquire(this);
89+
90+ ASSERT_NE(a.get(), b.get());
91+
92+ q.compositor_release(a);
93+
94+ auto w = client_acquire_async(q);
95+ ASSERT_TRUE(w->has_acquired_buffer());
96+ w->release_buffer();
97+
98+ q.compositor_release(b);
99+
100+ auto z = client_acquire_async(q);
101+ ASSERT_TRUE(z->has_acquired_buffer());
102+ z->release_buffer();
103+
104+ q.compositor_release(q.compositor_acquire(this));
105+ q.compositor_release(q.compositor_acquire(this));
106+ }
107+}
108+
109 /* Regression test for LP: #1306464 */
110 TEST_F(BufferQueueTest, framedropping_client_acquire_does_not_block_when_no_available_buffers)
111 {

Subscribers

People subscribed via source and target branches