Merge lp:~kdub/mir/sort-out-surface-ownership into lp:mir
- sort-out-surface-ownership
- Merge into development-branch
Status: | Merged |
---|---|
Approved by: | Chris Halse Rogers |
Approved revision: | no longer in the source branch. |
Merged at revision: | 3240 |
Proposed branch: | lp:~kdub/mir/sort-out-surface-ownership |
Merge into: | lp:mir |
Diff against target: |
1129 lines (+331/-299) 11 files modified
src/client/connection_surface_map.h (+2/-2) src/client/mir_connection.cpp (+186/-18) src/client/mir_connection.h (+27/-4) src/client/mir_surface.cpp (+31/-179) src/client/mir_surface.h (+16/-14) src/client/mir_surface_api.cpp (+2/-4) src/client/surface_map.cpp (+4/-10) src/client/surface_map.h (+1/-0) tests/unit-tests/client/test_client_mir_surface.cpp (+20/-61) tests/unit-tests/client/test_connection_resource_map.cpp (+7/-6) tests/unit-tests/client/test_mir_connection.cpp (+35/-1) |
To merge this branch: | bzr merge lp:~kdub/mir/sort-out-surface-ownership |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Chris Halse Rogers | Approve | ||
Alberto Aguirre (community) | Approve | ||
PS Jenkins bot (community) | continuous-integration | Approve | |
Mir CI Bot | continuous-integration | Approve | |
Alan Griffiths | Approve | ||
Review via email: mp+280481@code.launchpad.net |
Commit message
client: sort out the lifetime and ownership of MirSurface. The MirSurface lifetimes are now managed by MirConnection, and SurfaceMap is where MirConnection stores the surfaces.
Previously, they were imperfectly managed by SurfaceMap, eg, MirSurface would call "delete this" on itself. This led to scenarios where SurfaceMap wasn't really sure if the surface was alive or dead. Since NBS increases the amount of Events being sent to the surface, this would tease out existing problems with this scenario around surface destruction more.
Description of the change
client: sort out the lifetime and ownership of MirSurface. The MirSurface lifetimes are now managed by MirConnection, and SurfaceMap is where MirConnection stores the surfaces.
Previously, they were imperfectly managed by SurfaceMap, eg, MirSurface would call "delete this" on itself sometimes. This led to scenarios where SurfaceMap wasn't really sure if the surface was alive or dead. Since NBS increases the amount of Events being sent to the surface, this would tease out existing problems with this scenario around surface destruction more.
I'll probably do something similar with BufferStream to reduce complexity even more (eg, SurfaceMap won't auto-add bufferstreams, and the funny deletion around l725 won't be needed anymore).
PS Jenkins bot (ps-jenkins) wrote : | # |
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:3197
http://
Executed test runs:
SUCCESS: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:3198
http://
Executed test runs:
SUCCESS: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:3201
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
FAILURE: http://
FAILURE: http://
SUCCESS: http://
deb: http://
FAILURE: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Kevin DuBois (kdub) wrote : | # |
^still a FD leak for me to track down, probably on monday
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:3203
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Alan Griffiths (alan-griffiths) wrote : | # |
-TEST_F(
Is this test no longer relevant?
Kevin DuBois (kdub) wrote : | # |
Its more of a test of the wait handle, and the logic for creating a surface has moved to the MirConnection. I suppose I can port the test over instead of just removing it
Kevin DuBois (kdub) wrote : | # |
I think a case can be made for the removal of the test, but porting the test over was easy too.
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:3205
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Alan Griffiths (alan-griffiths) wrote : | # |
OK. (I'm not entirely convinced it is needed, but I don't see any harm.)
Mir CI Bot (mir-ci-bot) wrote : | # |
PASSED: Continuous integration, rev:3205
https:/
Executed test runs:
None: https:/
Click here to trigger a rebuild:
https:/
Chris Halse Rogers (raof) wrote : | # |
127 + std::lock_
...
136 + callback(
You're calling into client code with an internal mutex called. That's generally a bad idea, and I think it will deadlock under plausible client usage - MirConnection:
716 + //a bit batty, but the creation handle has to exist for as long as the MirSurface does,
717 + //as we don't really manage the lifetime of MirWaitHandle sensibly.
718 + std::shared_
I'd prefer a unique_ptr here, but that's stylistic rather than blocking.
Also, is this constraint sufficiently strong? Answer: Huh, that's the current behaviour. YAY MirWaitHandle!
Kevin DuBois (kdub) wrote : | # |
@Chris, good catch, fixed the callback during the exception catching scenario. I kept the wait handle a shared ptr, was a bit easier to call at the appropriate time.
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:3209
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Mir CI Bot (mir-ci-bot) wrote : | # |
PASSED: Continuous integration, rev:3209
https:/
Executed test runs:
None: https:/
Click here to trigger a rebuild:
https:/
Alberto Aguirre (albaguirre) wrote : | # |
+ if (strncmp(
Could just be if(!mir_
Kevin DuBois (kdub) wrote : | # |
@Alberto, fixed
Mir CI Bot (mir-ci-bot) wrote : | # |
PASSED: Continuous integration, rev:3212
https:/
Executed test runs:
None: https:/
Click here to trigger a rebuild:
https:/
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:3212
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Preview Diff
1 | === modified file 'src/client/connection_surface_map.h' |
2 | --- src/client/connection_surface_map.h 2015-12-15 12:24:10 +0000 |
3 | +++ src/client/connection_surface_map.h 2016-01-13 19:10:37 +0000 |
4 | @@ -40,7 +40,7 @@ |
5 | ~ConnectionSurfaceMap() noexcept; |
6 | |
7 | void with_surface_do(frontend::SurfaceId surface_id, std::function<void(MirSurface*)> const& exec) const override; |
8 | - void insert(frontend::SurfaceId surface_id, MirSurface* surface); |
9 | + void insert(frontend::SurfaceId surface_id, std::shared_ptr<MirSurface> const& surface); |
10 | void erase(frontend::SurfaceId surface_id); |
11 | |
12 | void with_stream_do(frontend::BufferStreamId stream_id, std::function<void(ClientBufferStream*)> const& exec) const override; |
13 | @@ -50,7 +50,7 @@ |
14 | |
15 | private: |
16 | std::shared_timed_mutex mutable guard; |
17 | - std::unordered_map<frontend::SurfaceId, MirSurface*> surfaces; |
18 | + std::unordered_map<frontend::SurfaceId, std::shared_ptr<MirSurface>> surfaces; |
19 | std::unordered_map<frontend::BufferStreamId, StreamInfo> streams; |
20 | }; |
21 | |
22 | |
23 | === modified file 'src/client/mir_connection.cpp' |
24 | --- src/client/mir_connection.cpp 2016-01-04 07:26:59 +0000 |
25 | +++ src/client/mir_connection.cpp 2016-01-13 19:10:37 +0000 |
26 | @@ -53,6 +53,76 @@ |
27 | |
28 | namespace |
29 | { |
30 | +mir::protobuf::SurfaceParameters serialize_spec(MirSurfaceSpec const& spec) |
31 | +{ |
32 | + mp::SurfaceParameters message; |
33 | + |
34 | +#define SERIALIZE_OPTION_IF_SET(option) \ |
35 | + if (spec.option.is_set()) \ |
36 | + message.set_##option(spec.option.value()); |
37 | + |
38 | + SERIALIZE_OPTION_IF_SET(width); |
39 | + SERIALIZE_OPTION_IF_SET(height); |
40 | + SERIALIZE_OPTION_IF_SET(pixel_format); |
41 | + SERIALIZE_OPTION_IF_SET(buffer_usage); |
42 | + SERIALIZE_OPTION_IF_SET(surface_name); |
43 | + SERIALIZE_OPTION_IF_SET(output_id); |
44 | + SERIALIZE_OPTION_IF_SET(type); |
45 | + SERIALIZE_OPTION_IF_SET(state); |
46 | + SERIALIZE_OPTION_IF_SET(pref_orientation); |
47 | + SERIALIZE_OPTION_IF_SET(edge_attachment); |
48 | + SERIALIZE_OPTION_IF_SET(min_width); |
49 | + SERIALIZE_OPTION_IF_SET(min_height); |
50 | + SERIALIZE_OPTION_IF_SET(max_width); |
51 | + SERIALIZE_OPTION_IF_SET(max_height); |
52 | + SERIALIZE_OPTION_IF_SET(width_inc); |
53 | + SERIALIZE_OPTION_IF_SET(height_inc); |
54 | + // min_aspect is a special case (below) |
55 | + // max_aspect is a special case (below) |
56 | + |
57 | + if (spec.parent.is_set() && spec.parent.value() != nullptr) |
58 | + message.set_parent_id(spec.parent.value()->id()); |
59 | + |
60 | + if (spec.parent_id) |
61 | + { |
62 | + auto id = message.mutable_parent_persistent_id(); |
63 | + id->set_value(spec.parent_id->as_string()); |
64 | + } |
65 | + |
66 | + if (spec.aux_rect.is_set()) |
67 | + { |
68 | + message.mutable_aux_rect()->set_left(spec.aux_rect.value().left); |
69 | + message.mutable_aux_rect()->set_top(spec.aux_rect.value().top); |
70 | + message.mutable_aux_rect()->set_width(spec.aux_rect.value().width); |
71 | + message.mutable_aux_rect()->set_height(spec.aux_rect.value().height); |
72 | + } |
73 | + |
74 | + if (spec.min_aspect.is_set()) |
75 | + { |
76 | + message.mutable_min_aspect()->set_width(spec.min_aspect.value().width); |
77 | + message.mutable_min_aspect()->set_height(spec.min_aspect.value().height); |
78 | + } |
79 | + |
80 | + if (spec.max_aspect.is_set()) |
81 | + { |
82 | + message.mutable_max_aspect()->set_width(spec.max_aspect.value().width); |
83 | + message.mutable_max_aspect()->set_height(spec.max_aspect.value().height); |
84 | + } |
85 | + |
86 | + if (spec.input_shape.is_set()) |
87 | + { |
88 | + for (auto const& rect : spec.input_shape.value()) |
89 | + { |
90 | + auto const new_shape = message.add_input_shape(); |
91 | + new_shape->set_left(rect.left); |
92 | + new_shape->set_top(rect.top); |
93 | + new_shape->set_width(rect.width); |
94 | + new_shape->set_height(rect.height); |
95 | + } |
96 | + } |
97 | + |
98 | + return message; |
99 | +} |
100 | |
101 | class MirDisplayConfigurationStore |
102 | { |
103 | @@ -175,10 +245,106 @@ |
104 | mir_surface_callback callback, |
105 | void * context) |
106 | { |
107 | - auto surface = new MirSurface(this, server, &debug, buffer_stream_factory, |
108 | - input_platform, spec, callback, context); |
109 | - |
110 | - return surface->get_create_wait_handle(); |
111 | + auto response = std::make_shared<mp::Surface>(); |
112 | + auto c = std::make_shared<MirConnection::SurfaceCreationRequest>(callback, context, spec); |
113 | + c->wh->expect_result(); |
114 | + auto const message = serialize_spec(spec); |
115 | + { |
116 | + std::lock_guard<decltype(mutex)> lock(mutex); |
117 | + surface_requests.emplace_back(c); |
118 | + } |
119 | + |
120 | + try |
121 | + { |
122 | + server.create_surface(&message, c->response.get(), |
123 | + gp::NewCallback(this, &MirConnection::surface_created, c.get())); |
124 | + } |
125 | + catch (std::exception const& ex) |
126 | + { |
127 | + std::unique_lock<decltype(mutex)> lock(mutex); |
128 | + auto request = std::find_if(surface_requests.begin(), surface_requests.end(), |
129 | + [&](std::shared_ptr<MirConnection::SurfaceCreationRequest> c2) { return c.get() == c2.get(); }); |
130 | + if (request != surface_requests.end()) |
131 | + { |
132 | + auto id = next_error_id(lock); |
133 | + auto surf = std::make_shared<MirSurface>( |
134 | + std::string{"Error creating surface: "} + boost::diagnostic_information(ex), this, id, (*request)->wh); |
135 | + surface_map->insert(id, surf); |
136 | + auto wh = (*request)->wh; |
137 | + surface_requests.erase(request); |
138 | + |
139 | + lock.unlock(); |
140 | + callback(surf.get(), context); |
141 | + wh->result_received(); |
142 | + } |
143 | + } |
144 | + return c->wh.get(); |
145 | +} |
146 | + |
147 | +mf::SurfaceId MirConnection::next_error_id(std::unique_lock<std::mutex> const&) |
148 | +{ |
149 | + return mf::SurfaceId{surface_error_id--}; |
150 | +} |
151 | + |
152 | +void MirConnection::surface_created(SurfaceCreationRequest* request) |
153 | +{ |
154 | + std::unique_lock<decltype(mutex)> lock(mutex); |
155 | + std::shared_ptr<MirSurface> surf {nullptr}; |
156 | + std::shared_ptr<mcl::ClientBufferStream> stream {nullptr}; |
157 | + //make sure this request actually was made. |
158 | + auto request_it = std::find_if(surface_requests.begin(), surface_requests.end(), |
159 | + [&request](std::shared_ptr<MirConnection::SurfaceCreationRequest> r){ return request == r.get(); }); |
160 | + if (request_it == surface_requests.end()) |
161 | + return; |
162 | + |
163 | + auto surface_proto = request->response; |
164 | + auto callback = request->cb; |
165 | + auto context = request->context; |
166 | + auto const& spec = request->spec; |
167 | + |
168 | + try |
169 | + { |
170 | + stream = buffer_stream_factory->make_producer_stream( |
171 | + this, server, surface_proto->buffer_stream(), std::string{}, |
172 | + {surface_proto->width(), surface_proto->height()}); |
173 | + } |
174 | + catch (std::exception const& error) |
175 | + { |
176 | + if (!surface_proto->has_error()) |
177 | + surface_proto->set_error(error.what()); |
178 | + // failed to create buffer_stream, so clean up FDs it doesn't own |
179 | + for (auto i = 0; i < surface_proto->fd_size(); i++) |
180 | + ::close(surface_proto->fd(i)); |
181 | + if (surface_proto->has_buffer_stream() && surface_proto->buffer_stream().has_buffer()) |
182 | + for (int i = 0; i < surface_proto->buffer_stream().buffer().fd_size(); i++) |
183 | + ::close(surface_proto->buffer_stream().buffer().fd(i)); |
184 | + } |
185 | + |
186 | + if (surface_proto->has_error() || !surface_proto->has_id()) |
187 | + { |
188 | + std::string reason; |
189 | + if (surface_proto->has_error()) |
190 | + reason += surface_proto->error(); |
191 | + if (surface_proto->has_error() && !surface_proto->has_id()) |
192 | + reason += " and "; |
193 | + if (!surface_proto->has_id()) |
194 | + reason += "Server assigned surface no id"; |
195 | + auto id = next_error_id(lock); |
196 | + surf = std::make_shared<MirSurface>(reason, this, id, request->wh); |
197 | + surface_map->insert(id, surf); |
198 | + } |
199 | + else |
200 | + { |
201 | + surf = std::make_shared<MirSurface>( |
202 | + this, server, &debug, stream, input_platform, spec, *surface_proto, request->wh); |
203 | + |
204 | + surface_map->insert(mf::SurfaceId{surface_proto->id().value()}, surf); |
205 | + } |
206 | + |
207 | + callback(surf.get(), context); |
208 | + request->wh->result_received(); |
209 | + |
210 | + surface_requests.erase(request_it); |
211 | } |
212 | |
213 | char const * MirConnection::get_error_message() |
214 | @@ -228,9 +394,7 @@ |
215 | |
216 | void MirConnection::released(SurfaceRelease data) |
217 | { |
218 | - surface_map->erase(mf::SurfaceId(data.surface->id())); |
219 | - |
220 | - // Erasing this surface from surface_map means that it will no longer receive events |
221 | + // releasing this surface from surface_map means that it will no longer receive events |
222 | // If it's still focused, send an unfocused event before we kill it entirely |
223 | if (data.surface->attrib(mir_surface_attrib_focus) == mir_surface_focused) |
224 | { |
225 | @@ -239,7 +403,7 @@ |
226 | } |
227 | data.callback(data.surface, data.context); |
228 | data.handle->result_received(); |
229 | - delete data.surface; |
230 | + surface_map->erase(mf::SurfaceId(data.surface->id())); |
231 | } |
232 | |
233 | MirWaitHandle* MirConnection::release_surface( |
234 | @@ -248,17 +412,26 @@ |
235 | void * context) |
236 | { |
237 | auto new_wait_handle = new MirWaitHandle; |
238 | + { |
239 | + std::lock_guard<decltype(release_wait_handle_guard)> rel_lock(release_wait_handle_guard); |
240 | + release_wait_handles.push_back(new_wait_handle); |
241 | + } |
242 | + |
243 | + if (!mir_surface_is_valid(surface)) |
244 | + { |
245 | + new_wait_handle->expect_result(); |
246 | + new_wait_handle->result_received(); |
247 | + callback(surface, context); |
248 | + auto id = surface->id(); |
249 | + surface_map->erase(mf::SurfaceId(id)); |
250 | + return new_wait_handle; |
251 | + } |
252 | |
253 | SurfaceRelease surf_release{surface, new_wait_handle, callback, context}; |
254 | |
255 | mp::SurfaceId message; |
256 | message.set_value(surface->id()); |
257 | |
258 | - { |
259 | - std::lock_guard<decltype(release_wait_handle_guard)> rel_lock(release_wait_handle_guard); |
260 | - release_wait_handles.push_back(new_wait_handle); |
261 | - } |
262 | - |
263 | new_wait_handle->expect_result(); |
264 | server.release_surface(&message, void_response.get(), |
265 | gp::NewCallback(this, &MirConnection::released, surf_release)); |
266 | @@ -537,11 +710,6 @@ |
267 | surface_map->insert(mf::BufferStreamId(id), stream); |
268 | } |
269 | |
270 | -void MirConnection::on_surface_created(int id, MirSurface* surface) |
271 | -{ |
272 | - surface_map->insert(mf::SurfaceId(id), surface); |
273 | -} |
274 | - |
275 | void MirConnection::register_lifecycle_event_callback(mir_lifecycle_event_callback callback, void* context) |
276 | { |
277 | lifecycle_control->set_callback(std::bind(callback, this, std::placeholders::_1, context)); |
278 | |
279 | === modified file 'src/client/mir_connection.h' |
280 | --- src/client/mir_connection.h 2016-01-04 21:41:00 +0000 |
281 | +++ src/client/mir_connection.h 2016-01-13 19:10:37 +0000 |
282 | @@ -26,8 +26,10 @@ |
283 | |
284 | #include "mir/geometry/size.h" |
285 | #include "mir/client_platform.h" |
286 | +#include "mir/frontend/surface_id.h" |
287 | #include "mir/client_context.h" |
288 | #include "mir_toolkit/mir_client_library.h" |
289 | +#include "mir_surface.h" |
290 | |
291 | #include <atomic> |
292 | #include <memory> |
293 | @@ -100,9 +102,9 @@ |
294 | mir_surface_callback callback, |
295 | void * context); |
296 | MirWaitHandle* release_surface( |
297 | - MirSurface *surface, |
298 | - mir_surface_callback callback, |
299 | - void *context); |
300 | + MirSurface *surface, |
301 | + mir_surface_callback callback, |
302 | + void *context); |
303 | |
304 | MirPromptSession* create_prompt_session(); |
305 | |
306 | @@ -152,7 +154,6 @@ |
307 | EGLNativeDisplayType egl_native_display(); |
308 | MirPixelFormat egl_pixel_format(EGLDisplay, EGLConfig) const; |
309 | |
310 | - void on_surface_created(int id, MirSurface* surface); |
311 | void on_stream_created(int id, mir::client::ClientBufferStream* stream); |
312 | |
313 | MirWaitHandle* configure_display(MirDisplayConfiguration* configuration); |
314 | @@ -167,9 +168,28 @@ |
315 | } |
316 | |
317 | mir::client::rpc::DisplayServer& display_server(); |
318 | + mir::client::rpc::DisplayServerDebug& debug_display_server(); |
319 | std::shared_ptr<mir::logging::Logger> const& the_logger() const; |
320 | |
321 | private: |
322 | + //google cant have callbacks with more than 2 args |
323 | + struct SurfaceCreationRequest |
324 | + { |
325 | + SurfaceCreationRequest(mir_surface_callback cb, void* context, MirSurfaceSpec const& spec) : |
326 | + cb(cb), context(context), spec(spec), |
327 | + response(std::make_shared<mir::protobuf::Surface>()), |
328 | + wh(std::make_shared<MirWaitHandle>()) |
329 | + { |
330 | + } |
331 | + mir_surface_callback cb; |
332 | + void* context; |
333 | + MirSurfaceSpec const spec; |
334 | + std::shared_ptr<mir::protobuf::Surface> response; |
335 | + std::shared_ptr<MirWaitHandle> wh; |
336 | + }; |
337 | + std::vector<std::shared_ptr<SurfaceCreationRequest>> surface_requests; |
338 | + void surface_created(SurfaceCreationRequest*); |
339 | + |
340 | void populate_server_package(MirPlatformPackage& platform_package) override; |
341 | // MUST be first data member so it is destroyed last. |
342 | struct Deregisterer |
343 | @@ -191,6 +211,9 @@ |
344 | std::unique_ptr<mir::protobuf::Void> set_base_display_configuration_response; |
345 | std::atomic<bool> disconnecting{false}; |
346 | |
347 | + mir::frontend::SurfaceId next_error_id(std::unique_lock<std::mutex> const&); |
348 | + int surface_error_id{-1}; |
349 | + |
350 | std::shared_ptr<mir::client::ClientPlatformFactory> const client_platform_factory; |
351 | std::shared_ptr<mir::client::ClientPlatform> platform; |
352 | std::shared_ptr<EGLNativeDisplayType> native_display; |
353 | |
354 | === modified file 'src/client/mir_surface.cpp' |
355 | --- src/client/mir_surface.cpp 2015-12-17 15:58:42 +0000 |
356 | +++ src/client/mir_surface.cpp 2016-01-13 19:10:37 +0000 |
357 | @@ -49,77 +49,6 @@ |
358 | { |
359 | std::mutex handle_mutex; |
360 | std::unordered_set<MirSurface*> valid_surfaces; |
361 | - |
362 | -mir::protobuf::SurfaceParameters serialize_spec(MirSurfaceSpec const& spec) |
363 | -{ |
364 | - mp::SurfaceParameters message; |
365 | - |
366 | -#define SERIALIZE_OPTION_IF_SET(option) \ |
367 | - if (spec.option.is_set()) \ |
368 | - message.set_##option(spec.option.value()); |
369 | - |
370 | - SERIALIZE_OPTION_IF_SET(width); |
371 | - SERIALIZE_OPTION_IF_SET(height); |
372 | - SERIALIZE_OPTION_IF_SET(pixel_format); |
373 | - SERIALIZE_OPTION_IF_SET(buffer_usage); |
374 | - SERIALIZE_OPTION_IF_SET(surface_name); |
375 | - SERIALIZE_OPTION_IF_SET(output_id); |
376 | - SERIALIZE_OPTION_IF_SET(type); |
377 | - SERIALIZE_OPTION_IF_SET(state); |
378 | - SERIALIZE_OPTION_IF_SET(pref_orientation); |
379 | - SERIALIZE_OPTION_IF_SET(edge_attachment); |
380 | - SERIALIZE_OPTION_IF_SET(min_width); |
381 | - SERIALIZE_OPTION_IF_SET(min_height); |
382 | - SERIALIZE_OPTION_IF_SET(max_width); |
383 | - SERIALIZE_OPTION_IF_SET(max_height); |
384 | - SERIALIZE_OPTION_IF_SET(width_inc); |
385 | - SERIALIZE_OPTION_IF_SET(height_inc); |
386 | - // min_aspect is a special case (below) |
387 | - // max_aspect is a special case (below) |
388 | - |
389 | - if (spec.parent.is_set() && spec.parent.value() != nullptr) |
390 | - message.set_parent_id(spec.parent.value()->id()); |
391 | - |
392 | - if (spec.parent_id) |
393 | - { |
394 | - auto id = message.mutable_parent_persistent_id(); |
395 | - id->set_value(spec.parent_id->as_string()); |
396 | - } |
397 | - |
398 | - if (spec.aux_rect.is_set()) |
399 | - { |
400 | - message.mutable_aux_rect()->set_left(spec.aux_rect.value().left); |
401 | - message.mutable_aux_rect()->set_top(spec.aux_rect.value().top); |
402 | - message.mutable_aux_rect()->set_width(spec.aux_rect.value().width); |
403 | - message.mutable_aux_rect()->set_height(spec.aux_rect.value().height); |
404 | - } |
405 | - |
406 | - if (spec.min_aspect.is_set()) |
407 | - { |
408 | - message.mutable_min_aspect()->set_width(spec.min_aspect.value().width); |
409 | - message.mutable_min_aspect()->set_height(spec.min_aspect.value().height); |
410 | - } |
411 | - |
412 | - if (spec.max_aspect.is_set()) |
413 | - { |
414 | - message.mutable_max_aspect()->set_width(spec.max_aspect.value().width); |
415 | - message.mutable_max_aspect()->set_height(spec.max_aspect.value().height); |
416 | - } |
417 | - |
418 | - if (spec.input_shape.is_set()) |
419 | - { |
420 | - for (auto const& rect : spec.input_shape.value()) |
421 | - { |
422 | - auto const new_shape = message.add_input_shape(); |
423 | - new_shape->set_left(rect.left); |
424 | - new_shape->set_top(rect.top); |
425 | - new_shape->set_width(rect.width); |
426 | - new_shape->set_height(rect.height); |
427 | - } |
428 | - } |
429 | - |
430 | - return message; |
431 | -} |
432 | } |
433 | |
434 | MirSurfaceSpec::MirSurfaceSpec( |
435 | @@ -159,10 +88,17 @@ |
436 | return string_id; |
437 | } |
438 | |
439 | -MirSurface::MirSurface(std::string const& error) |
440 | - : surface{mcl::make_protobuf_object<mir::protobuf::Surface>()} |
441 | +MirSurface::MirSurface( |
442 | + std::string const& error, |
443 | + MirConnection* conn, |
444 | + mir::frontend::SurfaceId id, |
445 | + std::shared_ptr<MirWaitHandle> const& handle) : |
446 | + surface{mcl::make_protobuf_object<mir::protobuf::Surface>()}, |
447 | + connection_(conn), |
448 | + creation_handle(handle) |
449 | { |
450 | surface->set_error(error); |
451 | + surface->mutable_id()->set_value(id.as_value()); |
452 | |
453 | std::lock_guard<decltype(handle_mutex)> lock(handle_mutex); |
454 | valid_surfaces.insert(this); |
455 | @@ -172,25 +108,30 @@ |
456 | MirConnection *allocating_connection, |
457 | mclr::DisplayServer& the_server, |
458 | mclr::DisplayServerDebug* debug, |
459 | - std::shared_ptr<mcl::ClientBufferStreamFactory> const& buffer_stream_factory, |
460 | + std::shared_ptr<mcl::ClientBufferStream> const& buffer_stream, |
461 | std::shared_ptr<mircv::InputPlatform> const& input_platform, |
462 | MirSurfaceSpec const& spec, |
463 | - mir_surface_callback callback, void * context) |
464 | + mir::protobuf::Surface const& surface_proto, |
465 | + std::shared_ptr<MirWaitHandle> const& handle) |
466 | : server{&the_server}, |
467 | debug{debug}, |
468 | - surface{mcl::make_protobuf_object<mir::protobuf::Surface>()}, |
469 | + surface{mcl::make_protobuf_object<mir::protobuf::Surface>(surface_proto)}, |
470 | persistent_id{mcl::make_protobuf_object<mir::protobuf::PersistentSurfaceId>()}, |
471 | name{spec.surface_name.is_set() ? spec.surface_name.value() : ""}, |
472 | void_response{mcl::make_protobuf_object<mir::protobuf::Void>()}, |
473 | modify_result{mcl::make_protobuf_object<mir::protobuf::Void>()}, |
474 | - connection(allocating_connection), |
475 | - buffer_stream_factory(buffer_stream_factory), |
476 | + connection_(allocating_connection), |
477 | + buffer_stream(buffer_stream), |
478 | input_platform(input_platform), |
479 | keymapper(std::make_shared<mircv::XKBMapper>()), |
480 | - configure_result{mcl::make_protobuf_object<mir::protobuf::SurfaceSetting>()} |
481 | + configure_result{mcl::make_protobuf_object<mir::protobuf::SurfaceSetting>()}, |
482 | + creation_handle(handle) |
483 | { |
484 | - for (int i = 0; i < mir_surface_attribs; i++) |
485 | - attrib_cache[i] = -1; |
486 | + for(int i = 0; i < surface_proto.attributes_size(); i++) |
487 | + { |
488 | + auto const& attrib = surface_proto.attributes(i); |
489 | + attrib_cache[attrib.attrib()] = attrib.ivalue(); |
490 | + } |
491 | |
492 | if (spec.event_handler.is_set()) |
493 | { |
494 | @@ -201,16 +142,10 @@ |
495 | spec.event_handler.value().context); |
496 | } |
497 | |
498 | - auto const message = serialize_spec(spec); |
499 | - create_wait_handle.expect_result(); |
500 | - try |
501 | - { |
502 | - server->create_surface(&message, surface.get(), gp::NewCallback(this, &MirSurface::created, callback, context)); |
503 | - } |
504 | - catch (std::exception const& ex) |
505 | - { |
506 | - surface->set_error(std::string{"Error invoking create surface: "} + |
507 | - boost::diagnostic_information(ex)); |
508 | + if (surface_proto.fd_size() > 0 && handle_event_callback) |
509 | + { |
510 | + input_thread = std::make_shared<md::ThreadedDispatcher>("Input dispatch", |
511 | + input_platform->create_input_receiver( surface_proto.fd(0), keymapper, handle_event_callback)); |
512 | } |
513 | |
514 | std::lock_guard<decltype(handle_mutex)> lock(handle_mutex); |
515 | @@ -303,11 +238,6 @@ |
516 | return &persistent_id_wait_handle; |
517 | } |
518 | |
519 | -MirWaitHandle* MirSurface::get_create_wait_handle() |
520 | -{ |
521 | - return &create_wait_handle; |
522 | -} |
523 | - |
524 | /* todo: all these conversion functions are a bit of a kludge, probably |
525 | better to have a more developed MirPixelFormat that can handle this */ |
526 | MirPixelFormat MirSurface::convert_ipc_pf_to_geometry(gp::int32 pf) const |
527 | @@ -315,89 +245,6 @@ |
528 | return static_cast<MirPixelFormat>(pf); |
529 | } |
530 | |
531 | -void MirSurface::created(mir_surface_callback callback, void * context) |
532 | -{ |
533 | - { |
534 | - std::lock_guard<decltype(mutex)> lock(mutex); |
535 | - if (!surface->has_id()) |
536 | - { |
537 | - if (!surface->has_error()) |
538 | - surface->set_error("Error processing surface create response, no ID (disconnected?)"); |
539 | - |
540 | - callback(this, context); |
541 | - create_wait_handle.result_received(); |
542 | - return; |
543 | - } |
544 | - } |
545 | - try |
546 | - { |
547 | - { |
548 | - geom::Size size{surface->width(), surface->height()}; |
549 | - auto stream = buffer_stream_factory-> |
550 | - make_producer_stream(connection, *server, surface->buffer_stream(), name, size); |
551 | - |
552 | - std::lock_guard<decltype(mutex)> lock(mutex); |
553 | - buffer_stream = std::move(stream); |
554 | - for(int i = 0; i < surface->attributes_size(); i++) |
555 | - { |
556 | - auto const& attrib = surface->attributes(i); |
557 | - attrib_cache[attrib.attrib()] = attrib.ivalue(); |
558 | - } |
559 | - } |
560 | - |
561 | - connection->on_surface_created(id(), this); |
562 | - } |
563 | - catch (std::exception const& error) |
564 | - { |
565 | - // failed to create buffer_stream, so clean up FDs it doesn't own |
566 | - if (!buffer_stream) |
567 | - for (int i = 0; i < surface->buffer_stream().buffer().fd_size(); i++) |
568 | - ::close(surface->buffer_stream().buffer().fd(i)); |
569 | - |
570 | - surface->set_error(std::string{"Error processing Surface creating response:"} + |
571 | - boost::diagnostic_information(error)); |
572 | - } |
573 | - |
574 | - if (surface->fd_size() > 0 && handle_event_callback) |
575 | - { |
576 | - auto input_dispatcher = input_platform->create_input_receiver(surface->fd(0), |
577 | - keymapper, |
578 | - handle_event_callback); |
579 | - input_thread = std::make_shared<md::ThreadedDispatcher>("Input dispatch", input_dispatcher); |
580 | - } |
581 | - |
582 | - callback(this, context); |
583 | - create_wait_handle.result_received(); |
584 | -} |
585 | - |
586 | -MirWaitHandle* MirSurface::release_surface( |
587 | - mir_surface_callback callback, |
588 | - void * context) |
589 | -{ |
590 | - bool was_valid = false; |
591 | - { |
592 | - std::lock_guard<decltype(handle_mutex)> lock(handle_mutex); |
593 | - if (valid_surfaces.count(this)) |
594 | - was_valid = true; |
595 | - valid_surfaces.erase(this); |
596 | - } |
597 | - if (this->surface->has_error()) |
598 | - was_valid = false; |
599 | - |
600 | - MirWaitHandle* wait_handle{nullptr}; |
601 | - if (connection && was_valid) |
602 | - { |
603 | - wait_handle = connection->release_surface(this, callback, context); |
604 | - } |
605 | - else |
606 | - { |
607 | - callback(this, context); |
608 | - delete this; |
609 | - } |
610 | - |
611 | - return wait_handle; |
612 | -} |
613 | - |
614 | MirWaitHandle* MirSurface::configure_cursor(MirCursorConfiguration const* cursor) |
615 | { |
616 | mp::CursorSetting setting; |
617 | @@ -779,3 +626,8 @@ |
618 | |
619 | return &modify_wait_handle; |
620 | } |
621 | + |
622 | +MirConnection* MirSurface::connection() const |
623 | +{ |
624 | + return connection_; |
625 | +} |
626 | |
627 | === modified file 'src/client/mir_surface.h' |
628 | --- src/client/mir_surface.h 2015-12-17 15:51:08 +0000 |
629 | +++ src/client/mir_surface.h 2016-01-13 19:10:37 +0000 |
630 | @@ -25,6 +25,7 @@ |
631 | #include "rpc/mir_display_server_debug.h" |
632 | |
633 | #include "mir/client_platform.h" |
634 | +#include "mir/frontend/surface_id.h" |
635 | #include "mir/optional_value.h" |
636 | #include "mir/geometry/dimensions.h" |
637 | #include "mir_toolkit/common.h" |
638 | @@ -100,7 +101,7 @@ |
639 | mir::optional_value<MirOrientationMode> pref_orientation; |
640 | |
641 | mir::optional_value<MirSurface*> parent; |
642 | - std::unique_ptr<MirPersistentId> parent_id; |
643 | + std::shared_ptr<MirPersistentId> parent_id; |
644 | mir::optional_value<MirRectangle> aux_rect; |
645 | mir::optional_value<MirEdgeAttachment> edge_attachment; |
646 | |
647 | @@ -140,28 +141,27 @@ |
648 | MirSurface(MirSurface const &) = delete; |
649 | MirSurface& operator=(MirSurface const &) = delete; |
650 | |
651 | - MirSurface(std::string const& error); |
652 | + MirSurface( |
653 | + std::string const& error, |
654 | + MirConnection *allocating_connection, |
655 | + mir::frontend::SurfaceId surface_id, |
656 | + std::shared_ptr<MirWaitHandle> const& handle); |
657 | |
658 | MirSurface( |
659 | MirConnection *allocating_connection, |
660 | mir::client::rpc::DisplayServer& server, |
661 | mir::client::rpc::DisplayServerDebug* debug, |
662 | - std::shared_ptr<mir::client::ClientBufferStreamFactory> const& buffer_stream_factory, |
663 | + std::shared_ptr<mir::client::ClientBufferStream> const& buffer_stream, |
664 | std::shared_ptr<mir::input::receiver::InputPlatform> const& input_platform, |
665 | - MirSurfaceSpec const& spec, |
666 | - mir_surface_callback callback, void * context); |
667 | + MirSurfaceSpec const& spec, mir::protobuf::Surface const& surface_proto, |
668 | + std::shared_ptr<MirWaitHandle> const& handle); |
669 | |
670 | ~MirSurface(); |
671 | |
672 | - MirWaitHandle* release_surface( |
673 | - mir_surface_callback callback, |
674 | - void *context); |
675 | - |
676 | MirSurfaceParameters get_parameters() const; |
677 | char const * get_error_message(); |
678 | int id() const; |
679 | |
680 | - MirWaitHandle* get_create_wait_handle(); |
681 | MirWaitHandle* configure(MirSurfaceAttrib a, int value); |
682 | |
683 | // TODO: Some sort of extension mechanism so that this can be moved |
684 | @@ -192,12 +192,12 @@ |
685 | static bool is_valid(MirSurface* query); |
686 | |
687 | MirWaitHandle* request_persistent_id(mir_surface_id_callback callback, void* context); |
688 | + MirConnection* connection() const; |
689 | private: |
690 | std::mutex mutable mutex; // Protects all members of *this |
691 | |
692 | void on_configured(); |
693 | void on_cursor_configured(); |
694 | - void created(mir_surface_callback callback, void* context); |
695 | void acquired_persistent_id(mir_surface_id_callback callback, void* context); |
696 | MirPixelFormat convert_ipc_pf_to_geometry(google::protobuf::int32 pf) const; |
697 | |
698 | @@ -213,14 +213,12 @@ |
699 | MirWaitHandle modify_wait_handle; |
700 | std::unique_ptr<mir::protobuf::Void> const modify_result; |
701 | |
702 | - MirConnection* const connection{nullptr}; |
703 | + MirConnection* const connection_; |
704 | |
705 | - MirWaitHandle create_wait_handle; |
706 | MirWaitHandle configure_wait_handle; |
707 | MirWaitHandle configure_cursor_wait_handle; |
708 | MirWaitHandle persistent_id_wait_handle; |
709 | |
710 | - std::shared_ptr<mir::client::ClientBufferStreamFactory> const buffer_stream_factory; |
711 | std::shared_ptr<mir::client::ClientBufferStream> buffer_stream; |
712 | std::shared_ptr<mir::input::receiver::InputPlatform> const input_platform; |
713 | std::shared_ptr<mir::input::receiver::XKBMapper> const keymapper; |
714 | @@ -234,6 +232,10 @@ |
715 | std::function<void(MirEvent const*)> handle_event_callback; |
716 | std::shared_ptr<mir::dispatch::ThreadedDispatcher> input_thread; |
717 | bool auto_resize_stream{true}; |
718 | + |
719 | + //a bit batty, but the creation handle has to exist for as long as the MirSurface does, |
720 | + //as we don't really manage the lifetime of MirWaitHandle sensibly. |
721 | + std::shared_ptr<MirWaitHandle> const creation_handle; |
722 | }; |
723 | |
724 | #endif /* MIR_CLIENT_PRIVATE_MIR_WAIT_HANDLE_H_ */ |
725 | |
726 | === modified file 'src/client/mir_surface_api.cpp' |
727 | --- src/client/mir_surface_api.cpp 2015-10-14 16:16:08 +0000 |
728 | +++ src/client/mir_surface_api.cpp 2016-01-13 19:10:37 +0000 |
729 | @@ -152,9 +152,6 @@ |
730 | } |
731 | catch (std::exception const& error) |
732 | { |
733 | - auto error_surf = new MirSurface{std::string{"Failed to create surface: "} + |
734 | - boost::diagnostic_information(error)}; |
735 | - (*callback)(error_surf, context); |
736 | return nullptr; |
737 | } |
738 | } |
739 | @@ -258,9 +255,10 @@ |
740 | MirSurface* surface, |
741 | mir_surface_callback callback, void* context) |
742 | { |
743 | + auto connection = surface->connection(); |
744 | try |
745 | { |
746 | - return surface->release_surface(callback, context); |
747 | + return connection->release_surface(surface, callback, context); |
748 | } |
749 | catch (std::exception const& ex) |
750 | { |
751 | |
752 | === modified file 'src/client/surface_map.cpp' |
753 | --- src/client/surface_map.cpp 2015-12-15 15:42:37 +0000 |
754 | +++ src/client/surface_map.cpp 2016-01-13 19:10:37 +0000 |
755 | @@ -31,7 +31,7 @@ |
756 | |
757 | mcl::ConnectionSurfaceMap::~ConnectionSurfaceMap() noexcept |
758 | { |
759 | - std::unordered_map<frontend::SurfaceId, MirSurface*> surface_map; |
760 | + std::unordered_map<frontend::SurfaceId, std::shared_ptr<MirSurface>> surface_map; |
761 | std::unordered_map<frontend::BufferStreamId, StreamInfo> stream_map; |
762 | { |
763 | //Prevent TSAN from flagging lock ordering issues |
764 | @@ -42,14 +42,8 @@ |
765 | stream_map = std::move(streams); |
766 | } |
767 | |
768 | - // Unless the client has screwed up there should be no surfaces left |
769 | + // Unless the client has screwed up there should be no streams left |
770 | // here. (OTOH *we* don't need to leak memory when clients screw up.) |
771 | - for (auto const& surface : surface_map) |
772 | - { |
773 | - if (MirSurface::is_valid(surface.second)) |
774 | - delete surface.second; |
775 | - } |
776 | - |
777 | for (auto const& info : stream_map) |
778 | { |
779 | if (info.second.owned) |
780 | @@ -65,7 +59,7 @@ |
781 | if (it != surfaces.end()) |
782 | { |
783 | auto const surface = it->second; |
784 | - exec(surface); |
785 | + exec(surface.get()); |
786 | } |
787 | else |
788 | { |
789 | @@ -75,7 +69,7 @@ |
790 | } |
791 | } |
792 | |
793 | -void mcl::ConnectionSurfaceMap::insert(mf::SurfaceId surface_id, MirSurface* surface) |
794 | +void mcl::ConnectionSurfaceMap::insert(mf::SurfaceId surface_id, std::shared_ptr<MirSurface> const& surface) |
795 | { |
796 | // get_buffer_stream has internal locks - call before locking mutex to |
797 | // avoid locking ordering issues |
798 | |
799 | === modified file 'src/client/surface_map.h' |
800 | --- src/client/surface_map.h 2015-07-16 07:03:19 +0000 |
801 | +++ src/client/surface_map.h 2016-01-13 19:10:37 +0000 |
802 | @@ -22,6 +22,7 @@ |
803 | #include "mir/frontend/surface_id.h" |
804 | #include "mir/frontend/buffer_stream_id.h" |
805 | #include <functional> |
806 | +#include <memory> |
807 | |
808 | struct MirSurface; |
809 | |
810 | |
811 | === modified file 'tests/unit-tests/client/test_client_mir_surface.cpp' |
812 | --- tests/unit-tests/client/test_client_mir_surface.cpp 2015-12-16 20:01:21 +0000 |
813 | +++ tests/unit-tests/client/test_client_mir_surface.cpp 2016-01-13 19:10:37 +0000 |
814 | @@ -51,8 +51,7 @@ |
815 | |
816 | #include <boost/throw_exception.hpp> |
817 | #include "mir/test/doubles/stub_client_buffer_factory.h" |
818 | -#include "mir/test/doubles/stub_client_buffer_stream_factory.h" |
819 | -#include "mir/test/doubles/mock_client_buffer_stream_factory.h" |
820 | +#include "mir/test/doubles/stub_buffer_stream.h" |
821 | #include "mir/test/doubles/mock_client_buffer_stream.h" |
822 | |
823 | #include "mir_test_framework/stub_client_platform_factory.h" |
824 | @@ -139,7 +138,6 @@ |
825 | |
826 | static std::map<int, int> sent_surface_attributes; |
827 | |
828 | -private: |
829 | void generate_unique_buffer() |
830 | { |
831 | global_buffer_id++; |
832 | @@ -278,10 +276,6 @@ |
833 | { |
834 | } |
835 | |
836 | -void null_surface_callback(MirSurface*, void*) |
837 | -{ |
838 | -} |
839 | - |
840 | void null_event_callback(MirSurface*, MirEvent const*, void*) |
841 | { |
842 | } |
843 | @@ -294,6 +288,8 @@ |
844 | { |
845 | MirClientSurfaceTest() |
846 | { |
847 | + mock_server_tool->create_surface_response(&surface_proto); |
848 | + ON_CALL(*stub_buffer_stream, swap_interval()).WillByDefault(testing::Return(1)); |
849 | start_test_server(); |
850 | connect_to_test_server(); |
851 | } |
852 | @@ -333,50 +329,47 @@ |
853 | connection.get(), |
854 | server_stub, |
855 | nullptr, |
856 | - stub_buffer_stream_factory, |
857 | + stub_buffer_stream, |
858 | input_platform, |
859 | spec, |
860 | - &null_surface_callback, |
861 | - nullptr); |
862 | + surface_proto, |
863 | + wh); |
864 | } |
865 | |
866 | std::shared_ptr<MirSurface> create_surface_with( |
867 | mclr::DisplayServer& server_stub, |
868 | - std::shared_ptr<mcl::ClientBufferStreamFactory> const& buffer_stream_factory) |
869 | + std::shared_ptr<mcl::ClientBufferStream> const& buffer_stream) |
870 | { |
871 | return std::make_shared<MirSurface>( |
872 | connection.get(), |
873 | server_stub, |
874 | nullptr, |
875 | - buffer_stream_factory, |
876 | + buffer_stream, |
877 | input_platform, |
878 | spec, |
879 | - &null_surface_callback, |
880 | - nullptr); |
881 | + surface_proto, |
882 | + wh); |
883 | } |
884 | |
885 | std::shared_ptr<MirSurface> create_and_wait_for_surface_with( |
886 | mclr::DisplayServer& server_stub) |
887 | { |
888 | auto surface = create_surface_with(server_stub); |
889 | - surface->get_create_wait_handle()->wait_for_all(); |
890 | return surface; |
891 | } |
892 | |
893 | std::shared_ptr<MirSurface> create_and_wait_for_surface_with( |
894 | mclr::DisplayServer& server_stub, |
895 | - std::shared_ptr<mcl::ClientBufferStreamFactory> const& buffer_stream_factory) |
896 | + std::shared_ptr<mcl::ClientBufferStream> const& buffer_stream) |
897 | { |
898 | - auto surface = create_surface_with(server_stub, buffer_stream_factory); |
899 | - surface->get_create_wait_handle()->wait_for_all(); |
900 | + auto surface = create_surface_with(server_stub, buffer_stream); |
901 | return surface; |
902 | } |
903 | |
904 | std::shared_ptr<MirConnection> connection; |
905 | |
906 | MirSurfaceSpec const spec{nullptr, 33, 45, mir_pixel_format_abgr_8888}; |
907 | - std::shared_ptr<mtd::StubClientBufferStreamFactory> const stub_buffer_stream_factory = |
908 | - std::make_shared<mtd::StubClientBufferStreamFactory>(); |
909 | + std::shared_ptr<mtd::MockClientBufferStream> stub_buffer_stream{std::make_shared<mtd::MockClientBufferStream>()}; |
910 | std::shared_ptr<StubClientInputPlatform> const input_platform = |
911 | std::make_shared<StubClientInputPlatform>(); |
912 | std::shared_ptr<MockServerPackageGenerator> const mock_server_tool = |
913 | @@ -385,6 +378,8 @@ |
914 | std::shared_ptr<mcl::ConnectionSurfaceMap> surface_map; |
915 | std::shared_ptr<mt::TestProtobufServer> test_server; |
916 | std::shared_ptr<mclr::DisplayServer> client_comm_channel; |
917 | + mir::protobuf::Surface surface_proto; |
918 | + std::shared_ptr<MirWaitHandle> const wh{std::make_shared<MirWaitHandle>()}; |
919 | |
920 | std::chrono::milliseconds const pause_time{10}; |
921 | }; |
922 | @@ -403,22 +398,6 @@ |
923 | } |
924 | } |
925 | |
926 | -TEST_F(MirClientSurfaceTest, create_wait_handle_really_blocks) |
927 | -{ |
928 | - using namespace testing; |
929 | - |
930 | - FakeRpcChannel fake_channel; |
931 | - mclr::DisplayServer unresponsive_server{mt::fake_shared(fake_channel)}; |
932 | - |
933 | - auto const surface = create_surface_with(unresponsive_server); |
934 | - auto wait_handle = surface->get_create_wait_handle(); |
935 | - |
936 | - auto expected_end = std::chrono::steady_clock::now() + pause_time; |
937 | - wait_handle->wait_for_pending(pause_time); |
938 | - |
939 | - EXPECT_GE(std::chrono::steady_clock::now(), expected_end); |
940 | -} |
941 | - |
942 | TEST_F(MirClientSurfaceTest, creates_input_thread_with_input_dispatcher_when_delegate_specified) |
943 | { |
944 | using namespace ::testing; |
945 | @@ -432,9 +411,7 @@ |
946 | .WillOnce(Return(mock_input_dispatcher)); |
947 | |
948 | MirSurface surface{connection.get(), *client_comm_channel, nullptr, |
949 | - stub_buffer_stream_factory, mock_input_platform, spec, &null_surface_callback, nullptr}; |
950 | - auto wait_handle = surface.get_create_wait_handle(); |
951 | - wait_handle->wait_for_all(); |
952 | + stub_buffer_stream, mock_input_platform, spec, surface_proto, wh}; |
953 | surface.set_event_handler(null_event_callback, nullptr); |
954 | |
955 | mock_input_dispatcher->trigger(); |
956 | @@ -455,9 +432,7 @@ |
957 | .WillOnce(Return(mock_input_dispatcher)); |
958 | |
959 | MirSurface surface{connection.get(), *client_comm_channel, nullptr, |
960 | - stub_buffer_stream_factory, mock_input_platform, spec, &null_surface_callback, nullptr}; |
961 | - auto wait_handle = surface.get_create_wait_handle(); |
962 | - wait_handle->wait_for_all(); |
963 | + stub_buffer_stream, mock_input_platform, spec, surface_proto, wh}; |
964 | surface.set_event_handler(null_event_callback, nullptr); |
965 | |
966 | // Should now not get dispatched. |
967 | @@ -478,9 +453,7 @@ |
968 | EXPECT_CALL(*mock_input_platform, create_input_receiver(_, _, _)).Times(0); |
969 | |
970 | MirSurface surface{connection.get(), *client_comm_channel, nullptr, |
971 | - stub_buffer_stream_factory, mock_input_platform, spec, &null_surface_callback, nullptr}; |
972 | - auto wait_handle = surface.get_create_wait_handle(); |
973 | - wait_handle->wait_for_all(); |
974 | + stub_buffer_stream, mock_input_platform, spec, surface_proto, wh}; |
975 | } |
976 | |
977 | TEST_F(MirClientSurfaceTest, valid_surface_is_valid) |
978 | @@ -531,12 +504,7 @@ |
979 | { |
980 | using namespace testing; |
981 | auto mock_stream = std::make_shared<mtd::MockClientBufferStream>(); |
982 | - auto mock_stream_factory = std::make_shared<NiceMock<mtd::MockClientBufferStreamFactory>>(); |
983 | auto mock_input_platform = std::make_shared<NiceMock<MockClientInputPlatform>>(); |
984 | - ON_CALL(*mock_stream_factory, make_producer_stream(_,_,_,_,An<void*>())) |
985 | - .WillByDefault(Return(mock_stream.get())); |
986 | - ON_CALL(*mock_stream_factory, make_producer_stream(_,_,_,_,An<geom::Size>())) |
987 | - .WillByDefault(Return(mock_stream)); |
988 | ON_CALL(*mock_input_platform, create_input_receiver(_,_,_)) |
989 | .WillByDefault(Return(std::make_shared<mt::TestDispatchable>([]{}))); |
990 | ON_CALL(*mock_stream, rpc_id()).WillByDefault(Return(mir::frontend::BufferStreamId(2))); |
991 | @@ -545,11 +513,8 @@ |
992 | EXPECT_CALL(*mock_stream, set_size(size)); |
993 | auto ev = mir::events::make_event(mir::frontend::SurfaceId(2), size); |
994 | |
995 | - //FIXME: difficult construction |
996 | MirSurface surface{connection.get(), *client_comm_channel, nullptr, |
997 | - mock_stream_factory, mock_input_platform, spec, &null_surface_callback, nullptr}; |
998 | - auto wait_handle = surface.get_create_wait_handle(); |
999 | - wait_handle->wait_for_all(); |
1000 | + mock_stream, mock_input_platform, spec, surface_proto, wh}; |
1001 | surface.handle_event(*ev); |
1002 | surface_map->erase(mir::frontend::BufferStreamId(2)); |
1003 | } |
1004 | @@ -558,13 +523,8 @@ |
1005 | { |
1006 | using namespace testing; |
1007 | auto mock_stream = std::make_shared<NiceMock<mtd::MockClientBufferStream>>(); |
1008 | - auto mock_stream_factory = std::make_shared<NiceMock<mtd::MockClientBufferStreamFactory>>(); |
1009 | auto mock_input_platform = std::make_shared<NiceMock<MockClientInputPlatform>>(); |
1010 | ON_CALL(*mock_stream, rpc_id()).WillByDefault(Return(mir::frontend::BufferStreamId(2))); |
1011 | - ON_CALL(*mock_stream_factory, make_producer_stream(_,_,_,_,An<void*>())) |
1012 | - .WillByDefault(Return(mock_stream.get())); |
1013 | - ON_CALL(*mock_stream_factory, make_producer_stream(_,_,_,_,An<geom::Size>())) |
1014 | - .WillByDefault(Return(mock_stream)); |
1015 | ON_CALL(*mock_input_platform, create_input_receiver(_,_,_)) |
1016 | .WillByDefault(Return(std::make_shared<mt::TestDispatchable>([]{}))); |
1017 | |
1018 | @@ -572,8 +532,7 @@ |
1019 | EXPECT_CALL(*mock_stream, set_size(size)).Times(0); |
1020 | auto ev = mir::events::make_event(mir::frontend::SurfaceId(2), size); |
1021 | MirSurface surface{connection.get(), *client_comm_channel, nullptr, |
1022 | - mock_stream_factory, mock_input_platform, spec, &null_surface_callback, nullptr}; |
1023 | - surface.get_create_wait_handle()->wait_for_all(); |
1024 | + mock_stream, mock_input_platform, spec, surface_proto, wh}; |
1025 | |
1026 | MirSurfaceSpec spec; |
1027 | std::vector<MirBufferStreamInfo> info = |
1028 | |
1029 | === modified file 'tests/unit-tests/client/test_connection_resource_map.cpp' |
1030 | --- tests/unit-tests/client/test_connection_resource_map.cpp 2015-07-16 07:03:19 +0000 |
1031 | +++ tests/unit-tests/client/test_connection_resource_map.cpp 2016-01-13 19:10:37 +0000 |
1032 | @@ -27,7 +27,8 @@ |
1033 | |
1034 | struct ConnectionResourceMap : testing::Test |
1035 | { |
1036 | - MirSurface surface{"a string"}; |
1037 | + std::shared_ptr<MirWaitHandle> wh { std::make_shared<MirWaitHandle>() }; |
1038 | + std::shared_ptr<MirSurface> surface{std::make_shared<MirSurface>("a string", nullptr, mf::SurfaceId{2}, wh)}; |
1039 | mtd::MockClientBufferStream stream; |
1040 | mf::SurfaceId const surface_id{43}; |
1041 | mf::BufferStreamId const stream_id{43}; |
1042 | @@ -39,14 +40,14 @@ |
1043 | auto surface_called = false; |
1044 | auto stream_called = false; |
1045 | mcl::ConnectionSurfaceMap map; |
1046 | - map.insert(surface_id, &surface); |
1047 | + map.insert(surface_id, surface); |
1048 | map.with_surface_do(surface_id, [&](MirSurface* surf) { |
1049 | - EXPECT_THAT(surf, Eq(&surface)); |
1050 | + EXPECT_THAT(surf, Eq(surface.get())); |
1051 | surface_called = true; |
1052 | }); |
1053 | |
1054 | map.with_stream_do(stream_id, [&](mcl::ClientBufferStream* stream) { |
1055 | - EXPECT_THAT(stream, Eq(surface.get_buffer_stream())); |
1056 | + EXPECT_THAT(stream, Eq(surface->get_buffer_stream())); |
1057 | stream_called = true; |
1058 | }); |
1059 | |
1060 | @@ -59,9 +60,9 @@ |
1061 | using namespace testing; |
1062 | auto stream_called = false; |
1063 | mcl::ConnectionSurfaceMap map; |
1064 | - map.insert(surface_id, &surface); |
1065 | + map.insert(surface_id, surface); |
1066 | map.with_stream_do(stream_id, [&](mcl::ClientBufferStream* stream) { |
1067 | - EXPECT_THAT(stream, Eq(surface.get_buffer_stream())); |
1068 | + EXPECT_THAT(stream, Eq(surface->get_buffer_stream())); |
1069 | stream_called = true; |
1070 | }); |
1071 | EXPECT_TRUE(stream_called); |
1072 | |
1073 | === modified file 'tests/unit-tests/client/test_mir_connection.cpp' |
1074 | --- tests/unit-tests/client/test_mir_connection.cpp 2015-07-29 01:39:52 +0000 |
1075 | +++ tests/unit-tests/client/test_mir_connection.cpp 2016-01-13 19:10:37 +0000 |
1076 | @@ -63,7 +63,7 @@ |
1077 | ON_CALL(*this, watch_fd()).WillByDefault(testing::Return(pollable_fd)); |
1078 | } |
1079 | |
1080 | - void call_method(std::string const& name, |
1081 | + virtual void call_method(std::string const& name, |
1082 | google::protobuf::MessageLite const* parameters, |
1083 | google::protobuf::MessageLite* response, |
1084 | google::protobuf::Closure* complete) |
1085 | @@ -83,6 +83,13 @@ |
1086 | platform_operation(static_cast<mp::PlatformOperationMessage const*>(parameters), |
1087 | static_cast<mp::PlatformOperationMessage*>(response)); |
1088 | } |
1089 | + else if (name == "create_surface") |
1090 | + { |
1091 | + auto response_message = static_cast<mp::Surface*>(response); |
1092 | + response_message->mutable_id()->set_value(33); |
1093 | + response_message->mutable_buffer_stream()->mutable_id()->set_value(33); |
1094 | + } |
1095 | + |
1096 | |
1097 | complete->Run(); |
1098 | } |
1099 | @@ -638,3 +645,30 @@ |
1100 | EXPECT_THAT(mir_platform_message_get_opcode(returned_response), Eq(opcode)); |
1101 | mir_platform_message_release(returned_response); |
1102 | } |
1103 | + |
1104 | +TEST_F(MirConnectionTest, create_wait_handle_really_blocks) |
1105 | +{ |
1106 | + using namespace testing; |
1107 | + |
1108 | + std::chrono::milliseconds const pause_time{10}; |
1109 | + struct FakeRpcChannel : public MockRpcChannel |
1110 | + { |
1111 | + void call_method( |
1112 | + std::string const&, |
1113 | + google::protobuf::MessageLite const*, |
1114 | + google::protobuf::MessageLite*, |
1115 | + google::protobuf::Closure* closure) override |
1116 | + { |
1117 | + delete closure; |
1118 | + } |
1119 | + }; |
1120 | + TestConnectionConfiguration conf{mock_platform, std::make_shared<NiceMock<FakeRpcChannel>>()}; |
1121 | + MirConnection connection(conf); |
1122 | + MirSurfaceSpec const spec{&connection, 33, 45, mir_pixel_format_abgr_8888}; |
1123 | + |
1124 | + auto wait_handle = connection.create_surface(spec, nullptr, nullptr); |
1125 | + auto expected_end = std::chrono::steady_clock::now() + pause_time; |
1126 | + wait_handle->wait_for_pending(pause_time); |
1127 | + |
1128 | + EXPECT_GE(std::chrono::steady_clock::now(), expected_end); |
1129 | +} |
FAILED: Continuous integration, rev:3197 jenkins. qa.ubuntu. com/job/ mir-ci/ 5857/ jenkins. qa.ubuntu. com/job/ mir-android- vivid-i386- build/5324 jenkins. qa.ubuntu. com/job/ mir-clang- vivid-amd64- build/4230/ console jenkins. qa.ubuntu. com/job/ mir-mediumtests -vivid- touch/5273/ console jenkins. qa.ubuntu. com/job/ mir-xenial- amd64-ci/ 185/console jenkins. qa.ubuntu. com/job/ mir-xenial- i386-ci/ 185/console jenkins. qa.ubuntu. com/job/ mir-mediumtests -builder- vivid-armhf/ 5273/console
http://
Executed test runs:
SUCCESS: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild: s-jenkins. ubuntu- ci:8080/ job/mir- ci/5857/ rebuild
http://