Mir

Merge lp:~alan-griffiths/mir/fix-1522105 into lp:mir

Proposed by Alan Griffiths
Status: Merged
Approved by: Alberto Aguirre
Approved revision: no longer in the source branch.
Merged at revision: 3172
Proposed branch: lp:~alan-griffiths/mir/fix-1522105
Merge into: lp:mir
Diff against target: 348 lines (+96/-35)
3 files modified
src/server/scene/surface_stack.cpp (+27/-23)
src/server/scene/surface_stack.h (+2/-1)
tests/unit-tests/scene/test_surface_stack.cpp (+67/-11)
To merge this branch: bzr merge lp:~alan-griffiths/mir/fix-1522105
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+279418@code.launchpad.net

Commit message

scene: fix the locking in SurfaceStack

Description of the change

scene: fix the locking in SurfaceStack

The primary motivation is add_observer() using a reference to an unlocked data structure (lp:1522105) but there were also issues with create_rendering_tracker_for() and update_rendering_tracker_compositors() which access rendering_trackers without any locking.

To post a comment you must log in.
Revision history for this message
Alan Griffiths (alan-griffiths) wrote :

An alternative solution to ~albaguirre/mir/fix-1522105/+merge/279393

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Alberto Aguirre (albaguirre) wrote :

I vote for this one :)

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

looks good to me

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

> looks good to me
At Alberto's request in standup today, will cherry-pick this fix into 0.18 once this MP lands to lp:mir

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'src/server/scene/surface_stack.cpp'
--- src/server/scene/surface_stack.cpp 2015-11-05 11:51:04 +0000
+++ src/server/scene/surface_stack.cpp 2015-12-03 10:31:29 +0000
@@ -127,7 +127,7 @@
127127
128mc::SceneElementSequence ms::SurfaceStack::scene_elements_for(mc::CompositorID id)128mc::SceneElementSequence ms::SurfaceStack::scene_elements_for(mc::CompositorID id)
129{129{
130 std::lock_guard<decltype(guard)> lg(guard);130 RecursiveReadLock lg(guard);
131131
132 scene_changed = false;132 scene_changed = false;
133 mc::SceneElementSequence elements;133 mc::SceneElementSequence elements;
@@ -155,7 +155,7 @@
155155
156int ms::SurfaceStack::frames_pending(mc::CompositorID id) const156int ms::SurfaceStack::frames_pending(mc::CompositorID id) const
157{157{
158 std::lock_guard<decltype(guard)> lg(guard);158 RecursiveReadLock lg(guard);
159159
160 int result = scene_changed ? 1 : 0;160 int result = scene_changed ? 1 : 0;
161 for (auto const& surface : surfaces)161 for (auto const& surface : surfaces)
@@ -182,7 +182,7 @@
182182
183void ms::SurfaceStack::register_compositor(mc::CompositorID cid)183void ms::SurfaceStack::register_compositor(mc::CompositorID cid)
184{184{
185 std::lock_guard<decltype(guard)> lg(guard);185 RecursiveWriteLock lg(guard);
186186
187 registered_compositors.insert(cid);187 registered_compositors.insert(cid);
188188
@@ -191,7 +191,7 @@
191191
192void ms::SurfaceStack::unregister_compositor(mc::CompositorID cid)192void ms::SurfaceStack::unregister_compositor(mc::CompositorID cid)
193{193{
194 std::lock_guard<decltype(guard)> lg(guard);194 RecursiveWriteLock lg(guard);
195195
196 registered_compositors.erase(cid);196 registered_compositors.erase(cid);
197197
@@ -202,7 +202,7 @@
202 std::shared_ptr<mg::Renderable> const& overlay)202 std::shared_ptr<mg::Renderable> const& overlay)
203{203{
204 {204 {
205 std::lock_guard<decltype(guard)> lg(guard);205 RecursiveWriteLock lg(guard);
206 overlays.push_back(overlay);206 overlays.push_back(overlay);
207 }207 }
208 emit_scene_changed();208 emit_scene_changed();
@@ -213,7 +213,7 @@
213{213{
214 auto overlay = weak_overlay.lock();214 auto overlay = weak_overlay.lock();
215 {215 {
216 std::lock_guard<decltype(guard)> lg(guard);216 RecursiveWriteLock lg(guard);
217 auto const p = std::find(overlays.begin(), overlays.end(), overlay);217 auto const p = std::find(overlays.begin(), overlays.end(), overlay);
218 if (p == overlays.end())218 if (p == overlays.end())
219 {219 {
@@ -228,7 +228,7 @@
228void ms::SurfaceStack::emit_scene_changed()228void ms::SurfaceStack::emit_scene_changed()
229{229{
230 {230 {
231 std::lock_guard<decltype(guard)> lg(guard);231 RecursiveWriteLock lg(guard);
232 scene_changed = true;232 scene_changed = true;
233 }233 }
234 observers.scene_changed();234 observers.scene_changed();
@@ -239,7 +239,7 @@
239 mi::InputReceptionMode input_mode)239 mi::InputReceptionMode input_mode)
240{240{
241 {241 {
242 std::lock_guard<decltype(guard)> lg(guard);242 RecursiveWriteLock lg(guard);
243 surfaces.push_back(surface);243 surfaces.push_back(surface);
244 create_rendering_tracker_for(surface);244 create_rendering_tracker_for(surface);
245 }245 }
@@ -255,7 +255,7 @@
255255
256 bool found_surface = false;256 bool found_surface = false;
257 {257 {
258 std::lock_guard<decltype(guard)> lg(guard);258 RecursiveWriteLock lg(guard);
259259
260 auto const surface = std::find(surfaces.begin(), surfaces.end(), keep_alive);260 auto const surface = std::find(surfaces.begin(), surfaces.end(), keep_alive);
261261
@@ -292,7 +292,7 @@
292auto ms::SurfaceStack::surface_at(geometry::Point cursor) const292auto ms::SurfaceStack::surface_at(geometry::Point cursor) const
293-> std::shared_ptr<Surface>293-> std::shared_ptr<Surface>
294{294{
295 std::lock_guard<decltype(guard)> lg(guard);295 RecursiveReadLock lg(guard);
296 for (auto const& surface : in_reverse(surfaces))296 for (auto const& surface : in_reverse(surfaces))
297 {297 {
298 // TODO There's a lack of clarity about how the input area will298 // TODO There's a lack of clarity about how the input area will
@@ -308,7 +308,7 @@
308308
309void ms::SurfaceStack::for_each(std::function<void(std::shared_ptr<mi::Surface> const&)> const& callback)309void ms::SurfaceStack::for_each(std::function<void(std::shared_ptr<mi::Surface> const&)> const& callback)
310{310{
311 std::lock_guard<decltype(guard)> lg(guard);311 RecursiveReadLock lg(guard);
312 for (auto &surface : surfaces)312 for (auto &surface : surfaces)
313 {313 {
314 if (surface->query(mir_surface_attrib_visibility) ==314 if (surface->query(mir_surface_attrib_visibility) ==
@@ -321,32 +321,34 @@
321321
322void ms::SurfaceStack::raise(std::weak_ptr<Surface> const& s)322void ms::SurfaceStack::raise(std::weak_ptr<Surface> const& s)
323{323{
324 auto surface = s.lock();324 bool surfaces_reordered{false};
325325
326 {326 {
327 std::unique_lock<decltype(guard)> ul(guard);327 auto const surface = s.lock();
328
329 RecursiveWriteLock ul(guard);
328 auto const p = std::find(surfaces.begin(), surfaces.end(), surface);330 auto const p = std::find(surfaces.begin(), surfaces.end(), surface);
329331
330 if (p != surfaces.end())332 if (p != surfaces.end())
331 {333 {
332 surfaces.erase(p);334 surfaces.erase(p);
333 surfaces.push_back(surface);335 surfaces.push_back(surface);
334336 surfaces_reordered = true;
335 ul.unlock();
336 observers.surfaces_reordered();
337
338 return;
339 }337 }
340 }338 }
341339
342 BOOST_THROW_EXCEPTION(std::runtime_error("Invalid surface"));340 if (!surfaces_reordered)
341 BOOST_THROW_EXCEPTION(std::runtime_error("Invalid surface"));
342
343 observers.surfaces_reordered();
344 return;
343}345}
344346
345void ms::SurfaceStack::raise(SurfaceSet const& ss)347void ms::SurfaceStack::raise(SurfaceSet const& ss)
346{348{
347 bool surfaces_reordered{false};349 bool surfaces_reordered{false};
348 {350 {
349 std::lock_guard<decltype(guard)> ul(guard);351 RecursiveWriteLock ul(guard);
350352
351 auto const old_surfaces = surfaces;353 auto const old_surfaces = surfaces;
352 std::stable_partition(354 std::stable_partition(
@@ -364,12 +366,16 @@
364void ms::SurfaceStack::create_rendering_tracker_for(std::shared_ptr<Surface> const& surface)366void ms::SurfaceStack::create_rendering_tracker_for(std::shared_ptr<Surface> const& surface)
365{367{
366 auto const tracker = std::make_shared<RenderingTracker>(surface);368 auto const tracker = std::make_shared<RenderingTracker>(surface);
369
370 RecursiveWriteLock ul(guard);
367 tracker->active_compositors(registered_compositors);371 tracker->active_compositors(registered_compositors);
368 rendering_trackers[surface.get()] = tracker;372 rendering_trackers[surface.get()] = tracker;
369}373}
370374
371void ms::SurfaceStack::update_rendering_tracker_compositors()375void ms::SurfaceStack::update_rendering_tracker_compositors()
372{376{
377 RecursiveReadLock ul(guard);
378
373 for (auto const& pair : rendering_trackers)379 for (auto const& pair : rendering_trackers)
374 pair.second->active_compositors(registered_compositors);380 pair.second->active_compositors(registered_compositors);
375}381}
@@ -379,12 +385,10 @@
379 observers.add(observer);385 observers.add(observer);
380386
381 // Notify observer of existing surfaces387 // Notify observer of existing surfaces
382 std::unique_lock<decltype(guard)> lk(guard);388 RecursiveReadLock lk(guard);
383 for (auto &surface : surfaces)389 for (auto &surface : surfaces)
384 {390 {
385 lk.unlock();
386 observer->surface_exists(surface.get());391 observer->surface_exists(surface.get());
387 lk.lock();
388 }392 }
389}393}
390394
391395
=== modified file 'src/server/scene/surface_stack.h'
--- src/server/scene/surface_stack.h 2015-11-25 16:32:07 +0000
+++ src/server/scene/surface_stack.h 2015-12-03 10:31:29 +0000
@@ -24,6 +24,7 @@
24#include "mir/compositor/scene.h"24#include "mir/compositor/scene.h"
25#include "mir/scene/observer.h"25#include "mir/scene/observer.h"
26#include "mir/input/scene.h"26#include "mir/input/scene.h"
27#include "mir/recursive_read_write_mutex.h"
2728
28#include "mir/basic_observers.h"29#include "mir/basic_observers.h"
2930
@@ -106,7 +107,7 @@
106 void create_rendering_tracker_for(std::shared_ptr<Surface> const&);107 void create_rendering_tracker_for(std::shared_ptr<Surface> const&);
107 void update_rendering_tracker_compositors();108 void update_rendering_tracker_compositors();
108109
109 std::mutex mutable guard;110 RecursiveReadWriteMutex mutable guard;
110111
111 std::shared_ptr<InputRegistrar> const input_registrar;112 std::shared_ptr<InputRegistrar> const input_registrar;
112 std::shared_ptr<SceneReport> const report;113 std::shared_ptr<SceneReport> const report;
113114
=== modified file 'tests/unit-tests/scene/test_surface_stack.cpp'
--- tests/unit-tests/scene/test_surface_stack.cpp 2015-11-05 11:51:04 +0000
+++ tests/unit-tests/scene/test_surface_stack.cpp 2015-12-03 10:31:29 +0000
@@ -349,7 +349,7 @@
349 .WillByDefault(InvokeWithoutArgs([&]{ready++;}));349 .WillByDefault(InvokeWithoutArgs([&]{ready++;}));
350 ON_CALL(*mock_queue, compositor_acquire(_))350 ON_CALL(*mock_queue, compositor_acquire(_))
351 .WillByDefault(InvokeWithoutArgs([&]{ready--; return mt::fake_shared(stub_buffer); }));351 .WillByDefault(InvokeWithoutArgs([&]{ready--; return mt::fake_shared(stub_buffer); }));
352 352
353 auto surface = std::make_shared<ms::BasicSurface>(353 auto surface = std::make_shared<ms::BasicSurface>(
354 std::string("stub"),354 std::string("stub"),
355 geom::Rectangle{{},{}},355 geom::Rectangle{{},{}},
@@ -620,20 +620,76 @@
620{620{
621 using namespace ::testing;621 using namespace ::testing;
622622
623 using namespace ::testing;
624
625 MockSceneObserver observer;623 MockSceneObserver observer;
626624
627 InSequence seq;625 InSequence seq;
628 EXPECT_CALL(observer, surface_exists(stub_surface1.get())).Times(1);626 EXPECT_CALL(observer, surface_exists(stub_surface1.get())).Times(1);
629 EXPECT_CALL(observer, surface_exists(stub_surface2.get())).Times(1);627 EXPECT_CALL(observer, surface_exists(stub_surface2.get())).Times(1);
630 628
631 stack.add_surface(stub_surface1, default_params.input_mode);629 stack.add_surface(stub_surface1, default_params.input_mode);
632 stack.add_surface(stub_surface2, default_params.input_mode);630 stack.add_surface(stub_surface2, default_params.input_mode);
633631
634 stack.add_observer(mt::fake_shared(observer));632 stack.add_observer(mt::fake_shared(observer));
635}633}
636634
635TEST_F(SurfaceStack, scene_observer_can_query_scene_within_surface_exists_notification)
636{
637 using namespace ::testing;
638
639 MockSceneObserver observer;
640
641 auto const scene_query = [&]{
642 stack.for_each([&](std::shared_ptr<mi::Surface> const& surface){
643 EXPECT_THAT(surface.get(), Eq(stub_surface1.get()));
644 });
645 };
646 EXPECT_CALL(observer, surface_exists(stub_surface1.get())).Times(1)
647 .WillOnce(InvokeWithoutArgs(scene_query));
648
649 stack.add_surface(stub_surface1, default_params.input_mode);
650 stack.add_observer(mt::fake_shared(observer));
651}
652
653TEST_F(SurfaceStack, scene_observer_can_async_query_scene_within_surface_exists_notification)
654{
655 using namespace ::testing;
656
657 MockSceneObserver observer;
658
659 auto const scene_query = [&]{
660 stack.for_each([&](std::shared_ptr<mi::Surface> const& surface){
661 EXPECT_THAT(surface.get(), Eq(stub_surface1.get()));
662 });
663 };
664
665 auto const async_scene_query = [&]{
666 std::async(std::launch::async, scene_query);
667 };
668
669 EXPECT_CALL(observer, surface_exists(stub_surface1.get())).Times(1)
670 .WillOnce(InvokeWithoutArgs(async_scene_query));
671
672 stack.add_surface(stub_surface1, default_params.input_mode);
673 stack.add_observer(mt::fake_shared(observer));
674}
675
676
677TEST_F(SurfaceStack, scene_observer_can_remove_surface_from_scene_within_surface_exists_notification)
678{
679 using namespace ::testing;
680
681 MockSceneObserver observer;
682
683 auto const surface_removal = [&]{
684 stack.remove_surface(stub_surface1);
685 };
686 EXPECT_CALL(observer, surface_exists(stub_surface1.get())).Times(1)
687 .WillOnce(InvokeWithoutArgs(surface_removal));
688
689 stack.add_surface(stub_surface1, default_params.input_mode);
690 stack.add_observer(mt::fake_shared(observer));
691}
692
637TEST_F(SurfaceStack, surfaces_reordered)693TEST_F(SurfaceStack, surfaces_reordered)
638{694{
639 using namespace ::testing;695 using namespace ::testing;
@@ -923,7 +979,7 @@
923TEST_F(SurfaceStack, overlays_do_not_appear_in_input_enumeration)979TEST_F(SurfaceStack, overlays_do_not_appear_in_input_enumeration)
924{980{
925 mtd::StubRenderable r;981 mtd::StubRenderable r;
926 982
927 stack.add_surface(stub_surface1, default_params.input_mode);983 stack.add_surface(stub_surface1, default_params.input_mode);
928 stack.add_surface(stub_surface2, default_params.input_mode);984 stack.add_surface(stub_surface2, default_params.input_mode);
929985
@@ -946,7 +1002,7 @@
946 using namespace ::testing;1002 using namespace ::testing;
9471003
948 mtd::StubRenderable r;1004 mtd::StubRenderable r;
949 1005
950 stack.add_surface(stub_surface1, default_params.input_mode);1006 stack.add_surface(stub_surface1, default_params.input_mode);
951 stack.add_input_visualization(mt::fake_shared(r));1007 stack.add_input_visualization(mt::fake_shared(r));
952 stack.add_surface(stub_surface2, default_params.input_mode);1008 stack.add_surface(stub_surface2, default_params.input_mode);
@@ -956,7 +1012,7 @@
956 ElementsAre(1012 ElementsAre(
957 SceneElementForSurface(stub_surface1),1013 SceneElementForSurface(stub_surface1),
958 SceneElementForSurface(stub_surface2),1014 SceneElementForSurface(stub_surface2),
959 SceneElementForStream(mt::fake_shared(r)))); 1015 SceneElementForStream(mt::fake_shared(r))));
960}1016}
9611017
962TEST_F(SurfaceStack, removed_overlays_are_removed)1018TEST_F(SurfaceStack, removed_overlays_are_removed)
@@ -964,7 +1020,7 @@
964 using namespace ::testing;1020 using namespace ::testing;
9651021
966 mtd::StubRenderable r;1022 mtd::StubRenderable r;
967 1023
968 stack.add_surface(stub_surface1, default_params.input_mode);1024 stack.add_surface(stub_surface1, default_params.input_mode);
969 stack.add_input_visualization(mt::fake_shared(r));1025 stack.add_input_visualization(mt::fake_shared(r));
970 stack.add_surface(stub_surface2, default_params.input_mode);1026 stack.add_surface(stub_surface2, default_params.input_mode);
@@ -975,7 +1031,7 @@
975 SceneElementForSurface(stub_surface1),1031 SceneElementForSurface(stub_surface1),
976 SceneElementForSurface(stub_surface2),1032 SceneElementForSurface(stub_surface2),
977 SceneElementForStream(mt::fake_shared(r))));1033 SceneElementForStream(mt::fake_shared(r))));
978 1034
979 stack.remove_input_visualization(mt::fake_shared(r));1035 stack.remove_input_visualization(mt::fake_shared(r));
9801036
981 EXPECT_THAT(1037 EXPECT_THAT(
@@ -991,10 +1047,10 @@
9911047
992 EXPECT_CALL(o1, scene_changed()).Times(1);1048 EXPECT_CALL(o1, scene_changed()).Times(1);
993 EXPECT_CALL(o2, scene_changed()).Times(1);1049 EXPECT_CALL(o2, scene_changed()).Times(1);
994 1050
995 stack.add_observer(mt::fake_shared(o1));1051 stack.add_observer(mt::fake_shared(o1));
996 stack.add_observer(mt::fake_shared(o2));1052 stack.add_observer(mt::fake_shared(o2));
997 1053
998 stack.emit_scene_changed();1054 stack.emit_scene_changed();
999}1055}
10001056

Subscribers

People subscribed via source and target branches