Mir

Merge lp:~afrantzis/mir/fix-1306464 into lp:mir

Proposed by Alexandros Frantzis
Status: Merged
Approved by: Alan Griffiths
Approved revision: no longer in the source branch.
Merged at revision: 1550
Proposed branch: lp:~afrantzis/mir/fix-1306464
Merge into: lp:mir
Diff against target: 153 lines (+85/-11)
3 files modified
include/test/mir_test/wait_condition.h (+11/-4)
src/server/compositor/switching_bundle.cpp (+17/-7)
tests/unit-tests/compositor/test_switching_bundle.cpp (+57/-0)
To merge this branch: bzr merge lp:~afrantzis/mir/fix-1306464
Reviewer Review Type Date Requested Status
Alan Griffiths Approve
Alberto Aguirre (community) Approve
PS Jenkins bot (community) continuous-integration Approve
Review via email: mp+215387@code.launchpad.net

Commit message

compositor: Don't block in SwitchingBundle::client_acquire() when a framedropping bundle has no free or ready buffers

Description of the change

compositor: Don't block in SwitchingBundle::client_acquire() when a framedropping bundle has no free or ready buffers

Fixes https://bugs.launchpad.net/mir/+bug/1306464 which cause intermittent CI failures.

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
Alberto Aguirre (albaguirre) wrote :

LGTM

review: Approve
Revision history for this message
Alan Griffiths (alan-griffiths) wrote :

Seems OK

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'include/test/mir_test/wait_condition.h'
2--- include/test/mir_test/wait_condition.h 2013-04-24 05:22:20 +0000
3+++ include/test/mir_test/wait_condition.h 2014-04-11 10:56:45 +0000
4@@ -31,24 +31,31 @@
5 {
6 struct WaitCondition
7 {
8- WaitCondition() : woken(false) {}
9+ WaitCondition() : woken_(false) {}
10
11 void wait_for_at_most_seconds(int seconds)
12 {
13 std::unique_lock<std::mutex> ul(guard);
14- if (!woken) condition.wait_for(ul, std::chrono::seconds(seconds));
15+ condition.wait_for(ul, std::chrono::seconds(seconds),
16+ [this] { return woken_; });
17 }
18
19 void wake_up_everyone()
20 {
21 std::unique_lock<std::mutex> ul(guard);
22- woken = true;
23+ woken_ = true;
24 condition.notify_all();
25 }
26
27+ bool woken()
28+ {
29+ std::unique_lock<std::mutex> ul(guard);
30+ return woken_;
31+ }
32+
33 std::mutex guard;
34 std::condition_variable condition;
35- bool woken;
36+ bool woken_;
37 };
38
39 ACTION_P(ReturnFalseAndWakeUp, wait_condition)
40
41=== modified file 'src/server/compositor/switching_bundle.cpp'
42--- src/server/compositor/switching_bundle.cpp 2014-03-26 05:48:59 +0000
43+++ src/server/compositor/switching_bundle.cpp 2014-04-11 10:56:45 +0000
44@@ -212,13 +212,12 @@
45
46 if ((framedropping || force_drop) && nbuffers > 1)
47 {
48- if (nfree() <= 0)
49- {
50- while (nready == 0)
51- cond.wait(lock);
52-
53- drop_frames(1);
54- }
55+ /*
56+ * If we don't have a free buffer to return or we cannot free a ready buffer
57+ * by dropping it, we would block in complete_client_acquire, so just return.
58+ */
59+ if (nfree() <= 0 && nready == 0)
60+ return;
61 }
62 else
63 {
64@@ -233,6 +232,17 @@
65 {
66 auto complete = std::move(client_acquire_todo);
67
68+ if ((framedropping || force_drop) && nbuffers > 1)
69+ {
70+ if (nfree() <= 0)
71+ {
72+ while (nready == 0)
73+ cond.wait(lock);
74+
75+ drop_frames(1);
76+ }
77+ }
78+
79 if (force_drop > 0)
80 force_drop--;
81
82
83=== modified file 'tests/unit-tests/compositor/test_switching_bundle.cpp'
84--- tests/unit-tests/compositor/test_switching_bundle.cpp 2014-03-26 05:48:59 +0000
85+++ tests/unit-tests/compositor/test_switching_bundle.cpp 2014-04-11 10:56:45 +0000
86@@ -19,6 +19,7 @@
87 #include "src/server/compositor/switching_bundle.h"
88 #include "mir_test_doubles/stub_buffer_allocator.h"
89 #include "mir_test_doubles/stub_buffer.h"
90+#include "mir_test/wait_condition.h"
91
92 #include <gtest/gtest.h>
93
94@@ -944,3 +945,59 @@
95 }
96 }
97 }
98+
99+TEST_F(SwitchingBundleTest, framedropping_client_acquire_does_not_block_when_no_available_buffers)
100+{
101+ /* Regression test for LP: #1306464 */
102+ using namespace testing;
103+
104+ int const nbuffers{3};
105+ mc::SwitchingBundle bundle{nbuffers, allocator, basic_properties};
106+
107+ bundle.allow_framedropping(true);
108+
109+ mg::Buffer* buffer{nullptr};
110+
111+ for (int i = 0; i < nbuffers; ++i)
112+ {
113+ bundle.client_acquire([&] (mg::Buffer* b) { buffer = b; });
114+ bundle.client_release(buffer);
115+ }
116+
117+ /*
118+ * We need nbuffers - 1 compositors to acquire all the buffers,
119+ * each compositor acquiring buffers twice (see below)
120+ */
121+ std::vector<int> compositors(nbuffers - 1);
122+ std::vector<std::shared_ptr<mg::Buffer>> buffers;
123+
124+ for (auto const& id : compositors)
125+ {
126+ buffers.push_back(bundle.compositor_acquire(&id));
127+ buffers.push_back(bundle.compositor_acquire(&id));
128+ }
129+
130+ /* At this point the bundle has 0 free buffers and 0 ready buffers */
131+
132+ mir::test::WaitCondition client_acquire_complete;
133+
134+ /*
135+ * Although we neither have a free buffer, nor can we free a buffer by dropping it,
136+ * this shouldn't block. BufferBundle::client_acquire() should *never* block.
137+ */
138+ bundle.client_acquire(
139+ [&] (mg::Buffer*)
140+ {
141+ client_acquire_complete.wake_up_everyone();
142+ });
143+
144+ /* Release compositor buffers so that the client can get one */
145+ for (auto const& buffer : buffers)
146+ {
147+ bundle.compositor_release(buffer);
148+ }
149+
150+ client_acquire_complete.wait_for_at_most_seconds(5);
151+
152+ EXPECT_TRUE(client_acquire_complete.woken());
153+}

Subscribers

People subscribed via source and target branches