Mir

Merge lp:~afrantzis/mir/fix-1513901-shutdown-crash-with-mesa-kms into lp:mir

Proposed by Alexandros Frantzis
Status: Merged
Approved by: Alexandros Frantzis
Approved revision: no longer in the source branch.
Merged at revision: 3094
Proposed branch: lp:~afrantzis/mir/fix-1513901-shutdown-crash-with-mesa-kms
Merge into: lp:mir
Diff against target: 171 lines (+41/-21)
6 files modified
src/include/platform/mir/emergency_cleanup_registry.h (+4/-1)
src/platforms/mesa/server/kms/platform.cpp (+10/-8)
src/server/default_emergency_cleanup.cpp (+11/-2)
src/server/default_emergency_cleanup.h (+2/-1)
tests/include/mir/test/doubles/null_emergency_cleanup.h (+1/-0)
tests/unit-tests/graphics/mesa/kms/test_platform.cpp (+13/-9)
To merge this branch: bzr merge lp:~afrantzis/mir/fix-1513901-shutdown-crash-with-mesa-kms
Reviewer Review Type Date Requested Status
PS Jenkins bot (community) continuous-integration Approve
Andreas Pokorny (community) Approve
Alan Griffiths Approve
Review via email: mp+276986@code.launchpad.net

Commit message

platform: Platform emergency cleanup handlers should keep platform modules alive

Otherwise, the cleanup handler destructor (which is part of the platform shared
object code) may be called after the platform shared object has been unloaded,
leading to a crash.

Description of the change

platform: Platform emergency cleanup handlers should keep platform modules alive

Otherwise, the cleanup handler destructor (which is part of the platform shared object code) may be called after the platform shared object has been unloaded, leading to a crash.

Note that the changes in this MP break the platform ABI, but the ABI has already been bumped after 0.17.

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

Fixes the problem.

It seems a shame to add yet a further level of indirection (and memory allocation) to std::function<> but this only costs during startup/shutdown, so OK.

review: Approve
Revision history for this message
Andreas Pokorny (andreas-pokorny) wrote :

> Fixes the problem.
>
> It seems a shame to add yet a further level of indirection (and memory
> allocation) to std::function<> but this only costs during startup/shutdown, so
> OK.

Hm there is a proposal for a std::function with allocator..

Couldnt we store alive-keeping inside the bound functor. (Downside: Moves responsibility of being aware of the problem and dealing with it properly to the caller/platform author.. ).

review: Needs Information
Revision history for this message
Andreas Pokorny (andreas-pokorny) wrote :

I meant:
     emergency_cleanup_registry.add(
        [weak_vt, weak_drm, keep_library_alive=mir::detail::RefCountedLibrary(reinterpret_cast<void*>(&create_host_platform))]
        {
            if (auto const vt = weak_vt.lock())
                try { vt->restore(); } catch (...) {}

            if (auto const drm = weak_drm.lock())
                try { drm->drop_master(); } catch (...) {}
 });

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

> keep_library_alive=mir::detail::RefCountedLibrary(reinterpret_cast<void*>(&create_host_platform))]

This what I tried first (although I used a shared_ptr<> backed by mir::UniqueModulePtr<int> as the keep_alive object) but it didn't have the desired result. I also tried your proposal (RefCountedLibrary) a moment ago without success either.

Revision history for this message
Andreas Pokorny (andreas-pokorny) wrote :

oh you might then have the problem that the destructor code is unloaded while being executed.. since it is part of the lambda object inside the platform library...

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

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/include/platform/mir/emergency_cleanup_registry.h'
2--- src/include/platform/mir/emergency_cleanup_registry.h 2015-02-22 07:46:25 +0000
3+++ src/include/platform/mir/emergency_cleanup_registry.h 2015-11-09 11:17:37 +0000
4@@ -21,11 +21,13 @@
5 #define MIR_EMERGENCY_CLEANUP_REGISTRY_H_
6
7 #include <functional>
8+#include "mir/module_deleter.h"
9
10 namespace mir
11 {
12
13-typedef std::function<void()> EmergencyCleanupHandler;
14+using EmergencyCleanupHandler = std::function<void()>;
15+using ModuleEmergencyCleanupHandler = mir::UniqueModulePtr<std::function<void()>>;
16
17 class EmergencyCleanupRegistry
18 {
19@@ -33,6 +35,7 @@
20 virtual ~EmergencyCleanupRegistry() = default;
21
22 virtual void add(EmergencyCleanupHandler const& handler) = 0;
23+ virtual void add(ModuleEmergencyCleanupHandler handler) = 0;
24
25 protected:
26 EmergencyCleanupRegistry() = default;
27
28=== modified file 'src/platforms/mesa/server/kms/platform.cpp'
29--- src/platforms/mesa/server/kms/platform.cpp 2015-11-05 18:24:29 +0000
30+++ src/platforms/mesa/server/kms/platform.cpp 2015-11-09 11:17:37 +0000
31@@ -51,14 +51,16 @@
32 std::weak_ptr<VirtualTerminal> weak_vt = vt;
33 std::weak_ptr<mgmh::DRMHelper> weak_drm = drm;
34 emergency_cleanup_registry.add(
35- [weak_vt,weak_drm]
36- {
37- if (auto const vt = weak_vt.lock())
38- try { vt->restore(); } catch (...) {}
39-
40- if (auto const drm = weak_drm.lock())
41- try { drm->drop_master(); } catch (...) {}
42- });
43+ make_module_ptr<EmergencyCleanupHandler>(
44+ [weak_vt,weak_drm]
45+ {
46+ if (auto const vt = weak_vt.lock())
47+ try { vt->restore(); } catch (...) {}
48+
49+ if (auto const drm = weak_drm.lock())
50+ try { drm->drop_master(); } catch (...) {}
51+ }));
52+
53 }
54
55 mir::UniqueModulePtr<mg::GraphicBufferAllocator> mgm::Platform::create_buffer_allocator()
56
57=== modified file 'src/server/default_emergency_cleanup.cpp'
58--- src/server/default_emergency_cleanup.cpp 2014-07-03 09:46:40 +0000
59+++ src/server/default_emergency_cleanup.cpp 2015-11-09 11:17:37 +0000
60@@ -22,7 +22,16 @@
61 {
62 std::lock_guard<std::mutex> lock{handlers_mutex};
63
64- last_item()->next.reset(new ListItem{handler, nullptr});
65+ last_item()->next.reset(
66+ new ListItem{std::make_shared<EmergencyCleanupHandler>(handler), nullptr});
67+ ++num_handlers;
68+}
69+
70+void mir::DefaultEmergencyCleanup::add(ModuleEmergencyCleanupHandler handler)
71+{
72+ std::lock_guard<std::mutex> lock{handlers_mutex};
73+
74+ last_item()->next.reset(new ListItem{std::move(handler), nullptr});
75 ++num_handlers;
76 }
77
78@@ -33,7 +42,7 @@
79 while (handlers_left-- > 0)
80 {
81 item = item->next.get();
82- item->handler();
83+ (*item->handler)();
84 }
85 }
86
87
88=== modified file 'src/server/default_emergency_cleanup.h'
89--- src/server/default_emergency_cleanup.h 2015-02-22 07:46:25 +0000
90+++ src/server/default_emergency_cleanup.h 2015-11-09 11:17:37 +0000
91@@ -32,12 +32,13 @@
92 {
93 public:
94 void add(EmergencyCleanupHandler const& handler) override;
95+ void add(ModuleEmergencyCleanupHandler handler) override;
96 void operator()() const override;
97
98 private:
99 struct ListItem
100 {
101- EmergencyCleanupHandler handler;
102+ std::shared_ptr<EmergencyCleanupHandler> handler;
103 std::unique_ptr<ListItem> next;
104 };
105
106
107=== modified file 'tests/include/mir/test/doubles/null_emergency_cleanup.h'
108--- tests/include/mir/test/doubles/null_emergency_cleanup.h 2014-05-21 11:59:30 +0000
109+++ tests/include/mir/test/doubles/null_emergency_cleanup.h 2015-11-09 11:17:37 +0000
110@@ -32,6 +32,7 @@
111 {
112 public:
113 void add(EmergencyCleanupHandler const&) override {}
114+ void add(ModuleEmergencyCleanupHandler) override {}
115 void operator()() const override {}
116 };
117
118
119=== modified file 'tests/unit-tests/graphics/mesa/kms/test_platform.cpp'
120--- tests/unit-tests/graphics/mesa/kms/test_platform.cpp 2015-11-02 21:56:56 +0000
121+++ tests/unit-tests/graphics/mesa/kms/test_platform.cpp 2015-11-09 11:17:37 +0000
122@@ -235,12 +235,16 @@
123
124 struct StubEmergencyCleanupRegistry : mir::EmergencyCleanupRegistry
125 {
126- void add(mir::EmergencyCleanupHandler const& handler) override
127- {
128- this->handler = handler;
129- }
130-
131- mir::EmergencyCleanupHandler handler;
132+ void add(mir::EmergencyCleanupHandler const&) override
133+ {
134+ }
135+
136+ void add(mir::ModuleEmergencyCleanupHandler handler) override
137+ {
138+ this->handler = std::move(handler);
139+ }
140+
141+ mir::ModuleEmergencyCleanupHandler handler;
142 };
143
144 TEST_F(MesaGraphicsPlatform, restores_vt_on_emergency_cleanup)
145@@ -257,7 +261,7 @@
146
147 EXPECT_CALL(*mock_vt, restore());
148
149- emergency_cleanup_registry.handler();
150+ (*emergency_cleanup_registry.handler)();
151
152 Mock::VerifyAndClearExpectations(mock_vt.get());
153 }
154@@ -278,7 +282,7 @@
155 EXPECT_CALL(mock_drm, drmDropMaster(mock_drm.fake_drm.fd()))
156 .WillOnce(Return(success_code));
157
158- emergency_cleanup_registry.handler();
159+ (*emergency_cleanup_registry.handler)();
160
161 Mock::VerifyAndClearExpectations(&mock_drm);
162 }
163@@ -300,7 +304,7 @@
164 EXPECT_CALL(mock_drm, drmDropMaster(mock_drm.fake_drm.fd()))
165 .WillOnce(Throw(std::runtime_error("drm drop master exception")));
166
167- emergency_cleanup_registry.handler();
168+ (*emergency_cleanup_registry.handler)();
169
170 Mock::VerifyAndClearExpectations(&mock_drm);
171 }

Subscribers

People subscribed via source and target branches