Merge lp:~vanvugt/mir/simplify-single-object-accesses into lp:mir
- simplify-single-object-accesses
- Merge into development-branch
Status: | Merged |
---|---|
Approved by: | Daniel van Vugt |
Approved revision: | no longer in the source branch. |
Merged at revision: | 3877 |
Proposed branch: | lp:~vanvugt/mir/simplify-single-object-accesses |
Merge into: | lp:mir |
Diff against target: |
278 lines (+42/-89) 6 files modified
src/client/connection_surface_map.cpp (+10/-30) src/client/connection_surface_map.h (+2/-2) src/client/rpc/mir_protobuf_rpc_channel.cpp (+17/-23) src/client/surface_map.h (+2/-4) tests/unit-tests/client/test_connection_resource_map.cpp (+4/-21) tests/unit-tests/client/test_protobuf_rpc_channel.cpp (+7/-9) |
To merge this branch: | bzr merge lp:~vanvugt/mir/simplify-single-object-accesses |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Mir CI Bot | continuous-integration | Approve | |
Alan Griffiths | Approve | ||
Review via email: mp+312790@code.launchpad.net |
Commit message
Simplify SurfaceMap's single object functions.
Also make them safer and more powerful by replacing raw pointers with
shared pointers. That's the reason I need this - to get a shared
pointer.
Description of the change
Mir CI Bot (mir-ci-bot) wrote : | # |
Mir CI Bot (mir-ci-bot) wrote : | # |
PASSED: Continuous integration, rev:3875
https:/
Executed test runs:
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
Click here to trigger a rebuild:
https:/
Alan Griffiths (alan-griffiths) wrote : | # |
I'm none to familiar with this code, but the change in behaviour looks rather drastic.
Before: a ConnectionSurfa
After: ownership is being shared meaning the MirSurface can be accessed without the lock.
Far from being "safer and more powerful" it will require the reviewer to invest significant thought to ensure that the changed behaviour doesn't violate consistency assumptions made elsewhere in the code.
Why is this necessary?
Daniel van Vugt (vanvugt) wrote : | # |
The assertion that actions were previously under lock is incorrect. See:
21 - lk.unlock();
22 - exec(surface.
So this proposal does not change the locking behaviour at all.
I need this because I'm in a situation where I want each MirBufferStream to hold a weak reference to the MirSurface(s) that use it. This is required to implement client-side vsync where the clock to sync the stream's swapping to is dictated by which output the window (MirSurface) is on.
So MirBufferStream (or anything in future) wants to hold a weak_ptr to its MirSurface(s). Presently we can only store raw pointers, which is unsafe because there's no guarantee the toolkit will always destroy its streams before its surfaces. Using a shared_ptr (or weak_ptr in my case) avoids such risk. And as mentioned above the locking semantics are unchanged.
Admittedly I can work around all this and move forward in my other work but it would be a hack. What I propose here is the cleanest solution and a generally nice to have simplification.
It should also be noted this is not a new idea. It's already used in:
174 virtual std::shared_
Alan Griffiths (alan-griffiths) wrote : | # |
> The assertion that actions were previously under lock is incorrect. See:
>
> 21 - lk.unlock();
> 22 - exec(surface.
>
> So this proposal does not change the locking behaviour at all.
Yikes! The existing code is confusing: The *point* of execute-around is to run paired operations *around* the invoked code (e.g. start transaction/end transaction).
It is far too easy to make the mistake I did and assume the lock is being held. If we're not holding the lock then either /1/ there's no need for this pattern; or, /2/ releasing the lock before exec() is an existing error.
Either way, this MP doesn't break things.
Mir CI Bot (mir-ci-bot) wrote : | # |
FAILED: Autolanding.
More details in the following jenkins job:
https:/
Executed test runs:
FAILURE: https:/
None: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
Daniel van Vugt (vanvugt) wrote : | # |
^^^
Bug 1628794
Mir CI Bot (mir-ci-bot) : | # |
Preview Diff
1 | === modified file 'src/client/connection_surface_map.cpp' |
2 | --- src/client/connection_surface_map.cpp 2016-12-02 05:05:06 +0000 |
3 | +++ src/client/connection_surface_map.cpp 2016-12-08 10:07:47 +0000 |
4 | @@ -26,23 +26,15 @@ |
5 | namespace mcl=mir::client; |
6 | namespace mf=mir::frontend; |
7 | |
8 | -void mcl::ConnectionSurfaceMap::with_surface_do( |
9 | - mf::SurfaceId surface_id, std::function<void(MirSurface*)> const& exec) const |
10 | +using mir::client::ConnectionSurfaceMap; |
11 | +using mir::frontend::SurfaceId; |
12 | +using mir::frontend::BufferStreamId; |
13 | + |
14 | +std::shared_ptr<MirSurface> ConnectionSurfaceMap::surface(SurfaceId id) const |
15 | { |
16 | std::shared_lock<decltype(guard)> lk(guard); |
17 | - auto const it = surfaces.find(surface_id); |
18 | - if (it != surfaces.end()) |
19 | - { |
20 | - auto const surface = it->second; |
21 | - lk.unlock(); |
22 | - exec(surface.get()); |
23 | - } |
24 | - else |
25 | - { |
26 | - std::stringstream ss; |
27 | - ss << __PRETTY_FUNCTION__ << "executed with non-existent surface ID " << surface_id; |
28 | - BOOST_THROW_EXCEPTION(std::runtime_error(ss.str())); |
29 | - } |
30 | + auto const found = surfaces.find(id); |
31 | + return found != surfaces.end() ? found->second : nullptr; |
32 | } |
33 | |
34 | void mcl::ConnectionSurfaceMap::insert(mf::SurfaceId surface_id, std::shared_ptr<MirSurface> const& surface) |
35 | @@ -57,23 +49,11 @@ |
36 | surfaces.erase(surface_id); |
37 | } |
38 | |
39 | -void mcl::ConnectionSurfaceMap::with_stream_do( |
40 | - mf::BufferStreamId stream_id, std::function<void(MirBufferStream*)> const& exec) const |
41 | +std::shared_ptr<MirBufferStream> ConnectionSurfaceMap::stream(BufferStreamId id) const |
42 | { |
43 | std::shared_lock<decltype(stream_guard)> lk(stream_guard); |
44 | - auto const it = streams.find(stream_id); |
45 | - if (it != streams.end()) |
46 | - { |
47 | - auto const stream = it->second; |
48 | - lk.unlock(); |
49 | - exec(stream.get()); |
50 | - } |
51 | - else |
52 | - { |
53 | - std::stringstream ss; |
54 | - ss << __PRETTY_FUNCTION__ << "executed with non-existent stream ID " << stream_id; |
55 | - BOOST_THROW_EXCEPTION(std::runtime_error(ss.str())); |
56 | - } |
57 | + auto const found = streams.find(id); |
58 | + return found != streams.end() ? found->second : nullptr; |
59 | } |
60 | |
61 | void mcl::ConnectionSurfaceMap::with_all_streams_do(std::function<void(MirBufferStream*)> const& fn) const |
62 | |
63 | === modified file 'src/client/connection_surface_map.h' |
64 | --- src/client/connection_surface_map.h 2016-12-02 05:05:06 +0000 |
65 | +++ src/client/connection_surface_map.h 2016-12-08 10:07:47 +0000 |
66 | @@ -34,11 +34,11 @@ |
67 | class ConnectionSurfaceMap : public SurfaceMap |
68 | { |
69 | public: |
70 | - void with_surface_do(frontend::SurfaceId surface_id, std::function<void(MirSurface*)> const& exec) const override; |
71 | + virtual std::shared_ptr<MirSurface> surface(frontend::SurfaceId) const override; |
72 | void insert(frontend::SurfaceId surface_id, std::shared_ptr<MirSurface> const& surface); |
73 | void erase(frontend::SurfaceId surface_id); |
74 | |
75 | - void with_stream_do(frontend::BufferStreamId stream_id, std::function<void(MirBufferStream*)> const& exec) const override; |
76 | + virtual std::shared_ptr<MirBufferStream> stream(frontend::BufferStreamId) const override; |
77 | void with_all_streams_do(std::function<void(MirBufferStream*)> const&) const override; |
78 | |
79 | void insert(frontend::BufferStreamId stream_id, std::shared_ptr<MirBufferStream> const& chain); |
80 | |
81 | === modified file 'src/client/rpc/mir_protobuf_rpc_channel.cpp' |
82 | --- src/client/rpc/mir_protobuf_rpc_channel.cpp 2016-12-02 05:05:06 +0000 |
83 | +++ src/client/rpc/mir_protobuf_rpc_channel.cpp 2016-12-08 10:07:47 +0000 |
84 | @@ -312,10 +312,9 @@ |
85 | { |
86 | if (seq.buffer_request().has_id()) |
87 | { |
88 | - map->with_stream_do(mf::BufferStreamId(seq.buffer_request().id().value()), |
89 | - [&] (MirBufferStream* receiver) { |
90 | + mf::BufferStreamId stream_id(seq.buffer_request().id().value()); |
91 | + if (auto receiver = map->stream(stream_id)) |
92 | receiver->buffer_available(seq.buffer_request().buffer()); |
93 | - }); |
94 | } |
95 | |
96 | else if (seq.buffer_request().has_operation()) |
97 | @@ -372,46 +371,41 @@ |
98 | { |
99 | rpc_report->event_parsing_succeeded(*e); |
100 | |
101 | - auto const send_e = [&e](MirSurface* surface) |
102 | - { surface->handle_event(*e); }; |
103 | + int surface_id = 0; |
104 | + bool is_surface_event = true; |
105 | |
106 | switch (e->type()) |
107 | { |
108 | case mir_event_type_surface: |
109 | - if (auto map = surface_map.lock()) |
110 | - map->with_surface_do(mf::SurfaceId(e->to_surface()->id()), send_e); |
111 | + surface_id = e->to_surface()->id(); |
112 | break; |
113 | - |
114 | case mir_event_type_resize: |
115 | - if (auto map = surface_map.lock()) |
116 | - map->with_surface_do(mf::SurfaceId(e->to_resize()->surface_id()), send_e); |
117 | + surface_id = e->to_resize()->surface_id(); |
118 | break; |
119 | - |
120 | case mir_event_type_orientation: |
121 | - if (auto map = surface_map.lock()) |
122 | - map->with_surface_do(mf::SurfaceId(e->to_orientation()->surface_id()), send_e); |
123 | + surface_id = e->to_orientation()->surface_id(); |
124 | break; |
125 | - |
126 | case mir_event_type_close_surface: |
127 | - if (auto map = surface_map.lock()) |
128 | - map->with_surface_do(mf::SurfaceId(e->to_close_surface()->surface_id()), send_e); |
129 | + surface_id = e->to_close_surface()->surface_id(); |
130 | break; |
131 | case mir_event_type_keymap: |
132 | - if (auto map = surface_map.lock()) |
133 | - map->with_surface_do(mf::SurfaceId(e->to_keymap()->surface_id()), send_e); |
134 | + surface_id = e->to_keymap()->surface_id(); |
135 | break; |
136 | case mir_event_type_surface_output: |
137 | - if (auto map = surface_map.lock()) |
138 | - map->with_surface_do(mf::SurfaceId(e->to_surface_output()->surface_id()), send_e); |
139 | + surface_id = e->to_surface_output()->surface_id(); |
140 | break; |
141 | case mir_event_type_surface_placement: |
142 | - if (auto map = surface_map.lock()) |
143 | - map->with_surface_do(mf::SurfaceId(e->to_surface_placement()->id()), send_e); |
144 | + surface_id = e->to_surface_placement()->id(); |
145 | break; |
146 | - |
147 | default: |
148 | + is_surface_event = false; |
149 | event_sink->handle_event(*e); |
150 | } |
151 | + |
152 | + if (is_surface_event) |
153 | + if (auto map = surface_map.lock()) |
154 | + if (auto surf = map->surface(mf::SurfaceId(surface_id))) |
155 | + surf->handle_event(*e); |
156 | } |
157 | } |
158 | catch(...) |
159 | |
160 | === modified file 'src/client/surface_map.h' |
161 | --- src/client/surface_map.h 2016-12-02 05:05:06 +0000 |
162 | +++ src/client/surface_map.h 2016-12-08 10:07:47 +0000 |
163 | @@ -40,10 +40,8 @@ |
164 | class SurfaceMap |
165 | { |
166 | public: |
167 | - virtual void with_surface_do( |
168 | - frontend::SurfaceId surface_id, std::function<void(MirSurface*)> const& exec) const = 0; |
169 | - virtual void with_stream_do( |
170 | - frontend::BufferStreamId stream_id, std::function<void(MirBufferStream*)> const& exec) const = 0; |
171 | + virtual std::shared_ptr<MirSurface> surface(frontend::SurfaceId) const = 0; |
172 | + virtual std::shared_ptr<MirBufferStream> stream(frontend::BufferStreamId) const = 0; |
173 | virtual void with_all_streams_do(std::function<void(MirBufferStream*)> const&) const = 0; |
174 | virtual std::shared_ptr<MirBuffer> buffer(int buffer_id) const = 0; |
175 | virtual void insert(int buffer_id, std::shared_ptr<MirBuffer> const& buffer) = 0; |
176 | |
177 | === modified file 'tests/unit-tests/client/test_connection_resource_map.cpp' |
178 | --- tests/unit-tests/client/test_connection_resource_map.cpp 2016-12-02 05:05:06 +0000 |
179 | +++ tests/unit-tests/client/test_connection_resource_map.cpp 2016-12-08 10:07:47 +0000 |
180 | @@ -56,15 +56,9 @@ |
181 | TEST_F(ConnectionResourceMap, maps_surface_when_surface_inserted) |
182 | { |
183 | using namespace testing; |
184 | - auto surface_called = false; |
185 | mcl::ConnectionSurfaceMap map; |
186 | map.insert(surface_id, surface); |
187 | - map.with_surface_do(surface_id, [&](MirSurface* surf) { |
188 | - EXPECT_THAT(surf, Eq(surface.get())); |
189 | - surface_called = true; |
190 | - }); |
191 | - |
192 | - EXPECT_TRUE(surface_called); |
193 | + EXPECT_EQ(surface, map.surface(surface_id)); |
194 | } |
195 | |
196 | TEST_F(ConnectionResourceMap, removes_surface_when_surface_removed) |
197 | @@ -73,22 +67,15 @@ |
198 | mcl::ConnectionSurfaceMap map; |
199 | map.insert(surface_id, surface); |
200 | map.erase(surface_id); |
201 | - EXPECT_THROW({ |
202 | - map.with_stream_do(stream_id, [](MirBufferStream*){}); |
203 | - }, std::runtime_error); |
204 | + EXPECT_FALSE(map.stream(stream_id)); |
205 | } |
206 | |
207 | TEST_F(ConnectionResourceMap, maps_streams) |
208 | { |
209 | using namespace testing; |
210 | - auto stream_called = false; |
211 | mcl::ConnectionSurfaceMap map; |
212 | map.insert(stream_id, stream); |
213 | - map.with_stream_do(stream_id, [&](MirBufferStream* str) { |
214 | - EXPECT_THAT(str, Eq(stream.get())); |
215 | - stream_called = true; |
216 | - }); |
217 | - EXPECT_TRUE(stream_called); |
218 | + EXPECT_EQ(stream, map.stream(stream_id)); |
219 | map.erase(stream_id); |
220 | } |
221 | |
222 | @@ -126,11 +113,7 @@ |
223 | mcl::ConnectionSurfaceMap map; |
224 | map.insert(buffer_id, buffer); |
225 | map.insert(surface_id, surface); |
226 | - |
227 | - map.with_surface_do(surface_id, |
228 | - [this, &map](auto) { |
229 | - EXPECT_THAT(map.buffer(buffer_id), Eq(buffer)); |
230 | - }); |
231 | + EXPECT_EQ(buffer, map.buffer(buffer_id)); |
232 | } |
233 | |
234 | TEST_F(ConnectionResourceMap, can_insert_retrieve_erase_render_surface) |
235 | |
236 | === modified file 'tests/unit-tests/client/test_protobuf_rpc_channel.cpp' |
237 | --- tests/unit-tests/client/test_protobuf_rpc_channel.cpp 2016-12-02 05:05:06 +0000 |
238 | +++ tests/unit-tests/client/test_protobuf_rpc_channel.cpp 2016-12-08 10:07:47 +0000 |
239 | @@ -59,10 +59,8 @@ |
240 | |
241 | struct MockSurfaceMap : mcl::SurfaceMap |
242 | { |
243 | - MOCK_CONST_METHOD2(with_surface_do, |
244 | - void(mir::frontend::SurfaceId, std::function<void(MirSurface*)> const&)); |
245 | - MOCK_CONST_METHOD2(with_stream_do, |
246 | - void(mir::frontend::BufferStreamId, std::function<void(MirBufferStream*)> const&)); |
247 | + MOCK_CONST_METHOD1(surface, std::shared_ptr<MirSurface>(mir::frontend::SurfaceId)); |
248 | + MOCK_CONST_METHOD1(stream, std::shared_ptr<MirBufferStream>(mir::frontend::BufferStreamId)); |
249 | MOCK_CONST_METHOD1(with_all_streams_do, |
250 | void(std::function<void(MirBufferStream*)> const&)); |
251 | MOCK_CONST_METHOD1(buffer, std::shared_ptr<mcl::MirBuffer>(int)); |
252 | @@ -74,13 +72,13 @@ |
253 | class StubSurfaceMap : public mcl::SurfaceMap |
254 | { |
255 | public: |
256 | - void with_surface_do( |
257 | - mir::frontend::SurfaceId, std::function<void(MirSurface*)> const&) const override |
258 | + std::shared_ptr<MirSurface> surface(mir::frontend::SurfaceId) const override |
259 | { |
260 | + return {}; |
261 | } |
262 | - void with_stream_do( |
263 | - mir::frontend::BufferStreamId, std::function<void(MirBufferStream*)> const&) const override |
264 | + std::shared_ptr<MirBufferStream> stream(mir::frontend::BufferStreamId) const override |
265 | { |
266 | + return {}; |
267 | } |
268 | void with_all_streams_do(std::function<void(MirBufferStream*)> const&) const override |
269 | { |
270 | @@ -796,7 +794,7 @@ |
271 | auto mock_buffer_factory = std::make_shared<MockBufferFactory>(); |
272 | auto mock_client_buffer = std::make_shared<mtd::MockClientBuffer>(); |
273 | auto buf = std::make_shared<mcl::Buffer>(buffer_cb, nullptr, buffer_id, mock_client_buffer, nullptr, mir_buffer_usage_software); |
274 | - EXPECT_CALL(*stream_map, with_stream_do(mir::frontend::BufferStreamId{stream_id},_)) |
275 | + EXPECT_CALL(*stream_map, stream(mir::frontend::BufferStreamId{stream_id})) |
276 | .Times(1); |
277 | |
278 | auto transport = std::make_unique<NiceMock<MockStreamTransport>>(); |
FAILED: Continuous integration, rev:3874 /mir-jenkins. ubuntu. com/job/ mir-ci/ 2347/ /mir-jenkins. ubuntu. com/job/ build-mir/ 3061/console /mir-jenkins. ubuntu. com/job/ build-0- fetch/3127 /mir-jenkins. ubuntu. com/job/ build-1- sourcepkg/ release= vivid+overlay/ 3119 /mir-jenkins. ubuntu. com/job/ build-1- sourcepkg/ release= xenial+ overlay/ 3119 /mir-jenkins. ubuntu. com/job/ build-1- sourcepkg/ release= yakkety/ 3119 /mir-jenkins. ubuntu. com/job/ build-2- binpkg- mir/arch= amd64,compiler= clang,platform= mesa,release= yakkety/ 3090 /mir-jenkins. ubuntu. com/job/ build-2- binpkg- mir/arch= amd64,compiler= clang,platform= mesa,release= yakkety/ 3090/artifact/ output/ *zip*/output. zip /mir-jenkins. ubuntu. com/job/ build-2- binpkg- mir/arch= amd64,compiler= gcc,platform= mesa,release= xenial+ overlay/ 3090 /mir-jenkins. ubuntu. com/job/ build-2- binpkg- mir/arch= amd64,compiler= gcc,platform= mesa,release= xenial+ overlay/ 3090/artifact/ output/ *zip*/output. zip /mir-jenkins. ubuntu. com/job/ build-2- binpkg- mir/arch= amd64,compiler= gcc,platform= mesa,release= yakkety/ 3090 /mir-jenkins. ubuntu. com/job/ build-2- binpkg- mir/arch= amd64,compiler= gcc,platform= mesa,release= yakkety/ 3090/artifact/ output/ *zip*/output. zip /mir-jenkins. ubuntu. com/job/ build-2- binpkg- mir/arch= cross-armhf, compiler= gcc,platform= android, release= vivid+overlay/ 3090 /mir-jenkins. ubuntu. com/job/ build-2- binpkg- mir/arch= cross-armhf, compiler= gcc,platform= android, release= vivid+overlay/ 3090/artifact/ output/ *zip*/output. zip /mir-jenkins. ubuntu. com/job/ build-2- binpkg- mir/arch= i386,compiler= gcc,platform= android, release= vivid+overlay/ 3090 /mir-jenkins. ubuntu. com/job/ build-2- binpkg- mir/arch= i386,compiler= gcc,platform= android, release= vivid+overlay/ 3090/artifact/ output/ *zip*/output. zip /mir-jenkins. ubuntu. com/job/ build-2- binpkg- mir/arch= i386,compiler= gcc,platform= mesa,release= xenial+ overlay/ 3090/console
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
Click here to trigger a rebuild: /mir-jenkins. ubuntu. com/job/ mir-ci/ 2347/rebuild
https:/