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
=== modified file 'src/server/compositor/buffer_queue.cpp'
--- src/server/compositor/buffer_queue.cpp 2014-05-15 03:53:45 +0000
+++ src/server/compositor/buffer_queue.cpp 2014-05-19 07:45:18 +0000
@@ -239,13 +239,29 @@
239 if (contains(buffer.get(), buffers_sent_to_compositor))239 if (contains(buffer.get(), buffers_sent_to_compositor))
240 return;240 return;
241241
242 if (nbuffers <= 1)
243 return;
244
242 /*245 /*
243 * This buffer is not owned by compositor anymore. If the queue is supposed246 * We can't release the current_compositor_buffer because we need to keep
244 * to only own a single buffer (nbuffers == 1), then this is a buffer that247 * a compositor buffer always-available. But there might be a new
245 * is no longer used (i.e. replaced by a new resized buffer), so just248 * compositor buffer available to take its place immediately. Moving to
246 * discard it.249 * that one immediately will free up the old compositor buffer, allowing
250 * us to call back the client with a buffer where otherwise we couldn't.
247 */251 */
248 if (current_compositor_buffer != buffer.get() && nbuffers > 1)252 if (current_compositor_buffer == buffer.get() &&
253 !ready_to_composite_queue.empty())
254 {
255 current_compositor_buffer = pop(ready_to_composite_queue);
256
257 // Ensure current_compositor_buffer gets reused by the next
258 // compositor_acquire:
259 current_buffer_users.clear();
260 void const* const impossible_user_id = this;
261 current_buffer_users.push_back(impossible_user_id);
262 }
263
264 if (current_compositor_buffer != buffer.get())
249 release(buffer.get(), std::move(lock));265 release(buffer.get(), std::move(lock));
250}266}
251267
252268
=== modified file 'tests/unit-tests/compositor/test_buffer_queue.cpp'
--- tests/unit-tests/compositor/test_buffer_queue.cpp 2014-05-15 03:20:25 +0000
+++ tests/unit-tests/compositor/test_buffer_queue.cpp 2014-05-19 07:45:18 +0000
@@ -1068,6 +1068,68 @@
1068 q.compositor_release(buf);1068 q.compositor_release(buf);
1069}1069}
10701070
1071TEST_F(BufferQueueTest, double_buffered_client_is_not_blocked_prematurely)
1072{ // Regression test for LP: #1319765
1073 using namespace testing;
1074
1075 mc::BufferQueue q{2, allocator, basic_properties};
1076
1077 q.client_release(client_acquire_sync(q));
1078 auto a = q.compositor_acquire(this);
1079 q.client_release(client_acquire_sync(q));
1080 auto b = q.compositor_acquire(this);
1081
1082 ASSERT_NE(a.get(), b.get());
1083
1084 q.compositor_release(a);
1085 q.client_release(client_acquire_sync(q));
1086
1087 q.compositor_release(b);
1088 auto handle = client_acquire_async(q);
1089 // With the fix, a buffer will be available instantaneously:
1090 ASSERT_TRUE(handle->has_acquired_buffer());
1091 handle->release_buffer();
1092}
1093
1094TEST_F(BufferQueueTest, composite_on_demand_never_deadlocks_with_2_buffers)
1095{ // Extended regression test for LP: #1319765
1096 using namespace testing;
1097
1098 mc::BufferQueue q{2, allocator, basic_properties};
1099
1100 for (int i = 0; i < 100; ++i)
1101 {
1102 auto x = client_acquire_async(q);
1103 ASSERT_TRUE(x->has_acquired_buffer());
1104 x->release_buffer();
1105
1106 auto a = q.compositor_acquire(this);
1107
1108 auto y = client_acquire_async(q);
1109 ASSERT_TRUE(y->has_acquired_buffer());
1110 y->release_buffer();
1111
1112 auto b = q.compositor_acquire(this);
1113
1114 ASSERT_NE(a.get(), b.get());
1115
1116 q.compositor_release(a);
1117
1118 auto w = client_acquire_async(q);
1119 ASSERT_TRUE(w->has_acquired_buffer());
1120 w->release_buffer();
1121
1122 q.compositor_release(b);
1123
1124 auto z = client_acquire_async(q);
1125 ASSERT_TRUE(z->has_acquired_buffer());
1126 z->release_buffer();
1127
1128 q.compositor_release(q.compositor_acquire(this));
1129 q.compositor_release(q.compositor_acquire(this));
1130 }
1131}
1132
1071/* Regression test for LP: #1306464 */1133/* Regression test for LP: #1306464 */
1072TEST_F(BufferQueueTest, framedropping_client_acquire_does_not_block_when_no_available_buffers)1134TEST_F(BufferQueueTest, framedropping_client_acquire_does_not_block_when_no_available_buffers)
1073{1135{

Subscribers

People subscribed via source and target branches