Mir

Merge lp:~robertcarr/mir/hold-surface-alive into lp:~mir-team/mir/trunk

Proposed by Robert Carr
Status: Superseded
Proposed branch: lp:~robertcarr/mir/hold-surface-alive
Merge into: lp:~mir-team/mir/trunk
Diff against target: 610 lines (+57/-362)
8 files modified
include/server/mir/frontend/surface.h (+0/-1)
include/server/mir/shell/surface.h (+1/-3)
include/test/mir_test_doubles/mock_surface.h (+0/-1)
include/test/mir_test_doubles/stub_surface.h (+0/-1)
src/server/shell/application_session.cpp (+1/-2)
src/server/shell/surface.cpp (+18/-127)
tests/unit-tests/shell/test_application_session.cpp (+26/-2)
tests/unit-tests/shell/test_surface.cpp (+11/-225)
To merge this branch: bzr merge lp:~robertcarr/mir/hold-surface-alive
Reviewer Review Type Date Requested Status
Alexandros Frantzis (community) Needs Fixing
Kevin DuBois (community) Needs Fixing
PS Jenkins bot (community) continuous-integration Approve
Review via email: mp+189156@code.launchpad.net

This proposal has been superseded by a proposal from 2013-10-04.

Commit message

Hold ms::Surface alive from msh::Surface, and remove the explicit throw calls. This way holding a shared_ptr to msh::Surface becomes safe (as long as you drop it eventually!).

Description of the change

End the weak_ptr madness.

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Kevin DuBois (kdub) wrote :

How does the shell know when a surface has been destroyed? I'd still like to hedge against giving the shell a strong pointer (which leads to the temptation that the shell will just keep it around, when really, it might be destroyed at any time by mir)

In general, i'm okay with the shell having a strong pointer to the surfaces, provided the way they use it makes it clear that they should get the strong pointer, use it, and then release it.

Much of the functions in msh::Shell are now just passthrough.
perhaps we have something like:
std::shared_ptr<ms::Surface> msh::Shell::compositor_surface()
and then eliminate the passthrough functions

this part of the code needs some reworking, so if it solves a bug though and makes strange code less strange, i suppose that adds up to approve :)

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

actually, should be retargeted :)

should probably get a second look over from someone else before top approve as well

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

I can verify that this MP fixes the reported bug. However, it seems that the shell::Surface is never released and therefore the underlying ms::Surface is also never released. This is a pre-existing issue in unity8/mir, obscured before because the underlying ms::Surface was freed when the ApplicationSession was destroyed and called shell::Surface::destroy(). Before we land this, we need to find why shell::Surface is not released, and coordinate the fix with unity8 (if the problem is indeed outside Mir).

Marking "Needs fixing" to block this from landing before the other half of the fix is in place.

review: Needs Fixing

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'include/server/mir/frontend/surface.h'
2--- include/server/mir/frontend/surface.h 2013-08-28 03:41:48 +0000
3+++ include/server/mir/frontend/surface.h 2013-10-04 18:28:48 +0000
4@@ -50,7 +50,6 @@
5
6 virtual ~Surface() {}
7
8- virtual void destroy() = 0;
9 virtual void force_requests_to_complete() = 0;
10
11 virtual geometry::Size size() const = 0;
12
13=== modified file 'include/server/mir/shell/surface.h'
14--- include/server/mir/shell/surface.h 2013-08-28 03:41:48 +0000
15+++ include/server/mir/shell/surface.h 2013-10-04 18:28:48 +0000
16@@ -60,8 +60,6 @@
17 virtual void hide();
18 virtual void show();
19
20- virtual void destroy();
21-
22 virtual void force_requests_to_complete();
23
24 virtual std::string name() const;
25@@ -97,7 +95,7 @@
26
27 std::shared_ptr<SurfaceBuilder> const builder;
28 std::shared_ptr<SurfaceConfigurator> const configurator;
29- std::weak_ptr<mir::surfaces::Surface> const surface;
30+ std::shared_ptr<mir::surfaces::Surface> const surface;
31
32 frontend::SurfaceId const id;
33 std::shared_ptr<frontend::EventSink> const event_sink;
34
35=== modified file 'include/test/mir_test_doubles/mock_surface.h'
36--- include/test/mir_test_doubles/mock_surface.h 2013-08-28 03:41:48 +0000
37+++ include/test/mir_test_doubles/mock_surface.h 2013-10-04 18:28:48 +0000
38@@ -51,7 +51,6 @@
39 MOCK_METHOD0(visible, bool());
40 MOCK_METHOD1(raise, void(std::shared_ptr<shell::SurfaceController> const&));
41
42- MOCK_METHOD0(destroy, void());
43 MOCK_METHOD0(force_requests_to_complete, void());
44 MOCK_METHOD0(advance_client_buffer, std::shared_ptr<graphics::Buffer>());
45
46
47=== modified file 'include/test/mir_test_doubles/stub_surface.h'
48--- include/test/mir_test_doubles/stub_surface.h 2013-08-28 03:41:48 +0000
49+++ include/test/mir_test_doubles/stub_surface.h 2013-10-04 18:28:48 +0000
50@@ -35,7 +35,6 @@
51
52 void hide() {}
53 void show() {}
54- void destroy() {}
55 void force_requests_to_complete() {}
56
57 geometry::Size size() const
58
59=== modified file 'src/server/shell/application_session.cpp'
60--- src/server/shell/application_session.cpp 2013-08-28 03:41:48 +0000
61+++ src/server/shell/application_session.cpp 2013-10-04 18:28:48 +0000
62@@ -55,7 +55,7 @@
63 std::unique_lock<std::mutex> lock(surfaces_mutex);
64 for (auto const& pair_id_surface : surfaces)
65 {
66- pair_id_surface.second->destroy();
67+ session_listener->destroying_surface(*this, pair_id_surface.second);
68 }
69 }
70
71@@ -116,7 +116,6 @@
72
73 session_listener->destroying_surface(*this, p->second);
74
75- p->second->destroy();
76 surfaces.erase(p);
77 }
78
79
80=== modified file 'src/server/shell/surface.cpp'
81--- src/server/shell/surface.cpp 2013-08-28 03:41:48 +0000
82+++ src/server/shell/surface.cpp 2013-10-04 18:28:48 +0000
83@@ -58,165 +58,74 @@
84
85 msh::Surface::~Surface() noexcept
86 {
87- if (surface.lock())
88- {
89- destroy();
90- }
91+ builder->destroy_surface(surface);
92 }
93
94 void msh::Surface::hide()
95 {
96- if (auto const& s = surface.lock())
97- {
98- s->set_hidden(true);
99- }
100- else
101- {
102- BOOST_THROW_EXCEPTION(std::runtime_error("Invalid surface"));
103- }
104+ surface->set_hidden(true);
105 }
106
107 void msh::Surface::show()
108 {
109- if (auto const& s = surface.lock())
110- {
111- s->set_hidden(false);
112- }
113- else
114- {
115- BOOST_THROW_EXCEPTION(std::runtime_error("Invalid surface"));
116- }
117-}
118-
119-void msh::Surface::destroy()
120-{
121- builder->destroy_surface(surface);
122+ surface->set_hidden(false);
123 }
124
125 void msh::Surface::force_requests_to_complete()
126 {
127- if (auto const& s = surface.lock())
128- {
129- s->force_requests_to_complete();
130- }
131+ surface->force_requests_to_complete();
132 }
133
134 mir::geometry::Size msh::Surface::size() const
135 {
136- if (auto const& s = surface.lock())
137- {
138- return s->size();
139- }
140- else
141- {
142- BOOST_THROW_EXCEPTION(std::runtime_error("Invalid surface"));
143- }
144+ return surface->size();
145 }
146
147 void msh::Surface::move_to(geometry::Point const& p)
148 {
149- if (auto const& s = surface.lock())
150- {
151- s->move_to(p);
152- }
153- else
154- {
155- BOOST_THROW_EXCEPTION(std::runtime_error("Invalid surface"));
156- }
157+ surface->move_to(p);
158 }
159
160 mir::geometry::Point msh::Surface::top_left() const
161 {
162- if (auto const& s = surface.lock())
163- {
164- return s->top_left();
165- }
166- else
167- {
168- BOOST_THROW_EXCEPTION(std::runtime_error("Invalid surface"));
169- }
170+ return surface->top_left();
171 }
172
173 std::string msh::Surface::name() const
174 {
175- if (auto const& s = surface.lock())
176- {
177- return s->name();
178- }
179- else
180- {
181- BOOST_THROW_EXCEPTION(std::runtime_error("Invalid surface"));
182- }
183+ return surface->name();
184 }
185
186 mir::geometry::PixelFormat msh::Surface::pixel_format() const
187 {
188- if (auto const& s = surface.lock())
189- {
190- return s->pixel_format();
191- }
192- else
193- {
194- BOOST_THROW_EXCEPTION(std::runtime_error("Invalid surface"));
195- }
196+ return surface->pixel_format();
197 }
198
199 std::shared_ptr<mg::Buffer> msh::Surface::advance_client_buffer()
200 {
201- if (auto const& s = surface.lock())
202- {
203- return s->advance_client_buffer();
204- }
205- else
206- {
207- BOOST_THROW_EXCEPTION(std::runtime_error("Invalid surface"));
208- }
209+ return surface->advance_client_buffer();
210 }
211
212 void msh::Surface::allow_framedropping(bool allow)
213 {
214- if (auto const& s = surface.lock())
215- {
216- s->allow_framedropping(allow);
217- }
218+ surface->allow_framedropping(allow);
219 }
220
221 void msh::Surface::with_most_recent_buffer_do(
222 std::function<void(mg::Buffer&)> const& exec)
223 {
224- if (auto const& s = surface.lock())
225- {
226- auto buf = s->snapshot_buffer();
227- exec(*buf);
228- }
229- else
230- {
231- BOOST_THROW_EXCEPTION(std::runtime_error("Invalid surface"));
232- }
233+ auto buf = surface->snapshot_buffer();
234+ exec(*buf);
235 }
236
237 bool msh::Surface::supports_input() const
238 {
239- if (auto const& s = surface.lock())
240- {
241- return s->supports_input();
242- }
243- else
244- {
245- BOOST_THROW_EXCEPTION(std::runtime_error("Invalid surface"));
246- }
247+ return surface->supports_input();
248 }
249
250 int msh::Surface::client_input_fd() const
251 {
252- if (auto const& s = surface.lock())
253- {
254- return s->client_input_fd();
255- }
256- else
257- {
258- BOOST_THROW_EXCEPTION(std::runtime_error("Invalid surface"));
259- }
260+ return surface->client_input_fd();
261 }
262
263 int msh::Surface::configure(MirSurfaceAttrib attrib, int value)
264@@ -319,33 +228,15 @@
265
266 void msh::Surface::take_input_focus(std::shared_ptr<msh::InputTargeter> const& targeter)
267 {
268- auto s = surface.lock();
269- if (s)
270- targeter->focus_changed(s->input_channel());
271- else
272- BOOST_THROW_EXCEPTION(std::runtime_error("Invalid surface"));
273+ targeter->focus_changed(surface->input_channel());
274 }
275
276 void msh::Surface::set_input_region(std::vector<geom::Rectangle> const& region)
277 {
278- if (auto const& s = surface.lock())
279- {
280- s->set_input_region(region);
281- }
282- else
283- {
284- BOOST_THROW_EXCEPTION(std::runtime_error("Invalid surface"));
285- }
286+ surface->set_input_region(region);
287 }
288
289 void msh::Surface::raise(std::shared_ptr<msh::SurfaceController> const& controller)
290 {
291- if (auto const& s = surface.lock())
292- {
293- controller->raise(s);
294- }
295- else
296- {
297- BOOST_THROW_EXCEPTION(std::runtime_error("Invalid surface"));
298- }
299+ controller->raise(surface);
300 }
301
302=== modified file 'tests/unit-tests/shell/test_application_session.cpp'
303--- tests/unit-tests/shell/test_application_session.cpp 2013-08-28 03:41:48 +0000
304+++ tests/unit-tests/shell/test_application_session.cpp 2013-10-04 18:28:48 +0000
305@@ -65,7 +65,6 @@
306 ON_CALL(surface_factory, create_surface(_,_,_,_)).WillByDefault(Return(mock_surface));
307
308 EXPECT_CALL(surface_factory, create_surface(_, _, _, _));
309- EXPECT_CALL(*mock_surface, destroy());
310
311 mtd::MockSessionListener listener;
312 EXPECT_CALL(listener, surface_created(_, _)).Times(1);
313@@ -82,6 +81,32 @@
314 session.destroy_surface(surf);
315 }
316
317+TEST(ApplicationSession, listener_notified_of_surface_destruction_on_session_destruction)
318+{
319+ using namespace ::testing;
320+
321+ auto mock_surface = make_mock_surface();
322+
323+ mtd::NullEventSink sender;
324+ mtd::MockSurfaceFactory surface_factory;
325+ ON_CALL(surface_factory, create_surface(_,_,_,_)).WillByDefault(Return(mock_surface));
326+
327+ EXPECT_CALL(surface_factory, create_surface(_, _, _, _));
328+
329+ mtd::MockSessionListener listener;
330+ EXPECT_CALL(listener, surface_created(_, _)).Times(1);
331+ EXPECT_CALL(listener, destroying_surface(_, _)).Times(1);
332+
333+ {
334+ msh::ApplicationSession session(mt::fake_shared(surface_factory), "Foo",
335+ std::make_shared<mtd::NullSnapshotStrategy>(), mt::fake_shared(listener),
336+ mt::fake_shared(sender));
337+
338+ msh::SurfaceCreationParameters params;
339+ session.create_surface(params);
340+ }
341+}
342+
343 TEST(ApplicationSession, default_surface_is_first_surface)
344 {
345 using namespace ::testing;
346@@ -142,7 +167,6 @@
347 InSequence seq;
348 EXPECT_CALL(*mock_surface, hide()).Times(1);
349 EXPECT_CALL(*mock_surface, show()).Times(1);
350- EXPECT_CALL(*mock_surface, destroy()).Times(1);
351 }
352
353 msh::SurfaceCreationParameters params;
354
355=== modified file 'tests/unit-tests/shell/test_surface.cpp'
356--- tests/unit-tests/shell/test_surface.cpp 2013-08-28 03:41:48 +0000
357+++ tests/unit-tests/shell/test_surface.cpp 2013-10-04 18:28:48 +0000
358@@ -191,197 +191,20 @@
359 EXPECT_CALL(surface_builder, create_surface(nullptr, _)).Times(AnyNumber());
360 EXPECT_CALL(surface_builder, destroy_surface(_)).Times(0);
361
362- msh::Surface test(
363- nullptr,
364- mt::fake_shared(surface_builder), std::make_shared<mtd::NullSurfaceConfigurator>(),
365- msh::a_surface(), stub_id, stub_sender);
366-
367- Mock::VerifyAndClearExpectations(&test);
368- EXPECT_CALL(surface_builder, destroy_surface(_)).Times(1);
369-
370- // Check destroy_surface is called immediately
371- test.destroy();
372-
373- Mock::VerifyAndClearExpectations(&test);
374+ {
375+ msh::Surface test(
376+ nullptr,
377+ mt::fake_shared(surface_builder), std::make_shared<mtd::NullSurfaceConfigurator>(),
378+ msh::a_surface(), stub_id, stub_sender);
379+
380+ Mock::VerifyAndClearExpectations(&test);
381+ EXPECT_CALL(surface_builder, destroy_surface(_)).Times(1);
382+ Mock::VerifyAndClearExpectations(&test);
383+ }
384+
385 EXPECT_CALL(surface_builder, destroy_surface(_)).Times(0);
386 }
387
388-TEST_F(ShellSurface, size_throw_behavior)
389-{
390- msh::Surface test(
391- nullptr,
392- mt::fake_shared(surface_builder), std::make_shared<mtd::NullSurfaceConfigurator>(),
393- msh::a_surface(), stub_id, stub_sender);
394-
395- EXPECT_NO_THROW({
396- test.size();
397- });
398-
399- surface_builder.reset_surface();
400-
401- EXPECT_THROW({
402- test.size();
403- }, std::runtime_error);
404-}
405-
406-TEST_F(ShellSurface, top_left_throw_behavior)
407-{
408- msh::Surface test(
409- nullptr,
410- mt::fake_shared(surface_builder), std::make_shared<mtd::NullSurfaceConfigurator>(),
411- msh::a_surface(), stub_id, stub_sender);
412-
413- EXPECT_NO_THROW({
414- test.top_left();
415- });
416-
417- surface_builder.reset_surface();
418-
419- EXPECT_THROW({
420- test.top_left();
421- }, std::runtime_error);
422-}
423-
424-TEST_F(ShellSurface, name_throw_behavior)
425-{
426- msh::Surface test(
427- nullptr,
428- mt::fake_shared(surface_builder), std::make_shared<mtd::NullSurfaceConfigurator>(),
429- msh::a_surface(), stub_id, stub_sender);
430-
431- EXPECT_NO_THROW({
432- test.name();
433- });
434-
435- surface_builder.reset_surface();
436-
437- EXPECT_THROW({
438- test.name();
439- }, std::runtime_error);
440-}
441-
442-TEST_F(ShellSurface, pixel_format_throw_behavior)
443-{
444- msh::Surface test(
445- nullptr,
446- mt::fake_shared(surface_builder), std::make_shared<mtd::NullSurfaceConfigurator>(),
447- msh::a_surface(), stub_id, stub_sender);
448-
449- EXPECT_NO_THROW({
450- test.pixel_format();
451- });
452-
453- surface_builder.reset_surface();
454-
455- EXPECT_THROW({
456- test.pixel_format();
457- }, std::runtime_error);
458-}
459-
460-TEST_F(ShellSurface, hide_throw_behavior)
461-{
462- msh::Surface test(
463- nullptr,
464- mt::fake_shared(surface_builder), std::make_shared<mtd::NullSurfaceConfigurator>(),
465- msh::a_surface(), stub_id, stub_sender);
466-
467- EXPECT_NO_THROW({
468- test.hide();
469- });
470-
471- surface_builder.reset_surface();
472-
473- EXPECT_THROW({
474- test.hide();
475- }, std::runtime_error);
476-}
477-
478-TEST_F(ShellSurface, show_throw_behavior)
479-{
480- msh::Surface test(
481- nullptr,
482- mt::fake_shared(surface_builder), std::make_shared<mtd::NullSurfaceConfigurator>(),
483- msh::a_surface(), stub_id, stub_sender);
484-
485- EXPECT_NO_THROW({
486- test.show();
487- });
488-
489- surface_builder.reset_surface();
490-
491- EXPECT_THROW({
492- test.show();
493- }, std::runtime_error);
494-}
495-
496-TEST_F(ShellSurface, destroy_throw_behavior)
497-{
498- msh::Surface test(
499- nullptr,
500- mt::fake_shared(surface_builder), std::make_shared<mtd::NullSurfaceConfigurator>(),
501- msh::a_surface(), stub_id, stub_sender);
502-
503- EXPECT_NO_THROW({
504- test.destroy();
505- });
506-
507- surface_builder.reset_surface();
508-
509- EXPECT_NO_THROW({
510- test.destroy();
511- });
512-}
513-
514-TEST_F(ShellSurface, force_request_to_complete_throw_behavior)
515-{
516- msh::Surface test(
517- nullptr,
518- mt::fake_shared(surface_builder), std::make_shared<mtd::NullSurfaceConfigurator>(),
519- msh::a_surface(), stub_id, stub_sender);
520-
521- EXPECT_NO_THROW({
522- test.force_requests_to_complete();
523- });
524-
525- surface_builder.reset_surface();
526-
527- EXPECT_NO_THROW({
528- test.force_requests_to_complete();
529- });
530-}
531-
532-TEST_F(ShellSurface, advance_client_buffer_throw_behavior)
533-{
534- msh::Surface test(
535- nullptr,
536- mt::fake_shared(surface_builder), std::make_shared<mtd::NullSurfaceConfigurator>(),
537- msh::a_surface(), stub_id, stub_sender);
538-
539- EXPECT_NO_THROW({
540- test.advance_client_buffer();
541- });
542-
543- surface_builder.reset_surface();
544-
545- EXPECT_THROW({
546- test.advance_client_buffer();
547- }, std::runtime_error);
548-}
549-
550-TEST_F(ShellSurface, input_fds_throw_behavior)
551-{
552- msh::Surface test(
553- nullptr,
554- mt::fake_shared(surface_builder), std::make_shared<mtd::NullSurfaceConfigurator>(),
555- msh::a_surface(), stub_id, stub_sender);
556-
557- surface_builder.reset_surface();
558-
559- EXPECT_THROW({
560- test.client_input_fd();
561- }, std::runtime_error);
562-}
563-
564 TEST_F(ShellSurface, attributes)
565 {
566 using namespace testing;
567@@ -522,43 +345,6 @@
568 test.take_input_focus(mt::fake_shared(targeter));
569 }
570
571-TEST_F(ShellSurface, take_input_focus_throw_behavior)
572-{
573- using namespace ::testing;
574-
575- msh::Surface test(
576- nullptr,
577- mt::fake_shared(surface_builder), std::make_shared<mtd::NullSurfaceConfigurator>(),
578- msh::a_surface(), stub_id, stub_sender);
579- surface_builder.reset_surface();
580-
581- mtd::StubInputTargeter targeter;
582-
583- EXPECT_THROW({
584- test.take_input_focus(mt::fake_shared(targeter));
585- }, std::runtime_error);
586-}
587-
588-TEST_F(ShellSurface, set_input_region_throw_behavior)
589-{
590- using namespace ::testing;
591-
592- msh::Surface test(
593- nullptr,
594- mt::fake_shared(surface_builder), std::make_shared<mtd::NullSurfaceConfigurator>(),
595- msh::a_surface(), stub_id, stub_sender);
596-
597- EXPECT_NO_THROW({
598- test.set_input_region(std::vector<geom::Rectangle>{});
599- });
600-
601- surface_builder.reset_surface();
602-
603- EXPECT_THROW({
604- test.set_input_region(std::vector<geom::Rectangle>{});
605- }, std::runtime_error);
606-}
607-
608 TEST_F(ShellSurface, with_most_recent_buffer_do_uses_compositor_buffer)
609 {
610 msh::Surface test(

Subscribers

People subscribed via source and target branches