Mir

Merge lp:~kdub/mir/sort-out-surface-ownership into lp:mir

Proposed by Kevin DuBois
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
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).

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: Needs Fixing (continuous-integration)
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: Needs Fixing (continuous-integration)
Revision history for this message
Kevin DuBois (kdub) wrote :

^still a FD leak for me to track down, probably on monday

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :

PASSED: Continuous integration, rev:3203
http://jenkins.qa.ubuntu.com/job/mir-ci/5908/
Executed test runs:
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-android-vivid-i386-build/5398
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-clang-vivid-amd64-build/4305
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-vivid-touch/5351
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-xenial-touch/223
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-xenial-amd64-ci/234
        deb: http://jenkins.qa.ubuntu.com/job/mir-xenial-amd64-ci/234/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-xenial-i386-ci/234
        deb: http://jenkins.qa.ubuntu.com/job/mir-xenial-i386-ci/234/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-builder-vivid-armhf/5348
        deb: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-builder-vivid-armhf/5348/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-runner-touch/7856
    SUCCESS: http://s-jenkins.ubuntu-ci:8080/job/touch-flash-device/26297
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-builder-xenial-armhf/219
        deb: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-builder-xenial-armhf/219/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-runner-xenial-touch/77
    SUCCESS: http://s-jenkins.ubuntu-ci:8080/job/touch-flash-device/26301

Click here to trigger a rebuild:
http://s-jenkins.ubuntu-ci:8080/job/mir-ci/5908/rebuild

review: Approve (continuous-integration)
Revision history for this message
Alan Griffiths (alan-griffiths) wrote :

-TEST_F(MirClientSurfaceTest, create_wait_handle_really_blocks)

Is this test no longer relevant?

review: Needs Information
Revision history for this message
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

Revision history for this message
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.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :

PASSED: Continuous integration, rev:3205
http://jenkins.qa.ubuntu.com/job/mir-ci/5937/
Executed test runs:
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-android-vivid-i386-build/5430
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-clang-vivid-amd64-build/4337
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-vivid-touch/5386
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-xenial-touch/236
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-xenial-amd64-ci/261
        deb: http://jenkins.qa.ubuntu.com/job/mir-xenial-amd64-ci/261/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-xenial-i386-ci/261
        deb: http://jenkins.qa.ubuntu.com/job/mir-xenial-i386-ci/261/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-builder-vivid-armhf/5383
        deb: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-builder-vivid-armhf/5383/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-runner-touch/7879
    SUCCESS: http://s-jenkins.ubuntu-ci:8080/job/touch-flash-device/26391
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-builder-xenial-armhf/232
        deb: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-builder-xenial-armhf/232/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-runner-xenial-touch/90
    SUCCESS: http://s-jenkins.ubuntu-ci:8080/job/touch-flash-device/26399

Click here to trigger a rebuild:
http://s-jenkins.ubuntu-ci:8080/job/mir-ci/5937/rebuild

review: Approve (continuous-integration)
Revision history for this message
Alan Griffiths (alan-griffiths) wrote :

OK. (I'm not entirely convinced it is needed, but I don't see any harm.)

review: Approve
Revision history for this message
Mir CI Bot (mir-ci-bot) wrote :

PASSED: Continuous integration, rev:3205
https://mir-jenkins.ubuntu.com/job/mir-ci/18/
Executed test runs:
    None: https://mir-jenkins.ubuntu.com/job/generic-update-mp/18/console

Click here to trigger a rebuild:
https://mir-jenkins.ubuntu.com/job/mir-ci/18/rebuild

review: Approve (continuous-integration)
Revision history for this message
Chris Halse Rogers (raof) wrote :

127 + std::lock_guard<decltype(mutex)> lock(mutex);
...
136 + callback(surf.get(), context);

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::disconnect() takes the same mutex, and calling mir_connection_release() in the error case for surface construction doesn't seem too farfetched.

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_ptr<MirWaitHandle> const creation_handle;

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!

review: Needs Fixing
Revision history for this message
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.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :

PASSED: Continuous integration, rev:3209
http://jenkins.qa.ubuntu.com/job/mir-ci/5979/
Executed test runs:
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-android-vivid-i386-build/5486
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-clang-vivid-amd64-build/4393
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-vivid-touch/5442
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-xenial-touch/258
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-xenial-amd64-ci/303
        deb: http://jenkins.qa.ubuntu.com/job/mir-xenial-amd64-ci/303/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-xenial-i386-ci/303
        deb: http://jenkins.qa.ubuntu.com/job/mir-xenial-i386-ci/303/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-builder-vivid-armhf/5439
        deb: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-builder-vivid-armhf/5439/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-runner-touch/7924
    SUCCESS: http://s-jenkins.ubuntu-ci:8080/job/touch-flash-device/26548
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-builder-xenial-armhf/254
        deb: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-builder-xenial-armhf/254/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-runner-xenial-touch/112
    SUCCESS: http://s-jenkins.ubuntu-ci:8080/job/touch-flash-device/26554

Click here to trigger a rebuild:
http://s-jenkins.ubuntu-ci:8080/job/mir-ci/5979/rebuild

review: Approve (continuous-integration)
Revision history for this message
Mir CI Bot (mir-ci-bot) wrote :

PASSED: Continuous integration, rev:3209
https://mir-jenkins.ubuntu.com/job/mir-ci/35/
Executed test runs:
    None: https://mir-jenkins.ubuntu.com/job/generic-update-mp/34/console

Click here to trigger a rebuild:
https://mir-jenkins.ubuntu.com/job/mir-ci/35/rebuild

review: Approve (continuous-integration)
Revision history for this message
Alberto Aguirre (albaguirre) wrote :

+ if (strncmp(surface->get_error_message(), "", 1))

Could just be if(!mir_surface_is_valid(surface))

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

@Alberto, fixed

Revision history for this message
Mir CI Bot (mir-ci-bot) wrote :

PASSED: Continuous integration, rev:3212
https://mir-jenkins.ubuntu.com/job/mir-ci/42/
Executed test runs:
    None: https://mir-jenkins.ubuntu.com/job/generic-update-mp/42/console

Click here to trigger a rebuild:
https://mir-jenkins.ubuntu.com/job/mir-ci/42/rebuild

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

PASSED: Continuous integration, rev:3212
http://jenkins.qa.ubuntu.com/job/mir-ci/6009/
Executed test runs:
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-android-vivid-i386-build/5522
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-clang-vivid-amd64-build/4429
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-vivid-touch/5478
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-xenial-touch/273
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-xenial-amd64-ci/333
        deb: http://jenkins.qa.ubuntu.com/job/mir-xenial-amd64-ci/333/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-xenial-i386-ci/333
        deb: http://jenkins.qa.ubuntu.com/job/mir-xenial-i386-ci/333/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-builder-vivid-armhf/5475
        deb: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-builder-vivid-armhf/5475/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-runner-touch/7949
    SUCCESS: http://s-jenkins.ubuntu-ci:8080/job/touch-flash-device/26625
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-builder-xenial-armhf/269
        deb: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-builder-xenial-armhf/269/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-runner-xenial-touch/127
    SUCCESS: http://s-jenkins.ubuntu-ci:8080/job/touch-flash-device/26633

Click here to trigger a rebuild:
http://s-jenkins.ubuntu-ci:8080/job/mir-ci/6009/rebuild

review: Approve (continuous-integration)
Revision history for this message
Alberto Aguirre (albaguirre) wrote :

LGTM.

review: Approve
Revision history for this message
Chris Halse Rogers (raof) wrote :

LGTM now.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'src/client/connection_surface_map.h'
--- src/client/connection_surface_map.h 2015-12-15 12:24:10 +0000
+++ src/client/connection_surface_map.h 2016-01-13 19:10:37 +0000
@@ -40,7 +40,7 @@
40 ~ConnectionSurfaceMap() noexcept;40 ~ConnectionSurfaceMap() noexcept;
4141
42 void with_surface_do(frontend::SurfaceId surface_id, std::function<void(MirSurface*)> const& exec) const override;42 void with_surface_do(frontend::SurfaceId surface_id, std::function<void(MirSurface*)> const& exec) const override;
43 void insert(frontend::SurfaceId surface_id, MirSurface* surface);43 void insert(frontend::SurfaceId surface_id, std::shared_ptr<MirSurface> const& surface);
44 void erase(frontend::SurfaceId surface_id);44 void erase(frontend::SurfaceId surface_id);
4545
46 void with_stream_do(frontend::BufferStreamId stream_id, std::function<void(ClientBufferStream*)> const& exec) const override;46 void with_stream_do(frontend::BufferStreamId stream_id, std::function<void(ClientBufferStream*)> const& exec) const override;
@@ -50,7 +50,7 @@
5050
51private:51private:
52 std::shared_timed_mutex mutable guard;52 std::shared_timed_mutex mutable guard;
53 std::unordered_map<frontend::SurfaceId, MirSurface*> surfaces;53 std::unordered_map<frontend::SurfaceId, std::shared_ptr<MirSurface>> surfaces;
54 std::unordered_map<frontend::BufferStreamId, StreamInfo> streams;54 std::unordered_map<frontend::BufferStreamId, StreamInfo> streams;
55};55};
5656
5757
=== modified file 'src/client/mir_connection.cpp'
--- src/client/mir_connection.cpp 2016-01-04 07:26:59 +0000
+++ src/client/mir_connection.cpp 2016-01-13 19:10:37 +0000
@@ -53,6 +53,76 @@
5353
54namespace54namespace
55{55{
56mir::protobuf::SurfaceParameters serialize_spec(MirSurfaceSpec const& spec)
57{
58 mp::SurfaceParameters message;
59
60#define SERIALIZE_OPTION_IF_SET(option) \
61 if (spec.option.is_set()) \
62 message.set_##option(spec.option.value());
63
64 SERIALIZE_OPTION_IF_SET(width);
65 SERIALIZE_OPTION_IF_SET(height);
66 SERIALIZE_OPTION_IF_SET(pixel_format);
67 SERIALIZE_OPTION_IF_SET(buffer_usage);
68 SERIALIZE_OPTION_IF_SET(surface_name);
69 SERIALIZE_OPTION_IF_SET(output_id);
70 SERIALIZE_OPTION_IF_SET(type);
71 SERIALIZE_OPTION_IF_SET(state);
72 SERIALIZE_OPTION_IF_SET(pref_orientation);
73 SERIALIZE_OPTION_IF_SET(edge_attachment);
74 SERIALIZE_OPTION_IF_SET(min_width);
75 SERIALIZE_OPTION_IF_SET(min_height);
76 SERIALIZE_OPTION_IF_SET(max_width);
77 SERIALIZE_OPTION_IF_SET(max_height);
78 SERIALIZE_OPTION_IF_SET(width_inc);
79 SERIALIZE_OPTION_IF_SET(height_inc);
80 // min_aspect is a special case (below)
81 // max_aspect is a special case (below)
82
83 if (spec.parent.is_set() && spec.parent.value() != nullptr)
84 message.set_parent_id(spec.parent.value()->id());
85
86 if (spec.parent_id)
87 {
88 auto id = message.mutable_parent_persistent_id();
89 id->set_value(spec.parent_id->as_string());
90 }
91
92 if (spec.aux_rect.is_set())
93 {
94 message.mutable_aux_rect()->set_left(spec.aux_rect.value().left);
95 message.mutable_aux_rect()->set_top(spec.aux_rect.value().top);
96 message.mutable_aux_rect()->set_width(spec.aux_rect.value().width);
97 message.mutable_aux_rect()->set_height(spec.aux_rect.value().height);
98 }
99
100 if (spec.min_aspect.is_set())
101 {
102 message.mutable_min_aspect()->set_width(spec.min_aspect.value().width);
103 message.mutable_min_aspect()->set_height(spec.min_aspect.value().height);
104 }
105
106 if (spec.max_aspect.is_set())
107 {
108 message.mutable_max_aspect()->set_width(spec.max_aspect.value().width);
109 message.mutable_max_aspect()->set_height(spec.max_aspect.value().height);
110 }
111
112 if (spec.input_shape.is_set())
113 {
114 for (auto const& rect : spec.input_shape.value())
115 {
116 auto const new_shape = message.add_input_shape();
117 new_shape->set_left(rect.left);
118 new_shape->set_top(rect.top);
119 new_shape->set_width(rect.width);
120 new_shape->set_height(rect.height);
121 }
122 }
123
124 return message;
125}
56126
57class MirDisplayConfigurationStore127class MirDisplayConfigurationStore
58{128{
@@ -175,10 +245,106 @@
175 mir_surface_callback callback,245 mir_surface_callback callback,
176 void * context)246 void * context)
177{247{
178 auto surface = new MirSurface(this, server, &debug, buffer_stream_factory,248 auto response = std::make_shared<mp::Surface>();
179 input_platform, spec, callback, context);249 auto c = std::make_shared<MirConnection::SurfaceCreationRequest>(callback, context, spec);
180250 c->wh->expect_result();
181 return surface->get_create_wait_handle();251 auto const message = serialize_spec(spec);
252 {
253 std::lock_guard<decltype(mutex)> lock(mutex);
254 surface_requests.emplace_back(c);
255 }
256
257 try
258 {
259 server.create_surface(&message, c->response.get(),
260 gp::NewCallback(this, &MirConnection::surface_created, c.get()));
261 }
262 catch (std::exception const& ex)
263 {
264 std::unique_lock<decltype(mutex)> lock(mutex);
265 auto request = std::find_if(surface_requests.begin(), surface_requests.end(),
266 [&](std::shared_ptr<MirConnection::SurfaceCreationRequest> c2) { return c.get() == c2.get(); });
267 if (request != surface_requests.end())
268 {
269 auto id = next_error_id(lock);
270 auto surf = std::make_shared<MirSurface>(
271 std::string{"Error creating surface: "} + boost::diagnostic_information(ex), this, id, (*request)->wh);
272 surface_map->insert(id, surf);
273 auto wh = (*request)->wh;
274 surface_requests.erase(request);
275
276 lock.unlock();
277 callback(surf.get(), context);
278 wh->result_received();
279 }
280 }
281 return c->wh.get();
282}
283
284mf::SurfaceId MirConnection::next_error_id(std::unique_lock<std::mutex> const&)
285{
286 return mf::SurfaceId{surface_error_id--};
287}
288
289void MirConnection::surface_created(SurfaceCreationRequest* request)
290{
291 std::unique_lock<decltype(mutex)> lock(mutex);
292 std::shared_ptr<MirSurface> surf {nullptr};
293 std::shared_ptr<mcl::ClientBufferStream> stream {nullptr};
294 //make sure this request actually was made.
295 auto request_it = std::find_if(surface_requests.begin(), surface_requests.end(),
296 [&request](std::shared_ptr<MirConnection::SurfaceCreationRequest> r){ return request == r.get(); });
297 if (request_it == surface_requests.end())
298 return;
299
300 auto surface_proto = request->response;
301 auto callback = request->cb;
302 auto context = request->context;
303 auto const& spec = request->spec;
304
305 try
306 {
307 stream = buffer_stream_factory->make_producer_stream(
308 this, server, surface_proto->buffer_stream(), std::string{},
309 {surface_proto->width(), surface_proto->height()});
310 }
311 catch (std::exception const& error)
312 {
313 if (!surface_proto->has_error())
314 surface_proto->set_error(error.what());
315 // failed to create buffer_stream, so clean up FDs it doesn't own
316 for (auto i = 0; i < surface_proto->fd_size(); i++)
317 ::close(surface_proto->fd(i));
318 if (surface_proto->has_buffer_stream() && surface_proto->buffer_stream().has_buffer())
319 for (int i = 0; i < surface_proto->buffer_stream().buffer().fd_size(); i++)
320 ::close(surface_proto->buffer_stream().buffer().fd(i));
321 }
322
323 if (surface_proto->has_error() || !surface_proto->has_id())
324 {
325 std::string reason;
326 if (surface_proto->has_error())
327 reason += surface_proto->error();
328 if (surface_proto->has_error() && !surface_proto->has_id())
329 reason += " and ";
330 if (!surface_proto->has_id())
331 reason += "Server assigned surface no id";
332 auto id = next_error_id(lock);
333 surf = std::make_shared<MirSurface>(reason, this, id, request->wh);
334 surface_map->insert(id, surf);
335 }
336 else
337 {
338 surf = std::make_shared<MirSurface>(
339 this, server, &debug, stream, input_platform, spec, *surface_proto, request->wh);
340
341 surface_map->insert(mf::SurfaceId{surface_proto->id().value()}, surf);
342 }
343
344 callback(surf.get(), context);
345 request->wh->result_received();
346
347 surface_requests.erase(request_it);
182}348}
183349
184char const * MirConnection::get_error_message()350char const * MirConnection::get_error_message()
@@ -228,9 +394,7 @@
228394
229void MirConnection::released(SurfaceRelease data)395void MirConnection::released(SurfaceRelease data)
230{396{
231 surface_map->erase(mf::SurfaceId(data.surface->id()));397 // releasing this surface from surface_map means that it will no longer receive events
232
233 // Erasing this surface from surface_map means that it will no longer receive events
234 // If it's still focused, send an unfocused event before we kill it entirely398 // If it's still focused, send an unfocused event before we kill it entirely
235 if (data.surface->attrib(mir_surface_attrib_focus) == mir_surface_focused)399 if (data.surface->attrib(mir_surface_attrib_focus) == mir_surface_focused)
236 {400 {
@@ -239,7 +403,7 @@
239 }403 }
240 data.callback(data.surface, data.context);404 data.callback(data.surface, data.context);
241 data.handle->result_received();405 data.handle->result_received();
242 delete data.surface;406 surface_map->erase(mf::SurfaceId(data.surface->id()));
243}407}
244408
245MirWaitHandle* MirConnection::release_surface(409MirWaitHandle* MirConnection::release_surface(
@@ -248,17 +412,26 @@
248 void * context)412 void * context)
249{413{
250 auto new_wait_handle = new MirWaitHandle;414 auto new_wait_handle = new MirWaitHandle;
415 {
416 std::lock_guard<decltype(release_wait_handle_guard)> rel_lock(release_wait_handle_guard);
417 release_wait_handles.push_back(new_wait_handle);
418 }
419
420 if (!mir_surface_is_valid(surface))
421 {
422 new_wait_handle->expect_result();
423 new_wait_handle->result_received();
424 callback(surface, context);
425 auto id = surface->id();
426 surface_map->erase(mf::SurfaceId(id));
427 return new_wait_handle;
428 }
251429
252 SurfaceRelease surf_release{surface, new_wait_handle, callback, context};430 SurfaceRelease surf_release{surface, new_wait_handle, callback, context};
253431
254 mp::SurfaceId message;432 mp::SurfaceId message;
255 message.set_value(surface->id());433 message.set_value(surface->id());
256434
257 {
258 std::lock_guard<decltype(release_wait_handle_guard)> rel_lock(release_wait_handle_guard);
259 release_wait_handles.push_back(new_wait_handle);
260 }
261
262 new_wait_handle->expect_result();435 new_wait_handle->expect_result();
263 server.release_surface(&message, void_response.get(),436 server.release_surface(&message, void_response.get(),
264 gp::NewCallback(this, &MirConnection::released, surf_release));437 gp::NewCallback(this, &MirConnection::released, surf_release));
@@ -537,11 +710,6 @@
537 surface_map->insert(mf::BufferStreamId(id), stream);710 surface_map->insert(mf::BufferStreamId(id), stream);
538}711}
539712
540void MirConnection::on_surface_created(int id, MirSurface* surface)
541{
542 surface_map->insert(mf::SurfaceId(id), surface);
543}
544
545void MirConnection::register_lifecycle_event_callback(mir_lifecycle_event_callback callback, void* context)713void MirConnection::register_lifecycle_event_callback(mir_lifecycle_event_callback callback, void* context)
546{714{
547 lifecycle_control->set_callback(std::bind(callback, this, std::placeholders::_1, context));715 lifecycle_control->set_callback(std::bind(callback, this, std::placeholders::_1, context));
548716
=== modified file 'src/client/mir_connection.h'
--- src/client/mir_connection.h 2016-01-04 21:41:00 +0000
+++ src/client/mir_connection.h 2016-01-13 19:10:37 +0000
@@ -26,8 +26,10 @@
2626
27#include "mir/geometry/size.h"27#include "mir/geometry/size.h"
28#include "mir/client_platform.h"28#include "mir/client_platform.h"
29#include "mir/frontend/surface_id.h"
29#include "mir/client_context.h"30#include "mir/client_context.h"
30#include "mir_toolkit/mir_client_library.h"31#include "mir_toolkit/mir_client_library.h"
32#include "mir_surface.h"
3133
32#include <atomic>34#include <atomic>
33#include <memory>35#include <memory>
@@ -100,9 +102,9 @@
100 mir_surface_callback callback,102 mir_surface_callback callback,
101 void * context);103 void * context);
102 MirWaitHandle* release_surface(104 MirWaitHandle* release_surface(
103 MirSurface *surface,105 MirSurface *surface,
104 mir_surface_callback callback,106 mir_surface_callback callback,
105 void *context);107 void *context);
106108
107 MirPromptSession* create_prompt_session();109 MirPromptSession* create_prompt_session();
108110
@@ -152,7 +154,6 @@
152 EGLNativeDisplayType egl_native_display();154 EGLNativeDisplayType egl_native_display();
153 MirPixelFormat egl_pixel_format(EGLDisplay, EGLConfig) const;155 MirPixelFormat egl_pixel_format(EGLDisplay, EGLConfig) const;
154156
155 void on_surface_created(int id, MirSurface* surface);
156 void on_stream_created(int id, mir::client::ClientBufferStream* stream);157 void on_stream_created(int id, mir::client::ClientBufferStream* stream);
157158
158 MirWaitHandle* configure_display(MirDisplayConfiguration* configuration);159 MirWaitHandle* configure_display(MirDisplayConfiguration* configuration);
@@ -167,9 +168,28 @@
167 }168 }
168169
169 mir::client::rpc::DisplayServer& display_server();170 mir::client::rpc::DisplayServer& display_server();
171 mir::client::rpc::DisplayServerDebug& debug_display_server();
170 std::shared_ptr<mir::logging::Logger> const& the_logger() const;172 std::shared_ptr<mir::logging::Logger> const& the_logger() const;
171173
172private:174private:
175 //google cant have callbacks with more than 2 args
176 struct SurfaceCreationRequest
177 {
178 SurfaceCreationRequest(mir_surface_callback cb, void* context, MirSurfaceSpec const& spec) :
179 cb(cb), context(context), spec(spec),
180 response(std::make_shared<mir::protobuf::Surface>()),
181 wh(std::make_shared<MirWaitHandle>())
182 {
183 }
184 mir_surface_callback cb;
185 void* context;
186 MirSurfaceSpec const spec;
187 std::shared_ptr<mir::protobuf::Surface> response;
188 std::shared_ptr<MirWaitHandle> wh;
189 };
190 std::vector<std::shared_ptr<SurfaceCreationRequest>> surface_requests;
191 void surface_created(SurfaceCreationRequest*);
192
173 void populate_server_package(MirPlatformPackage& platform_package) override;193 void populate_server_package(MirPlatformPackage& platform_package) override;
174 // MUST be first data member so it is destroyed last.194 // MUST be first data member so it is destroyed last.
175 struct Deregisterer195 struct Deregisterer
@@ -191,6 +211,9 @@
191 std::unique_ptr<mir::protobuf::Void> set_base_display_configuration_response;211 std::unique_ptr<mir::protobuf::Void> set_base_display_configuration_response;
192 std::atomic<bool> disconnecting{false};212 std::atomic<bool> disconnecting{false};
193213
214 mir::frontend::SurfaceId next_error_id(std::unique_lock<std::mutex> const&);
215 int surface_error_id{-1};
216
194 std::shared_ptr<mir::client::ClientPlatformFactory> const client_platform_factory;217 std::shared_ptr<mir::client::ClientPlatformFactory> const client_platform_factory;
195 std::shared_ptr<mir::client::ClientPlatform> platform;218 std::shared_ptr<mir::client::ClientPlatform> platform;
196 std::shared_ptr<EGLNativeDisplayType> native_display;219 std::shared_ptr<EGLNativeDisplayType> native_display;
197220
=== modified file 'src/client/mir_surface.cpp'
--- src/client/mir_surface.cpp 2015-12-17 15:58:42 +0000
+++ src/client/mir_surface.cpp 2016-01-13 19:10:37 +0000
@@ -49,77 +49,6 @@
49{49{
50std::mutex handle_mutex;50std::mutex handle_mutex;
51std::unordered_set<MirSurface*> valid_surfaces;51std::unordered_set<MirSurface*> valid_surfaces;
52
53mir::protobuf::SurfaceParameters serialize_spec(MirSurfaceSpec const& spec)
54{
55 mp::SurfaceParameters message;
56
57#define SERIALIZE_OPTION_IF_SET(option) \
58 if (spec.option.is_set()) \
59 message.set_##option(spec.option.value());
60
61 SERIALIZE_OPTION_IF_SET(width);
62 SERIALIZE_OPTION_IF_SET(height);
63 SERIALIZE_OPTION_IF_SET(pixel_format);
64 SERIALIZE_OPTION_IF_SET(buffer_usage);
65 SERIALIZE_OPTION_IF_SET(surface_name);
66 SERIALIZE_OPTION_IF_SET(output_id);
67 SERIALIZE_OPTION_IF_SET(type);
68 SERIALIZE_OPTION_IF_SET(state);
69 SERIALIZE_OPTION_IF_SET(pref_orientation);
70 SERIALIZE_OPTION_IF_SET(edge_attachment);
71 SERIALIZE_OPTION_IF_SET(min_width);
72 SERIALIZE_OPTION_IF_SET(min_height);
73 SERIALIZE_OPTION_IF_SET(max_width);
74 SERIALIZE_OPTION_IF_SET(max_height);
75 SERIALIZE_OPTION_IF_SET(width_inc);
76 SERIALIZE_OPTION_IF_SET(height_inc);
77 // min_aspect is a special case (below)
78 // max_aspect is a special case (below)
79
80 if (spec.parent.is_set() && spec.parent.value() != nullptr)
81 message.set_parent_id(spec.parent.value()->id());
82
83 if (spec.parent_id)
84 {
85 auto id = message.mutable_parent_persistent_id();
86 id->set_value(spec.parent_id->as_string());
87 }
88
89 if (spec.aux_rect.is_set())
90 {
91 message.mutable_aux_rect()->set_left(spec.aux_rect.value().left);
92 message.mutable_aux_rect()->set_top(spec.aux_rect.value().top);
93 message.mutable_aux_rect()->set_width(spec.aux_rect.value().width);
94 message.mutable_aux_rect()->set_height(spec.aux_rect.value().height);
95 }
96
97 if (spec.min_aspect.is_set())
98 {
99 message.mutable_min_aspect()->set_width(spec.min_aspect.value().width);
100 message.mutable_min_aspect()->set_height(spec.min_aspect.value().height);
101 }
102
103 if (spec.max_aspect.is_set())
104 {
105 message.mutable_max_aspect()->set_width(spec.max_aspect.value().width);
106 message.mutable_max_aspect()->set_height(spec.max_aspect.value().height);
107 }
108
109 if (spec.input_shape.is_set())
110 {
111 for (auto const& rect : spec.input_shape.value())
112 {
113 auto const new_shape = message.add_input_shape();
114 new_shape->set_left(rect.left);
115 new_shape->set_top(rect.top);
116 new_shape->set_width(rect.width);
117 new_shape->set_height(rect.height);
118 }
119 }
120
121 return message;
122}
123}52}
12453
125MirSurfaceSpec::MirSurfaceSpec(54MirSurfaceSpec::MirSurfaceSpec(
@@ -159,10 +88,17 @@
159 return string_id;88 return string_id;
160}89}
16190
162MirSurface::MirSurface(std::string const& error)91MirSurface::MirSurface(
163 : surface{mcl::make_protobuf_object<mir::protobuf::Surface>()}92 std::string const& error,
93 MirConnection* conn,
94 mir::frontend::SurfaceId id,
95 std::shared_ptr<MirWaitHandle> const& handle) :
96 surface{mcl::make_protobuf_object<mir::protobuf::Surface>()},
97 connection_(conn),
98 creation_handle(handle)
164{99{
165 surface->set_error(error);100 surface->set_error(error);
101 surface->mutable_id()->set_value(id.as_value());
166102
167 std::lock_guard<decltype(handle_mutex)> lock(handle_mutex);103 std::lock_guard<decltype(handle_mutex)> lock(handle_mutex);
168 valid_surfaces.insert(this);104 valid_surfaces.insert(this);
@@ -172,25 +108,30 @@
172 MirConnection *allocating_connection,108 MirConnection *allocating_connection,
173 mclr::DisplayServer& the_server,109 mclr::DisplayServer& the_server,
174 mclr::DisplayServerDebug* debug,110 mclr::DisplayServerDebug* debug,
175 std::shared_ptr<mcl::ClientBufferStreamFactory> const& buffer_stream_factory,111 std::shared_ptr<mcl::ClientBufferStream> const& buffer_stream,
176 std::shared_ptr<mircv::InputPlatform> const& input_platform,112 std::shared_ptr<mircv::InputPlatform> const& input_platform,
177 MirSurfaceSpec const& spec,113 MirSurfaceSpec const& spec,
178 mir_surface_callback callback, void * context)114 mir::protobuf::Surface const& surface_proto,
115 std::shared_ptr<MirWaitHandle> const& handle)
179 : server{&the_server},116 : server{&the_server},
180 debug{debug},117 debug{debug},
181 surface{mcl::make_protobuf_object<mir::protobuf::Surface>()},118 surface{mcl::make_protobuf_object<mir::protobuf::Surface>(surface_proto)},
182 persistent_id{mcl::make_protobuf_object<mir::protobuf::PersistentSurfaceId>()},119 persistent_id{mcl::make_protobuf_object<mir::protobuf::PersistentSurfaceId>()},
183 name{spec.surface_name.is_set() ? spec.surface_name.value() : ""},120 name{spec.surface_name.is_set() ? spec.surface_name.value() : ""},
184 void_response{mcl::make_protobuf_object<mir::protobuf::Void>()},121 void_response{mcl::make_protobuf_object<mir::protobuf::Void>()},
185 modify_result{mcl::make_protobuf_object<mir::protobuf::Void>()},122 modify_result{mcl::make_protobuf_object<mir::protobuf::Void>()},
186 connection(allocating_connection),123 connection_(allocating_connection),
187 buffer_stream_factory(buffer_stream_factory),124 buffer_stream(buffer_stream),
188 input_platform(input_platform),125 input_platform(input_platform),
189 keymapper(std::make_shared<mircv::XKBMapper>()),126 keymapper(std::make_shared<mircv::XKBMapper>()),
190 configure_result{mcl::make_protobuf_object<mir::protobuf::SurfaceSetting>()}127 configure_result{mcl::make_protobuf_object<mir::protobuf::SurfaceSetting>()},
128 creation_handle(handle)
191{129{
192 for (int i = 0; i < mir_surface_attribs; i++)130 for(int i = 0; i < surface_proto.attributes_size(); i++)
193 attrib_cache[i] = -1;131 {
132 auto const& attrib = surface_proto.attributes(i);
133 attrib_cache[attrib.attrib()] = attrib.ivalue();
134 }
194135
195 if (spec.event_handler.is_set())136 if (spec.event_handler.is_set())
196 {137 {
@@ -201,16 +142,10 @@
201 spec.event_handler.value().context);142 spec.event_handler.value().context);
202 }143 }
203144
204 auto const message = serialize_spec(spec);145 if (surface_proto.fd_size() > 0 && handle_event_callback)
205 create_wait_handle.expect_result();146 {
206 try 147 input_thread = std::make_shared<md::ThreadedDispatcher>("Input dispatch",
207 {148 input_platform->create_input_receiver( surface_proto.fd(0), keymapper, handle_event_callback));
208 server->create_surface(&message, surface.get(), gp::NewCallback(this, &MirSurface::created, callback, context));
209 }
210 catch (std::exception const& ex)
211 {
212 surface->set_error(std::string{"Error invoking create surface: "} +
213 boost::diagnostic_information(ex));
214 }149 }
215150
216 std::lock_guard<decltype(handle_mutex)> lock(handle_mutex);151 std::lock_guard<decltype(handle_mutex)> lock(handle_mutex);
@@ -303,11 +238,6 @@
303 return &persistent_id_wait_handle;238 return &persistent_id_wait_handle;
304}239}
305240
306MirWaitHandle* MirSurface::get_create_wait_handle()
307{
308 return &create_wait_handle;
309}
310
311/* todo: all these conversion functions are a bit of a kludge, probably241/* todo: all these conversion functions are a bit of a kludge, probably
312 better to have a more developed MirPixelFormat that can handle this */242 better to have a more developed MirPixelFormat that can handle this */
313MirPixelFormat MirSurface::convert_ipc_pf_to_geometry(gp::int32 pf) const243MirPixelFormat MirSurface::convert_ipc_pf_to_geometry(gp::int32 pf) const
@@ -315,89 +245,6 @@
315 return static_cast<MirPixelFormat>(pf);245 return static_cast<MirPixelFormat>(pf);
316}246}
317247
318void MirSurface::created(mir_surface_callback callback, void * context)
319{
320 {
321 std::lock_guard<decltype(mutex)> lock(mutex);
322 if (!surface->has_id())
323 {
324 if (!surface->has_error())
325 surface->set_error("Error processing surface create response, no ID (disconnected?)");
326
327 callback(this, context);
328 create_wait_handle.result_received();
329 return;
330 }
331 }
332 try
333 {
334 {
335 geom::Size size{surface->width(), surface->height()};
336 auto stream = buffer_stream_factory->
337 make_producer_stream(connection, *server, surface->buffer_stream(), name, size);
338
339 std::lock_guard<decltype(mutex)> lock(mutex);
340 buffer_stream = std::move(stream);
341 for(int i = 0; i < surface->attributes_size(); i++)
342 {
343 auto const& attrib = surface->attributes(i);
344 attrib_cache[attrib.attrib()] = attrib.ivalue();
345 }
346 }
347
348 connection->on_surface_created(id(), this);
349 }
350 catch (std::exception const& error)
351 {
352 // failed to create buffer_stream, so clean up FDs it doesn't own
353 if (!buffer_stream)
354 for (int i = 0; i < surface->buffer_stream().buffer().fd_size(); i++)
355 ::close(surface->buffer_stream().buffer().fd(i));
356
357 surface->set_error(std::string{"Error processing Surface creating response:"} +
358 boost::diagnostic_information(error));
359 }
360
361 if (surface->fd_size() > 0 && handle_event_callback)
362 {
363 auto input_dispatcher = input_platform->create_input_receiver(surface->fd(0),
364 keymapper,
365 handle_event_callback);
366 input_thread = std::make_shared<md::ThreadedDispatcher>("Input dispatch", input_dispatcher);
367 }
368
369 callback(this, context);
370 create_wait_handle.result_received();
371}
372
373MirWaitHandle* MirSurface::release_surface(
374 mir_surface_callback callback,
375 void * context)
376{
377 bool was_valid = false;
378 {
379 std::lock_guard<decltype(handle_mutex)> lock(handle_mutex);
380 if (valid_surfaces.count(this))
381 was_valid = true;
382 valid_surfaces.erase(this);
383 }
384 if (this->surface->has_error())
385 was_valid = false;
386
387 MirWaitHandle* wait_handle{nullptr};
388 if (connection && was_valid)
389 {
390 wait_handle = connection->release_surface(this, callback, context);
391 }
392 else
393 {
394 callback(this, context);
395 delete this;
396 }
397
398 return wait_handle;
399}
400
401MirWaitHandle* MirSurface::configure_cursor(MirCursorConfiguration const* cursor)248MirWaitHandle* MirSurface::configure_cursor(MirCursorConfiguration const* cursor)
402{249{
403 mp::CursorSetting setting;250 mp::CursorSetting setting;
@@ -779,3 +626,8 @@
779626
780 return &modify_wait_handle;627 return &modify_wait_handle;
781}628}
629
630MirConnection* MirSurface::connection() const
631{
632 return connection_;
633}
782634
=== modified file 'src/client/mir_surface.h'
--- src/client/mir_surface.h 2015-12-17 15:51:08 +0000
+++ src/client/mir_surface.h 2016-01-13 19:10:37 +0000
@@ -25,6 +25,7 @@
25#include "rpc/mir_display_server_debug.h"25#include "rpc/mir_display_server_debug.h"
2626
27#include "mir/client_platform.h"27#include "mir/client_platform.h"
28#include "mir/frontend/surface_id.h"
28#include "mir/optional_value.h"29#include "mir/optional_value.h"
29#include "mir/geometry/dimensions.h"30#include "mir/geometry/dimensions.h"
30#include "mir_toolkit/common.h"31#include "mir_toolkit/common.h"
@@ -100,7 +101,7 @@
100 mir::optional_value<MirOrientationMode> pref_orientation;101 mir::optional_value<MirOrientationMode> pref_orientation;
101102
102 mir::optional_value<MirSurface*> parent;103 mir::optional_value<MirSurface*> parent;
103 std::unique_ptr<MirPersistentId> parent_id;104 std::shared_ptr<MirPersistentId> parent_id;
104 mir::optional_value<MirRectangle> aux_rect;105 mir::optional_value<MirRectangle> aux_rect;
105 mir::optional_value<MirEdgeAttachment> edge_attachment;106 mir::optional_value<MirEdgeAttachment> edge_attachment;
106107
@@ -140,28 +141,27 @@
140 MirSurface(MirSurface const &) = delete;141 MirSurface(MirSurface const &) = delete;
141 MirSurface& operator=(MirSurface const &) = delete;142 MirSurface& operator=(MirSurface const &) = delete;
142143
143 MirSurface(std::string const& error);144 MirSurface(
145 std::string const& error,
146 MirConnection *allocating_connection,
147 mir::frontend::SurfaceId surface_id,
148 std::shared_ptr<MirWaitHandle> const& handle);
144149
145 MirSurface(150 MirSurface(
146 MirConnection *allocating_connection,151 MirConnection *allocating_connection,
147 mir::client::rpc::DisplayServer& server,152 mir::client::rpc::DisplayServer& server,
148 mir::client::rpc::DisplayServerDebug* debug,153 mir::client::rpc::DisplayServerDebug* debug,
149 std::shared_ptr<mir::client::ClientBufferStreamFactory> const& buffer_stream_factory,154 std::shared_ptr<mir::client::ClientBufferStream> const& buffer_stream,
150 std::shared_ptr<mir::input::receiver::InputPlatform> const& input_platform,155 std::shared_ptr<mir::input::receiver::InputPlatform> const& input_platform,
151 MirSurfaceSpec const& spec,156 MirSurfaceSpec const& spec, mir::protobuf::Surface const& surface_proto,
152 mir_surface_callback callback, void * context);157 std::shared_ptr<MirWaitHandle> const& handle);
153158
154 ~MirSurface();159 ~MirSurface();
155160
156 MirWaitHandle* release_surface(
157 mir_surface_callback callback,
158 void *context);
159
160 MirSurfaceParameters get_parameters() const;161 MirSurfaceParameters get_parameters() const;
161 char const * get_error_message();162 char const * get_error_message();
162 int id() const;163 int id() const;
163164
164 MirWaitHandle* get_create_wait_handle();
165 MirWaitHandle* configure(MirSurfaceAttrib a, int value);165 MirWaitHandle* configure(MirSurfaceAttrib a, int value);
166166
167 // TODO: Some sort of extension mechanism so that this can be moved167 // TODO: Some sort of extension mechanism so that this can be moved
@@ -192,12 +192,12 @@
192 static bool is_valid(MirSurface* query);192 static bool is_valid(MirSurface* query);
193193
194 MirWaitHandle* request_persistent_id(mir_surface_id_callback callback, void* context);194 MirWaitHandle* request_persistent_id(mir_surface_id_callback callback, void* context);
195 MirConnection* connection() const;
195private:196private:
196 std::mutex mutable mutex; // Protects all members of *this197 std::mutex mutable mutex; // Protects all members of *this
197198
198 void on_configured();199 void on_configured();
199 void on_cursor_configured();200 void on_cursor_configured();
200 void created(mir_surface_callback callback, void* context);
201 void acquired_persistent_id(mir_surface_id_callback callback, void* context);201 void acquired_persistent_id(mir_surface_id_callback callback, void* context);
202 MirPixelFormat convert_ipc_pf_to_geometry(google::protobuf::int32 pf) const;202 MirPixelFormat convert_ipc_pf_to_geometry(google::protobuf::int32 pf) const;
203203
@@ -213,14 +213,12 @@
213 MirWaitHandle modify_wait_handle;213 MirWaitHandle modify_wait_handle;
214 std::unique_ptr<mir::protobuf::Void> const modify_result;214 std::unique_ptr<mir::protobuf::Void> const modify_result;
215215
216 MirConnection* const connection{nullptr};216 MirConnection* const connection_;
217217
218 MirWaitHandle create_wait_handle;
219 MirWaitHandle configure_wait_handle;218 MirWaitHandle configure_wait_handle;
220 MirWaitHandle configure_cursor_wait_handle;219 MirWaitHandle configure_cursor_wait_handle;
221 MirWaitHandle persistent_id_wait_handle;220 MirWaitHandle persistent_id_wait_handle;
222221
223 std::shared_ptr<mir::client::ClientBufferStreamFactory> const buffer_stream_factory;
224 std::shared_ptr<mir::client::ClientBufferStream> buffer_stream;222 std::shared_ptr<mir::client::ClientBufferStream> buffer_stream;
225 std::shared_ptr<mir::input::receiver::InputPlatform> const input_platform;223 std::shared_ptr<mir::input::receiver::InputPlatform> const input_platform;
226 std::shared_ptr<mir::input::receiver::XKBMapper> const keymapper;224 std::shared_ptr<mir::input::receiver::XKBMapper> const keymapper;
@@ -234,6 +232,10 @@
234 std::function<void(MirEvent const*)> handle_event_callback;232 std::function<void(MirEvent const*)> handle_event_callback;
235 std::shared_ptr<mir::dispatch::ThreadedDispatcher> input_thread;233 std::shared_ptr<mir::dispatch::ThreadedDispatcher> input_thread;
236 bool auto_resize_stream{true};234 bool auto_resize_stream{true};
235
236 //a bit batty, but the creation handle has to exist for as long as the MirSurface does,
237 //as we don't really manage the lifetime of MirWaitHandle sensibly.
238 std::shared_ptr<MirWaitHandle> const creation_handle;
237};239};
238240
239#endif /* MIR_CLIENT_PRIVATE_MIR_WAIT_HANDLE_H_ */241#endif /* MIR_CLIENT_PRIVATE_MIR_WAIT_HANDLE_H_ */
240242
=== modified file 'src/client/mir_surface_api.cpp'
--- src/client/mir_surface_api.cpp 2015-10-14 16:16:08 +0000
+++ src/client/mir_surface_api.cpp 2016-01-13 19:10:37 +0000
@@ -152,9 +152,6 @@
152 }152 }
153 catch (std::exception const& error)153 catch (std::exception const& error)
154 {154 {
155 auto error_surf = new MirSurface{std::string{"Failed to create surface: "} +
156 boost::diagnostic_information(error)};
157 (*callback)(error_surf, context);
158 return nullptr;155 return nullptr;
159 }156 }
160}157}
@@ -258,9 +255,10 @@
258 MirSurface* surface,255 MirSurface* surface,
259 mir_surface_callback callback, void* context)256 mir_surface_callback callback, void* context)
260{257{
258 auto connection = surface->connection();
261 try259 try
262 {260 {
263 return surface->release_surface(callback, context);261 return connection->release_surface(surface, callback, context);
264 }262 }
265 catch (std::exception const& ex)263 catch (std::exception const& ex)
266 {264 {
267265
=== modified file 'src/client/surface_map.cpp'
--- src/client/surface_map.cpp 2015-12-15 15:42:37 +0000
+++ src/client/surface_map.cpp 2016-01-13 19:10:37 +0000
@@ -31,7 +31,7 @@
3131
32mcl::ConnectionSurfaceMap::~ConnectionSurfaceMap() noexcept32mcl::ConnectionSurfaceMap::~ConnectionSurfaceMap() noexcept
33{33{
34 std::unordered_map<frontend::SurfaceId, MirSurface*> surface_map;34 std::unordered_map<frontend::SurfaceId, std::shared_ptr<MirSurface>> surface_map;
35 std::unordered_map<frontend::BufferStreamId, StreamInfo> stream_map;35 std::unordered_map<frontend::BufferStreamId, StreamInfo> stream_map;
36 {36 {
37 //Prevent TSAN from flagging lock ordering issues37 //Prevent TSAN from flagging lock ordering issues
@@ -42,14 +42,8 @@
42 stream_map = std::move(streams);42 stream_map = std::move(streams);
43 }43 }
4444
45 // Unless the client has screwed up there should be no surfaces left45 // Unless the client has screwed up there should be no streams left
46 // here. (OTOH *we* don't need to leak memory when clients screw up.)46 // here. (OTOH *we* don't need to leak memory when clients screw up.)
47 for (auto const& surface : surface_map)
48 {
49 if (MirSurface::is_valid(surface.second))
50 delete surface.second;
51 }
52
53 for (auto const& info : stream_map)47 for (auto const& info : stream_map)
54 {48 {
55 if (info.second.owned)49 if (info.second.owned)
@@ -65,7 +59,7 @@
65 if (it != surfaces.end())59 if (it != surfaces.end())
66 {60 {
67 auto const surface = it->second;61 auto const surface = it->second;
68 exec(surface);62 exec(surface.get());
69 }63 }
70 else64 else
71 {65 {
@@ -75,7 +69,7 @@
75 }69 }
76}70}
7771
78void mcl::ConnectionSurfaceMap::insert(mf::SurfaceId surface_id, MirSurface* surface)72void mcl::ConnectionSurfaceMap::insert(mf::SurfaceId surface_id, std::shared_ptr<MirSurface> const& surface)
79{73{
80 // get_buffer_stream has internal locks - call before locking mutex to74 // get_buffer_stream has internal locks - call before locking mutex to
81 // avoid locking ordering issues75 // avoid locking ordering issues
8276
=== modified file 'src/client/surface_map.h'
--- src/client/surface_map.h 2015-07-16 07:03:19 +0000
+++ src/client/surface_map.h 2016-01-13 19:10:37 +0000
@@ -22,6 +22,7 @@
22#include "mir/frontend/surface_id.h"22#include "mir/frontend/surface_id.h"
23#include "mir/frontend/buffer_stream_id.h"23#include "mir/frontend/buffer_stream_id.h"
24#include <functional>24#include <functional>
25#include <memory>
2526
26struct MirSurface;27struct MirSurface;
2728
2829
=== modified file 'tests/unit-tests/client/test_client_mir_surface.cpp'
--- tests/unit-tests/client/test_client_mir_surface.cpp 2015-12-16 20:01:21 +0000
+++ tests/unit-tests/client/test_client_mir_surface.cpp 2016-01-13 19:10:37 +0000
@@ -51,8 +51,7 @@
5151
52#include <boost/throw_exception.hpp>52#include <boost/throw_exception.hpp>
53#include "mir/test/doubles/stub_client_buffer_factory.h"53#include "mir/test/doubles/stub_client_buffer_factory.h"
54#include "mir/test/doubles/stub_client_buffer_stream_factory.h"54#include "mir/test/doubles/stub_buffer_stream.h"
55#include "mir/test/doubles/mock_client_buffer_stream_factory.h"
56#include "mir/test/doubles/mock_client_buffer_stream.h"55#include "mir/test/doubles/mock_client_buffer_stream.h"
5756
58#include "mir_test_framework/stub_client_platform_factory.h"57#include "mir_test_framework/stub_client_platform_factory.h"
@@ -139,7 +138,6 @@
139138
140 static std::map<int, int> sent_surface_attributes;139 static std::map<int, int> sent_surface_attributes;
141140
142private:
143 void generate_unique_buffer()141 void generate_unique_buffer()
144 {142 {
145 global_buffer_id++;143 global_buffer_id++;
@@ -278,10 +276,6 @@
278{276{
279}277}
280278
281void null_surface_callback(MirSurface*, void*)
282{
283}
284
285void null_event_callback(MirSurface*, MirEvent const*, void*)279void null_event_callback(MirSurface*, MirEvent const*, void*)
286{280{
287}281}
@@ -294,6 +288,8 @@
294{288{
295 MirClientSurfaceTest()289 MirClientSurfaceTest()
296 {290 {
291 mock_server_tool->create_surface_response(&surface_proto);
292 ON_CALL(*stub_buffer_stream, swap_interval()).WillByDefault(testing::Return(1));
297 start_test_server();293 start_test_server();
298 connect_to_test_server();294 connect_to_test_server();
299 }295 }
@@ -333,50 +329,47 @@
333 connection.get(),329 connection.get(),
334 server_stub,330 server_stub,
335 nullptr,331 nullptr,
336 stub_buffer_stream_factory,332 stub_buffer_stream,
337 input_platform,333 input_platform,
338 spec,334 spec,
339 &null_surface_callback,335 surface_proto,
340 nullptr);336 wh);
341 }337 }
342338
343 std::shared_ptr<MirSurface> create_surface_with(339 std::shared_ptr<MirSurface> create_surface_with(
344 mclr::DisplayServer& server_stub,340 mclr::DisplayServer& server_stub,
345 std::shared_ptr<mcl::ClientBufferStreamFactory> const& buffer_stream_factory)341 std::shared_ptr<mcl::ClientBufferStream> const& buffer_stream)
346 {342 {
347 return std::make_shared<MirSurface>(343 return std::make_shared<MirSurface>(
348 connection.get(),344 connection.get(),
349 server_stub,345 server_stub,
350 nullptr,346 nullptr,
351 buffer_stream_factory,347 buffer_stream,
352 input_platform,348 input_platform,
353 spec,349 spec,
354 &null_surface_callback,350 surface_proto,
355 nullptr);351 wh);
356 }352 }
357353
358 std::shared_ptr<MirSurface> create_and_wait_for_surface_with(354 std::shared_ptr<MirSurface> create_and_wait_for_surface_with(
359 mclr::DisplayServer& server_stub)355 mclr::DisplayServer& server_stub)
360 {356 {
361 auto surface = create_surface_with(server_stub);357 auto surface = create_surface_with(server_stub);
362 surface->get_create_wait_handle()->wait_for_all();
363 return surface;358 return surface;
364 }359 }
365360
366 std::shared_ptr<MirSurface> create_and_wait_for_surface_with(361 std::shared_ptr<MirSurface> create_and_wait_for_surface_with(
367 mclr::DisplayServer& server_stub,362 mclr::DisplayServer& server_stub,
368 std::shared_ptr<mcl::ClientBufferStreamFactory> const& buffer_stream_factory)363 std::shared_ptr<mcl::ClientBufferStream> const& buffer_stream)
369 {364 {
370 auto surface = create_surface_with(server_stub, buffer_stream_factory);365 auto surface = create_surface_with(server_stub, buffer_stream);
371 surface->get_create_wait_handle()->wait_for_all();
372 return surface;366 return surface;
373 }367 }
374368
375 std::shared_ptr<MirConnection> connection;369 std::shared_ptr<MirConnection> connection;
376370
377 MirSurfaceSpec const spec{nullptr, 33, 45, mir_pixel_format_abgr_8888};371 MirSurfaceSpec const spec{nullptr, 33, 45, mir_pixel_format_abgr_8888};
378 std::shared_ptr<mtd::StubClientBufferStreamFactory> const stub_buffer_stream_factory =372 std::shared_ptr<mtd::MockClientBufferStream> stub_buffer_stream{std::make_shared<mtd::MockClientBufferStream>()};
379 std::make_shared<mtd::StubClientBufferStreamFactory>();
380 std::shared_ptr<StubClientInputPlatform> const input_platform =373 std::shared_ptr<StubClientInputPlatform> const input_platform =
381 std::make_shared<StubClientInputPlatform>();374 std::make_shared<StubClientInputPlatform>();
382 std::shared_ptr<MockServerPackageGenerator> const mock_server_tool =375 std::shared_ptr<MockServerPackageGenerator> const mock_server_tool =
@@ -385,6 +378,8 @@
385 std::shared_ptr<mcl::ConnectionSurfaceMap> surface_map;378 std::shared_ptr<mcl::ConnectionSurfaceMap> surface_map;
386 std::shared_ptr<mt::TestProtobufServer> test_server;379 std::shared_ptr<mt::TestProtobufServer> test_server;
387 std::shared_ptr<mclr::DisplayServer> client_comm_channel;380 std::shared_ptr<mclr::DisplayServer> client_comm_channel;
381 mir::protobuf::Surface surface_proto;
382 std::shared_ptr<MirWaitHandle> const wh{std::make_shared<MirWaitHandle>()};
388383
389 std::chrono::milliseconds const pause_time{10};384 std::chrono::milliseconds const pause_time{10};
390};385};
@@ -403,22 +398,6 @@
403 }398 }
404}399}
405400
406TEST_F(MirClientSurfaceTest, create_wait_handle_really_blocks)
407{
408 using namespace testing;
409
410 FakeRpcChannel fake_channel;
411 mclr::DisplayServer unresponsive_server{mt::fake_shared(fake_channel)};
412
413 auto const surface = create_surface_with(unresponsive_server);
414 auto wait_handle = surface->get_create_wait_handle();
415
416 auto expected_end = std::chrono::steady_clock::now() + pause_time;
417 wait_handle->wait_for_pending(pause_time);
418
419 EXPECT_GE(std::chrono::steady_clock::now(), expected_end);
420}
421
422TEST_F(MirClientSurfaceTest, creates_input_thread_with_input_dispatcher_when_delegate_specified)401TEST_F(MirClientSurfaceTest, creates_input_thread_with_input_dispatcher_when_delegate_specified)
423{402{
424 using namespace ::testing;403 using namespace ::testing;
@@ -432,9 +411,7 @@
432 .WillOnce(Return(mock_input_dispatcher));411 .WillOnce(Return(mock_input_dispatcher));
433412
434 MirSurface surface{connection.get(), *client_comm_channel, nullptr,413 MirSurface surface{connection.get(), *client_comm_channel, nullptr,
435 stub_buffer_stream_factory, mock_input_platform, spec, &null_surface_callback, nullptr};414 stub_buffer_stream, mock_input_platform, spec, surface_proto, wh};
436 auto wait_handle = surface.get_create_wait_handle();
437 wait_handle->wait_for_all();
438 surface.set_event_handler(null_event_callback, nullptr);415 surface.set_event_handler(null_event_callback, nullptr);
439416
440 mock_input_dispatcher->trigger();417 mock_input_dispatcher->trigger();
@@ -455,9 +432,7 @@
455 .WillOnce(Return(mock_input_dispatcher));432 .WillOnce(Return(mock_input_dispatcher));
456433
457 MirSurface surface{connection.get(), *client_comm_channel, nullptr,434 MirSurface surface{connection.get(), *client_comm_channel, nullptr,
458 stub_buffer_stream_factory, mock_input_platform, spec, &null_surface_callback, nullptr};435 stub_buffer_stream, mock_input_platform, spec, surface_proto, wh};
459 auto wait_handle = surface.get_create_wait_handle();
460 wait_handle->wait_for_all();
461 surface.set_event_handler(null_event_callback, nullptr);436 surface.set_event_handler(null_event_callback, nullptr);
462437
463 // Should now not get dispatched.438 // Should now not get dispatched.
@@ -478,9 +453,7 @@
478 EXPECT_CALL(*mock_input_platform, create_input_receiver(_, _, _)).Times(0);453 EXPECT_CALL(*mock_input_platform, create_input_receiver(_, _, _)).Times(0);
479454
480 MirSurface surface{connection.get(), *client_comm_channel, nullptr,455 MirSurface surface{connection.get(), *client_comm_channel, nullptr,
481 stub_buffer_stream_factory, mock_input_platform, spec, &null_surface_callback, nullptr};456 stub_buffer_stream, mock_input_platform, spec, surface_proto, wh};
482 auto wait_handle = surface.get_create_wait_handle();
483 wait_handle->wait_for_all();
484}457}
485458
486TEST_F(MirClientSurfaceTest, valid_surface_is_valid)459TEST_F(MirClientSurfaceTest, valid_surface_is_valid)
@@ -531,12 +504,7 @@
531{504{
532 using namespace testing;505 using namespace testing;
533 auto mock_stream = std::make_shared<mtd::MockClientBufferStream>(); 506 auto mock_stream = std::make_shared<mtd::MockClientBufferStream>();
534 auto mock_stream_factory = std::make_shared<NiceMock<mtd::MockClientBufferStreamFactory>>();
535 auto mock_input_platform = std::make_shared<NiceMock<MockClientInputPlatform>>();507 auto mock_input_platform = std::make_shared<NiceMock<MockClientInputPlatform>>();
536 ON_CALL(*mock_stream_factory, make_producer_stream(_,_,_,_,An<void*>()))
537 .WillByDefault(Return(mock_stream.get()));
538 ON_CALL(*mock_stream_factory, make_producer_stream(_,_,_,_,An<geom::Size>()))
539 .WillByDefault(Return(mock_stream));
540 ON_CALL(*mock_input_platform, create_input_receiver(_,_,_))508 ON_CALL(*mock_input_platform, create_input_receiver(_,_,_))
541 .WillByDefault(Return(std::make_shared<mt::TestDispatchable>([]{})));509 .WillByDefault(Return(std::make_shared<mt::TestDispatchable>([]{})));
542 ON_CALL(*mock_stream, rpc_id()).WillByDefault(Return(mir::frontend::BufferStreamId(2)));510 ON_CALL(*mock_stream, rpc_id()).WillByDefault(Return(mir::frontend::BufferStreamId(2)));
@@ -545,11 +513,8 @@
545 EXPECT_CALL(*mock_stream, set_size(size));513 EXPECT_CALL(*mock_stream, set_size(size));
546 auto ev = mir::events::make_event(mir::frontend::SurfaceId(2), size);514 auto ev = mir::events::make_event(mir::frontend::SurfaceId(2), size);
547515
548 //FIXME: difficult construction
549 MirSurface surface{connection.get(), *client_comm_channel, nullptr,516 MirSurface surface{connection.get(), *client_comm_channel, nullptr,
550 mock_stream_factory, mock_input_platform, spec, &null_surface_callback, nullptr};517 mock_stream, mock_input_platform, spec, surface_proto, wh};
551 auto wait_handle = surface.get_create_wait_handle();
552 wait_handle->wait_for_all();
553 surface.handle_event(*ev);518 surface.handle_event(*ev);
554 surface_map->erase(mir::frontend::BufferStreamId(2));519 surface_map->erase(mir::frontend::BufferStreamId(2));
555}520}
@@ -558,13 +523,8 @@
558{523{
559 using namespace testing;524 using namespace testing;
560 auto mock_stream = std::make_shared<NiceMock<mtd::MockClientBufferStream>>();525 auto mock_stream = std::make_shared<NiceMock<mtd::MockClientBufferStream>>();
561 auto mock_stream_factory = std::make_shared<NiceMock<mtd::MockClientBufferStreamFactory>>();
562 auto mock_input_platform = std::make_shared<NiceMock<MockClientInputPlatform>>();526 auto mock_input_platform = std::make_shared<NiceMock<MockClientInputPlatform>>();
563 ON_CALL(*mock_stream, rpc_id()).WillByDefault(Return(mir::frontend::BufferStreamId(2)));527 ON_CALL(*mock_stream, rpc_id()).WillByDefault(Return(mir::frontend::BufferStreamId(2)));
564 ON_CALL(*mock_stream_factory, make_producer_stream(_,_,_,_,An<void*>()))
565 .WillByDefault(Return(mock_stream.get()));
566 ON_CALL(*mock_stream_factory, make_producer_stream(_,_,_,_,An<geom::Size>()))
567 .WillByDefault(Return(mock_stream));
568 ON_CALL(*mock_input_platform, create_input_receiver(_,_,_))528 ON_CALL(*mock_input_platform, create_input_receiver(_,_,_))
569 .WillByDefault(Return(std::make_shared<mt::TestDispatchable>([]{})));529 .WillByDefault(Return(std::make_shared<mt::TestDispatchable>([]{})));
570530
@@ -572,8 +532,7 @@
572 EXPECT_CALL(*mock_stream, set_size(size)).Times(0);532 EXPECT_CALL(*mock_stream, set_size(size)).Times(0);
573 auto ev = mir::events::make_event(mir::frontend::SurfaceId(2), size);533 auto ev = mir::events::make_event(mir::frontend::SurfaceId(2), size);
574 MirSurface surface{connection.get(), *client_comm_channel, nullptr,534 MirSurface surface{connection.get(), *client_comm_channel, nullptr,
575 mock_stream_factory, mock_input_platform, spec, &null_surface_callback, nullptr};535 mock_stream, mock_input_platform, spec, surface_proto, wh};
576 surface.get_create_wait_handle()->wait_for_all();
577536
578 MirSurfaceSpec spec;537 MirSurfaceSpec spec;
579 std::vector<MirBufferStreamInfo> info =538 std::vector<MirBufferStreamInfo> info =
580539
=== modified file 'tests/unit-tests/client/test_connection_resource_map.cpp'
--- tests/unit-tests/client/test_connection_resource_map.cpp 2015-07-16 07:03:19 +0000
+++ tests/unit-tests/client/test_connection_resource_map.cpp 2016-01-13 19:10:37 +0000
@@ -27,7 +27,8 @@
2727
28struct ConnectionResourceMap : testing::Test28struct ConnectionResourceMap : testing::Test
29{29{
30 MirSurface surface{"a string"};30 std::shared_ptr<MirWaitHandle> wh { std::make_shared<MirWaitHandle>() };
31 std::shared_ptr<MirSurface> surface{std::make_shared<MirSurface>("a string", nullptr, mf::SurfaceId{2}, wh)};
31 mtd::MockClientBufferStream stream; 32 mtd::MockClientBufferStream stream;
32 mf::SurfaceId const surface_id{43};33 mf::SurfaceId const surface_id{43};
33 mf::BufferStreamId const stream_id{43};34 mf::BufferStreamId const stream_id{43};
@@ -39,14 +40,14 @@
39 auto surface_called = false;40 auto surface_called = false;
40 auto stream_called = false;41 auto stream_called = false;
41 mcl::ConnectionSurfaceMap map;42 mcl::ConnectionSurfaceMap map;
42 map.insert(surface_id, &surface);43 map.insert(surface_id, surface);
43 map.with_surface_do(surface_id, [&](MirSurface* surf) {44 map.with_surface_do(surface_id, [&](MirSurface* surf) {
44 EXPECT_THAT(surf, Eq(&surface));45 EXPECT_THAT(surf, Eq(surface.get()));
45 surface_called = true;46 surface_called = true;
46 });47 });
4748
48 map.with_stream_do(stream_id, [&](mcl::ClientBufferStream* stream) {49 map.with_stream_do(stream_id, [&](mcl::ClientBufferStream* stream) {
49 EXPECT_THAT(stream, Eq(surface.get_buffer_stream()));50 EXPECT_THAT(stream, Eq(surface->get_buffer_stream()));
50 stream_called = true;51 stream_called = true;
51 });52 });
5253
@@ -59,9 +60,9 @@
59 using namespace testing;60 using namespace testing;
60 auto stream_called = false;61 auto stream_called = false;
61 mcl::ConnectionSurfaceMap map;62 mcl::ConnectionSurfaceMap map;
62 map.insert(surface_id, &surface);63 map.insert(surface_id, surface);
63 map.with_stream_do(stream_id, [&](mcl::ClientBufferStream* stream) {64 map.with_stream_do(stream_id, [&](mcl::ClientBufferStream* stream) {
64 EXPECT_THAT(stream, Eq(surface.get_buffer_stream()));65 EXPECT_THAT(stream, Eq(surface->get_buffer_stream()));
65 stream_called = true;66 stream_called = true;
66 });67 });
67 EXPECT_TRUE(stream_called);68 EXPECT_TRUE(stream_called);
6869
=== modified file 'tests/unit-tests/client/test_mir_connection.cpp'
--- tests/unit-tests/client/test_mir_connection.cpp 2015-07-29 01:39:52 +0000
+++ tests/unit-tests/client/test_mir_connection.cpp 2016-01-13 19:10:37 +0000
@@ -63,7 +63,7 @@
63 ON_CALL(*this, watch_fd()).WillByDefault(testing::Return(pollable_fd));63 ON_CALL(*this, watch_fd()).WillByDefault(testing::Return(pollable_fd));
64 }64 }
6565
66 void call_method(std::string const& name,66 virtual void call_method(std::string const& name,
67 google::protobuf::MessageLite const* parameters,67 google::protobuf::MessageLite const* parameters,
68 google::protobuf::MessageLite* response,68 google::protobuf::MessageLite* response,
69 google::protobuf::Closure* complete)69 google::protobuf::Closure* complete)
@@ -83,6 +83,13 @@
83 platform_operation(static_cast<mp::PlatformOperationMessage const*>(parameters),83 platform_operation(static_cast<mp::PlatformOperationMessage const*>(parameters),
84 static_cast<mp::PlatformOperationMessage*>(response));84 static_cast<mp::PlatformOperationMessage*>(response));
85 }85 }
86 else if (name == "create_surface")
87 {
88 auto response_message = static_cast<mp::Surface*>(response);
89 response_message->mutable_id()->set_value(33);
90 response_message->mutable_buffer_stream()->mutable_id()->set_value(33);
91 }
92
8693
87 complete->Run();94 complete->Run();
88 }95 }
@@ -638,3 +645,30 @@
638 EXPECT_THAT(mir_platform_message_get_opcode(returned_response), Eq(opcode));645 EXPECT_THAT(mir_platform_message_get_opcode(returned_response), Eq(opcode));
639 mir_platform_message_release(returned_response);646 mir_platform_message_release(returned_response);
640}647}
648
649TEST_F(MirConnectionTest, create_wait_handle_really_blocks)
650{
651 using namespace testing;
652
653 std::chrono::milliseconds const pause_time{10};
654 struct FakeRpcChannel : public MockRpcChannel
655 {
656 void call_method(
657 std::string const&,
658 google::protobuf::MessageLite const*,
659 google::protobuf::MessageLite*,
660 google::protobuf::Closure* closure) override
661 {
662 delete closure;
663 }
664 };
665 TestConnectionConfiguration conf{mock_platform, std::make_shared<NiceMock<FakeRpcChannel>>()};
666 MirConnection connection(conf);
667 MirSurfaceSpec const spec{&connection, 33, 45, mir_pixel_format_abgr_8888};
668
669 auto wait_handle = connection.create_surface(spec, nullptr, nullptr);
670 auto expected_end = std::chrono::steady_clock::now() + pause_time;
671 wait_handle->wait_for_pending(pause_time);
672
673 EXPECT_GE(std::chrono::steady_clock::now(), expected_end);
674}

Subscribers

People subscribed via source and target branches