Mir

Merge lp:~raof/mir/provide-event-fd into lp:mir

Proposed by Chris Halse Rogers
Status: Work in progress
Proposed branch: lp:~raof/mir/provide-event-fd
Merge into: lp:mir
Prerequisite: lp:~raof/mir/make-input-dispatcher-a-dispatchable
Diff against target: 7460 lines (+4248/-373) (has conflicts)
87 files modified
benchmarks/benchmark_multiplexing_dispatchable.cpp (+1/-0)
debian/control (+1/-0)
examples/chain_jumping_buffers.c (+6/-0)
examples/prerendered_frames.c (+5/-0)
examples/render_surface.cpp (+20/-4)
include/client/mir_toolkit/mir_connection.h (+70/-0)
include/client/mir_toolkit/mir_wait.h (+1/-0)
include/client/mir_toolkit/rs/mir_render_surface.h (+69/-5)
include/common/mir/dispatch/threaded_dispatcher.h.moved (+75/-0)
include/test/mir/test/validity_matchers.h (+8/-0)
playground/egldiamond_render_surface.c (+5/-0)
playground/mir_egl_platform_shim.c (+9/-0)
src/client/CMakeLists.txt (+9/-0)
src/client/buffer_factory.cpp (+11/-1)
src/client/buffer_stream.cpp (+146/-38)
src/client/buffer_stream.h (+27/-3)
src/client/buffer_stream_configuration.cpp (+8/-0)
src/client/buffer_stream_configuration.h (+1/-0)
src/client/buffer_vault.cpp (+22/-5)
src/client/client_buffer_stream_factory.h.THIS (+66/-0)
src/client/connection_configuration.h (+11/-0)
src/client/connection_surface_map.cpp (+53/-1)
src/client/connection_surface_map.h (+32/-0)
src/client/default_client_buffer_stream_factory.cpp.THIS (+87/-0)
src/client/default_client_buffer_stream_factory.h.THIS (+70/-0)
src/client/default_connection_configuration.cpp (+15/-2)
src/client/default_connection_configuration.h (+2/-0)
src/client/error_render_surface.cpp (+1/-4)
src/client/error_render_surface.h (+6/-3)
src/client/mir_buffer_stream_api.cpp (+29/-14)
src/client/mir_connection.cpp (+194/-50)
src/client/mir_connection.h (+37/-11)
src/client/mir_connection_api.cpp (+159/-0)
src/client/mir_prompt_session_api.cpp (+13/-0)
src/client/mir_render_surface_api.cpp (+104/-4)
src/client/mir_screencast.cpp (+13/-2)
src/client/mir_screencast.h (+2/-1)
src/client/mir_screencast_api.cpp (+20/-3)
src/client/mir_surface.cpp (+30/-2)
src/client/mir_surface.h (+5/-2)
src/client/mir_surface_api.cpp (+25/-0)
src/client/mir_wait_api.cpp (+9/-0)
src/client/no_tls_future-inl.h (+1/-0)
src/client/render_surface.cpp (+34/-14)
src/client/render_surface.h (+6/-3)
src/client/rpc/make_rpc_channel.h (+1/-0)
src/client/rpc/mir_basic_rpc_channel.h (+8/-0)
src/client/rpc/mir_protobuf_rpc_channel.cpp (+10/-1)
src/client/rpc/mir_protobuf_rpc_channel.h (+3/-3)
src/client/symbols.map (+21/-0)
src/client/synchronous_helper.cpp (+33/-0)
src/client/synchronous_helper.h (+160/-0)
src/common/dispatch/threaded_dispatcher.cpp.moved (+294/-0)
src/include/client/mir/mir_render_surface.h (+6/-3)
src/server/scene/mediating_display_changer.cpp (+1/-1)
tests/acceptance-tests/CMakeLists.txt (+8/-0)
tests/acceptance-tests/test_client_library.cpp (+494/-0)
tests/acceptance-tests/test_client_surfaces.cpp (+40/-0)
tests/acceptance-tests/test_render_surface.cpp (+235/-20)
tests/acceptance-tests/test_server_shutdown.cpp (+1/-1)
tests/include/mir/test/doubles/mock_client_buffer_stream_factory.h.THIS (+59/-0)
tests/include/mir/test/doubles/mock_mir_buffer_stream.h (+1/-0)
tests/include/mir/test/doubles/stub_buffer_stream_factory.h (+18/-2)
tests/include/mir/test/doubles/stub_client_buffer_stream_factory.h.THIS (+66/-0)
tests/integration-tests/test_buffer_scheduling.cpp (+3/-1)
tests/integration-tests/test_surfaceloop.cpp (+60/-35)
tests/integration-tests/test_swapinterval.cpp (+2/-2)
tests/mir_test/CMakeLists.txt (+5/-1)
tests/mir_test/validity_matchers.cpp (+31/-0)
tests/mir_test_doubles/stub_buffer.cpp.THIS (+39/-0)
tests/mir_test_doubles/test_protobuf_client.cpp (+2/-1)
tests/mir_test_framework/CMakeLists.txt (+1/-0)
tests/mir_test_framework/udev_environment.cpp (+12/-4)
tests/unit-tests/client/test_buffer_vault.cpp (+2/-1)
tests/unit-tests/client/test_client_buffer_stream.cpp (+158/-82)
tests/unit-tests/client/test_client_mir_surface.cpp (+22/-0)
tests/unit-tests/client/test_connection_resource_map.cpp (+71/-5)
tests/unit-tests/client/test_mir_connection.cpp (+206/-7)
tests/unit-tests/client/test_mir_render_surface.cpp (+182/-20)
tests/unit-tests/compositor/test_stream.cpp (+1/-1)
tests/unit-tests/dispatch/CMakeLists.txt (+1/-0)
tests/unit-tests/dispatch/test_multiplexing_dispatchable.cpp (+7/-8)
tests/unit-tests/dispatch/test_threaded_dispatcher.cpp.moved (+403/-0)
tests/unit-tests/frontend/stress_protobuf_communicator.cpp (+4/-1)
tests/unit-tests/scene/test_application_session.cpp (+3/-1)
tests/unit-tests/scene/test_surface_stack.cpp (+11/-0)
tools/valgrind_suppressions_generic (+45/-0)
Text conflict in examples/chain_jumping_buffers.c
Text conflict in examples/prerendered_frames.c
Text conflict in examples/render_surface.cpp
Text conflict in include/client/mir_toolkit/rs/mir_render_surface.h
Text conflict in playground/egldiamond_render_surface.c
Text conflict in playground/mir_egl_platform_shim.c
Text conflict in src/client/CMakeLists.txt
Text conflict in src/client/buffer_stream.cpp
Text conflict in src/client/buffer_stream.h
Text conflict in src/client/connection_surface_map.cpp
Text conflict in src/client/connection_surface_map.h
Text conflict in src/client/mir_buffer_stream_api.cpp
Text conflict in src/client/mir_connection.cpp
Text conflict in src/client/mir_connection_api.cpp
Text conflict in src/client/mir_prompt_session_api.cpp
Text conflict in src/client/mir_render_surface_api.cpp
Text conflict in src/client/mir_screencast.cpp
Text conflict in src/client/mir_surface.cpp
Text conflict in src/client/mir_surface.h
Text conflict in src/client/mir_surface_api.cpp
Text conflict in src/client/rpc/mir_basic_rpc_channel.h
Text conflict in src/client/rpc/mir_protobuf_rpc_channel.cpp
Text conflict in src/client/symbols.map
Text conflict in tests/acceptance-tests/CMakeLists.txt
Text conflict in tests/acceptance-tests/test_client_library.cpp
Text conflict in tests/acceptance-tests/test_client_surfaces.cpp
Text conflict in tests/acceptance-tests/test_render_surface.cpp
Text conflict in tests/include/mir/test/doubles/stub_buffer_stream_factory.h
Text conflict in tests/integration-tests/test_surfaceloop.cpp
Text conflict in tests/unit-tests/client/test_client_buffer_stream.cpp
Text conflict in tests/unit-tests/client/test_client_mir_surface.cpp
Text conflict in tests/unit-tests/client/test_connection_resource_map.cpp
Text conflict in tests/unit-tests/client/test_mir_connection.cpp
Text conflict in tests/unit-tests/client/test_mir_render_surface.cpp
Text conflict in tests/unit-tests/scene/test_surface_stack.cpp
To merge this branch: bzr merge lp:~raof/mir/provide-event-fd
Reviewer Review Type Date Requested Status
PS Jenkins bot (community) continuous-integration Needs Fixing
Alexandros Frantzis (community) Needs Fixing
Andreas Pokorny (community) Approve
Robert Carr (community) Approve
Kevin DuBois (community) Approve
Review via email: mp+247794@code.launchpad.net

Commit message

Provide a mechanism for manual dispatch of client events.

A client can create a manually dispatched MirConnection by mir_connect_with_manual_dispatch. The client can then dispatch events by calling mir_connection_dispatch() on the MirConnection, and can know when to dispatch events by checking when the file descriptor returned from mir_connection_get_fd becomes readable.

Fixes: https://bugs.launchpad.net/mir/+bug/1397375

Description of the change

The last, client-visible component of eventloop-integration.

The relevant client API bits are mir_connect_with_manual_dispatch/mir_connection_get_fd/mir_connection_dispatch

This mostly preserves the current behaviour for automatic, threaded dispatch. The one difference is that there are now no longer dedicated threads for surfaces' input loops; instead there is now one thread per surface with input plus one for RPC that together dispatch whatever events may happen.

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
Kevin DuBois (kdub) wrote :

int mir_connection_get_fd(MirConnection* connection);
It seems more important what the fd is for, so I'd rather the fn say something about what the fd does... maybe:
int mir_connection_event_dispatch_fd(MirConnection* connection)

201 + thread_local static bool running;
Nothing wrong here, but we still haven't properly sorted out TLS with hybris. We'd probably be a bit more robust if we still avoid using TLS.

704 + if (pipe2(pipefds, O_NONBLOCK) < 0)
O_CLOEXEC?

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

On Thu, Jan 29, 2015 at 1:18 AM, Kevin DuBois
<email address hidden> wrote:
> Review: Needs Fixing
>
> int mir_connection_get_fd(MirConnection* connection);
> It seems more important what the fd is for, so I'd rather the fn say
> something about what the fd does... maybe:
> int mir_connection_event_dispatch_fd(MirConnection* connection)

Seems reasonable, I'll use that naming.
>
>
> 201 + thread_local static bool running;
> Nothing wrong here, but we still haven't properly sorted out TLS with
> hybris. We'd probably be a bit more robust if we still avoid using
> TLS.

Boo. And it was sooooo elegant.

I'll rework this to not need TLS.

>
> 704 + if (pipe2(pipefds, O_NONBLOCK) < 0)
> O_CLOEXEC?

While we're at it, yes.

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

Harumph.

So, this adds tests to TestClientLibrary that require umockdev's evemu replay functionality. I guess I'll need to (a) modify the test runner to call through umockdev-run, (b) ensure that the recordings get installed in the packages, and (c) ensure that the tests can *find* them.

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 :

looks good to me, although perhaps some clients might disagree with:
757 + // If the client is entirely unresponsive for a whole minute, it deserves to die.

review: Approve
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: Approve (continuous-integration)
Revision history for this message
Robert Carr (robertcarr) wrote :

I really like the way this turned out :)

A few nits:

+TEST_F(ClientLibrary, manual_dispatch_handles_callbacks_in_parent_thread)

I think its worth refactoring this and the following test. If you merged the TestData and test up to SurfaceCreation in to a fixture it would be possible to then split the sections of the test without duplicating code. Then the next test could not have to deal with surface states and umockdev recordings in the same test.

1888 and elsewhere + auto connection = std::make_shared<MirConnection>(conf);

You can keep connection in the fixture and then inherit from the fixture with
MirConnectionAutomaticDispatchTest and MirConnectionManualDispatchTest

Revision history for this message
Robert Carr (robertcarr) wrote :

2 small needs fixing:

The 1 second timeouts are going to fail in ARMHF valgrind.

1499 + GError* err = nullptr;

Here and at 1511 please use g_error_free (I know a leak is unlikely to matter here but its worth using the API correctly I think)

review: Needs Fixing
Revision history for this message
Robert Carr (robertcarr) wrote :

PINGGGGGGGGGGGGGGGGGGGGGGGGG

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

PIIIIING responded to :)

Revision history for this message
Robert Carr (robertcarr) wrote :

Yay. Thanks.

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

A call to mir::set_thread_name is missing.

What about exceptions that reach the dispatch_loop? Do we need something like mir_terminate_with_current_exception?

Looks good otherwise

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

> A call to mir::set_thread_name is missing.

Could be a constructor parameter to ThreadedDispatcher.. and a trivial numbering scheme.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Andreas Pokorny (andreas-pokorny) wrote :

lgtm as soon as jenkins agrees.

review: Approve
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Chris Halse Rogers (raof) wrote :

Retrigger CI now that we've got shiny new log output for the failed test.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
lp:~raof/mir/provide-event-fd updated
2351. By Chris Halse Rogers

Switch manual dispatch tests over to an eventloop thread.

This still tests that the callbacks are dispatched on the thread that called dispatch(),
but doesn't rely on implementation details like how many times you'll need to call
dispatch() after each request in order to get it processed, and is less prone to possible
races where fd readability races the while(fd_is_readable()) loop.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
lp:~raof/mir/provide-event-fd updated
2352. By Chris Halse Rogers

Merge trunk

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Alexandros Frantzis (afrantzis) wrote :

267 + dispatcher{std::shared_ptr<md::MultiplexingDispatchable>(new md::MultiplexingDispatchable{std::dynamic_pointer_cast<md::Dispatchable>(channel)})},

Why not std::make_shared?

286 + if (eventloop) abort();

It would be helpful to the poor users if we printed an informative error message before we abort.

755 + std::thread::id terminate_one_thread()

I think there is a potential race here:

T1: calls terminate_one_thread(), T2: calls terminate_one_thread()
A thread terminates, sets terminating_thread_id
Another thread terminates, sets terminating_thread_id, overwriting previous value
T1 wakes up, finds a valid terminating_thread_id, continues and clears terminating_thread_id
T2 wakes up, finds a cleared terminating_thread_id and blocks for the remainder of 60s timeout

review: Needs Fixing
lp:~raof/mir/provide-event-fd updated
2353. By Chris Halse Rogers

Add timeout to EventDispatchThread

2354. By Chris Halse Rogers

Resolve race in terminate_one_thread.

If two threads called terminate_one_thread simultaneously it was possible for
both threadpool threads to unregister before either terminate_one_thread picked the
terminating_thread_mutex lock up again.

In this case the second threadpool thread would overwrite terminating_thread_id, and the
second terminate_one_thread call would timeout.

This is fundamentally a typical producer/consumer situation; resolve it by having terminating
threads write to a queue of ids, and terminate_one_thread pull from that queue.

2355. By Chris Halse Rogers

Switch ThreadExiter over to an eventfd.

We don't actually need a pipe; an eventfd is lighter for just handling notifications.

2356. By Chris Halse Rogers

Fix handles_events_in_parent_thread test.

We need to post a buffer to the surface in order for it to be a vaild focus target!

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
lp:~raof/mir/provide-event-fd updated
2357. By Chris Halse Rogers

Merge trunk

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
lp:~raof/mir/provide-event-fd updated
2358. By Chris Halse Rogers

Merge trunk. MOAR CONFLICTS!

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
lp:~raof/mir/provide-event-fd updated
2359. By Chris Halse Rogers

Merge trunk

2360. By Chris Halse Rogers

Fix race in dispatches_multiple_dispatchees_simultaneously

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
lp:~raof/mir/provide-event-fd updated
2361. By Chris Halse Rogers

Merge trunk

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
Alan Griffiths (alan-griffiths) wrote :

2850+ auto dispatchable = std::make_shared<mt::TestDispatchable>([dispatched]()
2851+ {
2852+ static std::atomic<int> dispatch_count{0};
2853+ char buffer[80] = {0};
2854+ pthread_getname_np(pthread_self(), buffer, sizeof(buffer));
2855+ EXPECT_THAT(buffer, StartsWith(threadname_base));
2856+
2857+ if (++dispatch_count == threadcount)
2858+ {
2859+ dispatched->raise();
2860+ }
2861+ else
2862+ {
2863+ dispatched->wait_for(10s);
2864+ }
2865+ });

I'm not convinced by the massive indents that this style causes. (Nor the multi-line diffs a simple change like "auto dispatchable" => "auto const dispatchable" would imply.)

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

286 + if (eventloop) abort();

We should print out an error message before we abort so that the users have some clue of what they did wrong.

review: Needs Fixing
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Chris Halse Rogers (raof) wrote :

Oh ho ho!

While cleaning up the dispatch tests I've noticed that mir_connection_release() is an implicit synchronous RPC call, which obviously doesn't work if you're manually dispatching from the same thread that calls mir_connection_release().

Ryan *will* be pleased that I have to fix that case first!

lp:~raof/mir/provide-event-fd updated
2362. By Chris Halse Rogers

Merge trunk

2363. By Chris Halse Rogers

ClientLibrary dispatch tests: release the MirConnection from the dispatch thread.

This prevents us from accessing a freed MirConnection.

2364. By Chris Halse Rogers

Add acceptance test for async/sync call interaction with manual dispatch.

2365. By Chris Halse Rogers

Use mir::require for MirConnection::dispatch() precondition

2366. By Chris Halse Rogers

make_client_protobuf_tests_match_naming_scheme

2367. By Chris Halse Rogers

Merge trunk

2368. By Chris Halse Rogers

Improve MirProtobufRpcChanneltests.

Rather than having the mock StreamTransport manually notifying until all
data is read (somewhat defeating the purpose of the “does it read all the
data” test), have the mock StreamTransport properly implement Dispatchable
and use MirProtobufRpcChannel's Dispatchable interface to drive things.

2369. By Chris Halse Rogers

Merge prereq: ActionQueue

2370. By Chris Halse Rogers

Add an out-of-order processing mode to MirProtobufRpcChannel.

This lets a consumer wait on the result of a particular call, delaying other message
processing until it has completed.

This is required for proper *_sync handling in eventloop-driven dispatch mode.

2371. By Chris Halse Rogers

Fix mir_connection_release with manual dispatch

2372. By Chris Halse Rogers

Hook up process_next_request_first to MirConnection

2373. By Chris Halse Rogers

Add mir_wait_handle_ready to client API

2374. By Chris Halse Rogers

Pump the eventloop from the main test body.

This makes it possible to mix synchronous and asynchronous calls in the test;
otherwise the synchonous calls get done on the main thread, and the asynchonous
calls on the eventloop thread.

2375. By Chris Halse Rogers

Move reply parsing out of PendingCallCache and into ProtobufRpc.

This lets us do all the reply processing in one place, leaving the
PendingCallCache to just handle ID lookup, storage, and final completion
dispatch.

2376. By Chris Halse Rogers

Make MirBasicRpcChannel the lowest-common-denominator type.

Rather than dynamic_cast<>ing in multiple places, just return a MirBasicRpcChannel
from ConnectionConfiguration and ensure that MirBasicRpcChannel provides all the
interfaces the code needs.

2377. By Chris Halse Rogers

Add a way to get the MirConnection associated with a BufferStream.

This is necessary for synchonous calls on manually-dispatched MirConnections

2378. By Chris Halse Rogers

Add a way to get the MirConnection associated with a MirSurface

2379. By Chris Halse Rogers

We treat MirBufferStream as a ClientBufferStream internally - make sure the pointers we return *are* ClientBufferStreams

2380. By Chris Halse Rogers

Enable getting a MirConnection out of a MirScreencast

2381. By Chris Halse Rogers

Add helper infrastructure for making synchronous RPC calls

2382. By Chris Halse Rogers

Use make_synchronous_call helper for all synchronous RPC calls

2383. By Chris Halse Rogers

Minor improvements to synchronous helper

2384. By Chris Halse Rogers

Initialise ProtobufRpcChannel::prioritise_next_request.

Thanks, valgrind.

2385. By Chris Halse Rogers

Don't call a synchronous method from a manually-dispatched async callback.

This fails for... some reason. Don't know at the moment.

2386. By Chris Halse Rogers

Free the surface_spec in ClientLibrary test.

Now doesn't leak!

2387. By Chris Halse Rogers

Add valgrind suppressions for GDBus bollocks.

2388. By Chris Halse Rogers

Merge trunk.

Lots and lots of changes, and the test-suite now fails due to NBS, but
commit this so that there's a stable base to fix the test-suite on.

2389. By Chris Halse Rogers

Merge prerequisite

2390. By Chris Halse Rogers

Set connection field of MirScreencast error-objects.

The synchonous dispatch helper requires the MirConnection to be valid.

2391. By Chris Halse Rogers

Update tests; everything now passes.

Mostly. Still have crashes where *_release_sync race with event delivery on the released object.

2392. By Chris Halse Rogers

Remove superfluous threads in tests.

These mt::AutoJoinThread()s were immediately being destroyed - and so, thread.join()ed - so
they only served to obfuscate the callstack.

2393. By Chris Halse Rogers

Add mir_connect_with_manual_dispatch_sync.

It's easy, it's plausibly useful, and it makes the tests easier

2394. By Chris Halse Rogers

Merge trunk

2395. By Chris Halse Rogers

Revert no-hidden-RPC-in-bufferstream.

This turns out to be surprisingly hard, and I can work around it.

2396. By Chris Halse Rogers

Merge trunk

2397. By Chris Halse Rogers

Revert the no-hidden-BufferStream-RPC reversion.

Turns out I *can* make this work.

2398. By Chris Halse Rogers

Merge in new bufferstream-no-hidden-RPC

2399. By Chris Halse Rogers

Merge trunk, resolving conflicts but not testsuite failures

2400. By Chris Halse Rogers

Merge BufferStream simplification branch

2401. By Chris Halse Rogers

Merge NoTLSFuture<T>::detach()

2402. By Chris Halse Rogers

Merge prerequisite, resolving conflicts

Unmerged revisions

2402. By Chris Halse Rogers

Merge prerequisite, resolving conflicts

2401. By Chris Halse Rogers

Merge NoTLSFuture<T>::detach()

2400. By Chris Halse Rogers

Merge BufferStream simplification branch

2399. By Chris Halse Rogers

Merge trunk, resolving conflicts but not testsuite failures

2398. By Chris Halse Rogers

Merge in new bufferstream-no-hidden-RPC

2397. By Chris Halse Rogers

Revert the no-hidden-BufferStream-RPC reversion.

Turns out I *can* make this work.

2396. By Chris Halse Rogers

Merge trunk

2395. By Chris Halse Rogers

Revert no-hidden-RPC-in-bufferstream.

This turns out to be surprisingly hard, and I can work around it.

2394. By Chris Halse Rogers

Merge trunk

2393. By Chris Halse Rogers

Add mir_connect_with_manual_dispatch_sync.

It's easy, it's plausibly useful, and it makes the tests easier

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'benchmarks/benchmark_multiplexing_dispatchable.cpp'
2--- benchmarks/benchmark_multiplexing_dispatchable.cpp 2015-06-17 05:20:42 +0000
3+++ benchmarks/benchmark_multiplexing_dispatchable.cpp 2017-03-28 00:17:49 +0000
4@@ -19,6 +19,7 @@
5 #include "mir/dispatch/multiplexing_dispatchable.h"
6
7 #include <iostream>
8+#include <thread>
9 #include <vector>
10 #include <memory>
11 #include <chrono>
12
13=== modified file 'debian/control'
14--- debian/control 2017-03-22 23:38:59 +0000
15+++ debian/control 2017-03-28 00:17:49 +0000
16@@ -288,6 +288,7 @@
17 Pre-Depends: ${misc:Pre-Depends}
18 Depends: ${misc:Depends},
19 ${shlibs:Depends},
20+ umockdev,
21 Recommends: mir-demos,
22 Description: Display Server for Ubuntu - stress tests and other test tools
23 Mir is a display server running on linux systems, with a focus on efficiency,
24
25=== modified file 'examples/chain_jumping_buffers.c'
26--- examples/chain_jumping_buffers.c 2017-03-10 19:47:57 +0000
27+++ examples/chain_jumping_buffers.c 2017-03-28 00:17:49 +0000
28@@ -268,8 +268,14 @@
29 for (unsigned int i = 0u; i < num_buffers; i++)
30 mir_buffer_release(buffer_available[i].buffer);
31 for (unsigned int i = 0u; i < num_chains; i++)
32+<<<<<<< TREE
33 mir_render_surface_release(render_surface[i]);
34 mir_window_release_sync(window);
35+=======
36+ mir_render_surface_release_sync(render_surface[i]);
37+
38+ mir_surface_release_sync(surface);
39+>>>>>>> MERGE-SOURCE
40 mir_connection_release(connection);
41 return 0;
42 }
43
44=== modified file 'examples/prerendered_frames.c'
45--- examples/prerendered_frames.c 2017-03-10 19:47:57 +0000
46+++ examples/prerendered_frames.c 2017-03-28 00:17:49 +0000
47@@ -234,8 +234,13 @@
48
49 for (i = 0u; i < num_prerendered_frames; i++)
50 mir_buffer_release(buffer_available[i].buffer);
51+<<<<<<< TREE
52 mir_render_surface_release(render_surface);
53 mir_window_release_sync(window);
54+=======
55+ mir_render_surface_release_sync(render_surface);
56+ mir_surface_release_sync(surface);
57+>>>>>>> MERGE-SOURCE
58 mir_connection_release(connection);
59 return 0;
60 }
61
62=== modified file 'examples/render_surface.cpp'
63--- examples/render_surface.cpp 2017-03-10 19:47:57 +0000
64+++ examples/render_surface.cpp 2017-03-28 00:17:49 +0000
65@@ -23,6 +23,8 @@
66 #include <signal.h>
67 #include <sys/signalfd.h>
68 #include <poll.h>
69+#include <mutex>
70+#include <condition_variable>
71
72 #include "mir_toolkit/mir_client_library.h"
73 #include "mir_toolkit/rs/mir_render_surface.h"
74@@ -207,14 +209,23 @@
75 if (nformats == 0)
76 throw std::runtime_error("no pixel formats for buffer stream");
77 printf("Software Driver selected pixel format %d\n", pixel_format);
78+<<<<<<< TREE
79 auto buffer_stream = mir_render_surface_get_buffer_stream(
80 render_surface, width, height, pixel_format);
81+=======
82+
83+ auto stream = mir_render_surface_get_buffer_stream_sync(
84+ render_surface,
85+ width, height,
86+ pixel_format,
87+ mir_buffer_usage_software);
88+>>>>>>> MERGE-SOURCE
89
90 auto window = mir_create_window_sync(spec);
91 mir_window_spec_release(spec);
92
93- fill_stream_with(buffer_stream, 255, 0, 0, 128);
94- mir_buffer_stream_swap_buffers_sync(buffer_stream);
95+ fill_stream_with(stream, 255, 0, 0, 128);
96+ mir_buffer_stream_swap_buffers_sync(stream);
97
98 sigset_t halt_signals;
99 sigemptyset(&halt_signals);
100@@ -235,13 +246,18 @@
101 {
102 bounce_position(baseColour, dbase, 128, 255);
103
104- fill_stream_with(buffer_stream, baseColour, 0, 0, 128);
105+ fill_stream_with(stream, baseColour, 0, 0, 128);
106
107- mir_buffer_stream_swap_buffers_sync(buffer_stream);
108+ mir_buffer_stream_swap_buffers_sync(stream);
109 }
110
111+<<<<<<< TREE
112 mir_render_surface_release(render_surface);
113 mir_window_release_sync(window);
114+=======
115+ mir_render_surface_release_sync(render_surface);
116+ mir_surface_release_sync(surface);
117+>>>>>>> MERGE-SOURCE
118 close(signal_watch);
119
120 return 0;
121
122=== modified file 'include/client/mir_toolkit/mir_connection.h'
123--- include/client/mir_toolkit/mir_connection.h 2017-03-13 08:12:52 +0000
124+++ include/client/mir_toolkit/mir_connection.h 2017-03-28 00:17:49 +0000
125@@ -63,6 +63,54 @@
126 MirConnection *mir_connect_sync(char const *server, char const *app_name);
127
128 /**
129+ * Request a connection to the Mir server.
130+ *
131+ * The client is responsible for handling event consumption via
132+ * mir_connection_dispatch(). Events will be available when the fd returned
133+ * by mir_connection_get_event_fd() becomes readable.
134+ *
135+ * All callbacks for this MirConnection and any objects created on it will be
136+ * called from the thread calling mir_connection_dispatch().
137+ *
138+ * \param [in] server A string specifying the server to connect to.
139+ * Connection strings can either be path to the socket file on
140+ * the filesystem, or an open file descriptor fd://
141+ * \param [in] app_name A name referring to the application
142+ * \param [in] callback Callback function to be invoked when request
143+ * completes. mir_connection_is_valid() will return false
144+ * until this callback has completed.
145+ * \param [in,out] context User data passed to the callback function
146+ * \returns The resulting MirConnection
147+ * \todo Currently manual dispatch interacts awkwardly with *_sync() calls;
148+ * Synchronous calls do *not* automatically dispatch, so unless client
149+ * code has a separate thread running dispatch, any *_sync() call will
150+ * deadlock. This restriction will be fixed in a later release.
151+ */
152+MirConnection* mir_connect_with_manual_dispatch(char const* server,
153+ char const* app_name,
154+ mir_connected_callback callback,
155+ void* context);
156+
157+/**
158+ * Synchronously connect to the Mir server.
159+ *
160+ * The client is responsible for handling event consumption via
161+ * mir_connection_dispatch(). Events will be available when the fd returned
162+ * by mir_connection_get_event_fd() becomes readable.
163+ *
164+ * All callbacks for this MirConnection and any objects created on it will be
165+ * called from the thread calling mir_connection_dispatch().
166+ *
167+ * \param [in] server A string specifying the server to connect to.
168+ * Connection strings can either be path to the socket file on
169+ * the filesystem, or an open file descriptor fd://
170+ * \param [in] app_name A name referring to the application
171+ * \returns The resulting MirConnection
172+ */
173+MirConnection* mir_connect_with_manual_dispatch_sync(char const* server,
174+ char const* app_name);
175+
176+/**
177 * Test for a valid connection
178 * \param [in] connection The connection
179 * \return True if the supplied connection is valid, or
180@@ -87,6 +135,28 @@
181 void mir_connection_release(MirConnection *connection);
182
183 /**
184+ * \brief Get the notification fd for this connection
185+ * \param [in] connection The connection. This connection must have been created by
186+ * mir_connect_with_manual_dispatch().
187+ * \return A file descriptor that supports select/poll/epoll and similar
188+ * APIs that becomes readable when there are events to dispatch,
189+ * or -1 if \ref connection was not created by
190+ * mir_connect_with_manual_dispatch();
191+ * \note This fd is owned by the MirConnection. Do not close the fd yourself.
192+ * The fd remains valid until mir_connection_release() returns.
193+ */
194+int mir_connection_get_event_fd(MirConnection* connection);
195+
196+/**
197+ * \brief Dispatch a single pending event on the connection
198+ * \param [in] connection The connection. This connection must have been created by
199+ * mir_connect_with_manual_dispatch().
200+ * \note It is an error to call this on a \ref connection not created by
201+ * mir_connect_with_manual_dispatch().
202+ */
203+void mir_connection_dispatch(MirConnection* connection);
204+
205+/**
206 * Query platform-specific data and/or file descriptors that are required to
207 * initialize GL/EGL features.
208 * \param [in] connection The connection
209
210=== modified file 'include/client/mir_toolkit/mir_wait.h'
211--- include/client/mir_toolkit/mir_wait.h 2017-01-19 23:17:56 +0000
212+++ include/client/mir_toolkit/mir_wait.h 2017-03-28 00:17:49 +0000
213@@ -49,6 +49,7 @@
214 void mir_wait_for_one(MirWaitHandle *wait_handle)
215 __attribute__ ((deprecated("No longer supported - use callbacks or wait for state changes")));
216
217+bool mir_wait_handle_ready(MirWaitHandle* wait_handle);
218
219 #ifdef __cplusplus
220 }
221
222=== modified file 'include/client/mir_toolkit/rs/mir_render_surface.h'
223--- include/client/mir_toolkit/rs/mir_render_surface.h 2017-03-14 04:41:33 +0000
224+++ include/client/mir_toolkit/rs/mir_render_surface.h 2017-03-28 00:17:49 +0000
225@@ -118,13 +118,30 @@
226 /**
227 * Release the specified render surface
228 *
229- * \param [in] render_surface The render surface to be released
230+ * \param [in] render_surface The render surface to be released
231+ * \param [in] callback Callback to be run when the operation completes
232+ * \param [in,out] ctx Context passed to callback
233 */
234 void mir_render_surface_release(
235+<<<<<<< TREE
236 MirRenderSurface* render_surface)
237 __attribute__((deprecated("This function is slated for rename due to MirRenderSurface-->MirSurface transition")));
238-
239-/**
240+=======
241+ MirRenderSurface* render_surface,
242+ mir_render_surface_callback callback,
243+ void* ctx);
244+
245+/**
246+ * Release the specified render surface and wait for the operation to complete
247+ *
248+ * \param [in] render_surface The render surface to be released
249+ */
250+void mir_render_surface_release_sync(
251+ MirRenderSurface* render_surface);
252+>>>>>>> MERGE-SOURCE
253+
254+/**
255+<<<<<<< TREE
256 * Obtain the buffer stream backing a given render surface.
257 * The MirBufferStream will contain buffers suitable for writing via the CPU.
258 *
259@@ -143,10 +160,57 @@
260 int width, int height,
261 MirPixelFormat format)
262 __attribute__((deprecated("This function is slated for rename due to MirRenderSurface-->MirSurface transition")));
263-
264-/**
265+=======
266+ * Obtain a buffer stream backing a given render surface
267+ *
268+ * \pre The MirRenderSurface does not have a backing object.
269+ *
270+ * \param [in] render_surface The render surface
271+ * \param [in] width Requested width
272+ * \param [in] height Requested height
273+ * \param [in] format Requested pixel format
274+ * \param [in] usage Requested buffer usage
275+ * \param [in] callback Callback to be run when operation completes
276+ * \param [in,out] context Context passed to callback
277+ */
278+void mir_render_surface_get_buffer_stream(
279+ MirRenderSurface* render_surface,
280+ int width,
281+ int height,
282+ MirPixelFormat format,
283+ MirBufferUsage usage,
284+ mir_buffer_stream_callback callback,
285+ void* context);
286+
287+/**
288+ * Back the render surface with a buffer stream and wait for the operation to complete.
289+ *
290+ * \pre The MirRenderSurface does not have a backing object.
291+ *
292+ * \param [in] render_surface The render surface
293+ * \param [in] width Requested width
294+ * \param [in] height Requested height
295+ * \param [in] format Requested pixel format
296+ * \param [in] usage Requested buffer usage
297+ * \return The new MirBufferStream backing the MirRenderSurface.
298+ * If a backing object for this MirRenderSurface has already been realised
299+ * this returns NULL, otherwise it returns a non-null MirBufferStream
300+ */
301+MirBufferStream* mir_render_surface_get_buffer_stream_sync(
302+ MirRenderSurface* render_surface,
303+ int width,
304+ int height,
305+ MirPixelFormat format,
306+ MirBufferUsage usage);
307+>>>>>>> MERGE-SOURCE
308+
309+/**
310+<<<<<<< TREE
311 * Obtain the presentation chain backing a given render surface.
312 * The MirPresentationChain is created in mir_present_mode_fifo submission mode.
313+=======
314+ * Obtain a presentation chain backing a given render surface
315+>>>>>>> MERGE-SOURCE
316 *
317 * \return The chain contained in the given render surface
318 * or 'nullptr' if it, or
319
320=== added file 'include/common/mir/dispatch/threaded_dispatcher.h.moved'
321--- include/common/mir/dispatch/threaded_dispatcher.h.moved 1970-01-01 00:00:00 +0000
322+++ include/common/mir/dispatch/threaded_dispatcher.h.moved 2017-03-28 00:17:49 +0000
323@@ -0,0 +1,75 @@
324+/*
325+ * Copyright © 2015 Canonical Ltd.
326+ *
327+ * This program is free software: you can redistribute it and/or modify it
328+ * under the terms of the GNU Lesser General Public License version 3,
329+ * as published by the Free Software Foundation.
330+ *
331+ * This program is distributed in the hope that it will be useful,
332+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
333+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
334+ * GNU Lesser General Public License for more details.
335+ *
336+ * You should have received a copy of the GNU Lesser General Public License
337+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
338+ *
339+ * Authored by: Christopher James Halse Rogers <christopher.halse.rogers@canonical.com>
340+ */
341+
342+#ifndef MIR_DISPATCH_SIMPLE_DISPATCH_THREAD_H_
343+#define MIR_DISPATCH_SIMPLE_DISPATCH_THREAD_H_
344+
345+#include <string>
346+#include <memory>
347+#include <thread>
348+#include <vector>
349+#include <mutex>
350+#include <condition_variable>
351+
352+#include "mir/dispatch/multiplexing_dispatchable.h"
353+#include "mir/fd.h"
354+
355+namespace mir
356+{
357+namespace dispatch
358+{
359+class Dispatchable;
360+
361+class ThreadedDispatcher
362+{
363+public:
364+ ThreadedDispatcher(std::string const& name, std::shared_ptr<Dispatchable> const& dispatchee);
365+ ThreadedDispatcher(std::string const& name,
366+ std::shared_ptr<Dispatchable> const& dispatchee,
367+ std::function<void()> const& exception_handler);
368+ ~ThreadedDispatcher() noexcept;
369+
370+ void add_thread();
371+ void remove_thread();
372+
373+private:
374+ class ThreadShutdownRequestHandler;
375+ friend class ThreadShutdownRequestHandler;
376+
377+ std::string const name_base;
378+
379+ std::shared_ptr<ThreadShutdownRequestHandler> thread_exiter;
380+ std::shared_ptr<MultiplexingDispatchable> dispatcher;
381+
382+ std::mutex thread_pool_mutex;
383+ std::vector<std::thread> threadpool;
384+
385+ std::function<void()> const exception_handler;
386+
387+ static void dispatch_loop(std::string const& name,
388+ std::shared_ptr<ThreadShutdownRequestHandler> thread_register,
389+ std::shared_ptr<Dispatchable> dispatcher,
390+ std::function<void()> const& exception_handler);
391+
392+};
393+
394+}
395+}
396+
397+
398+#endif // MIR_DISPATCH_SIMPLE_DISPATCH_THREAD_H_
399
400=== renamed file 'tests/include/mir/test/fd_utils.h' => 'include/test/mir/test/fd_utils.h'
401=== modified file 'include/test/mir/test/validity_matchers.h'
402--- include/test/mir/test/validity_matchers.h 2017-01-18 02:29:37 +0000
403+++ include/test/mir/test/validity_matchers.h 2017-03-28 00:17:49 +0000
404@@ -23,6 +23,8 @@
405
406 #include "mir_toolkit/mir_client_library.h"
407
408+class MirRenderSurface;
409+
410 using ::testing::MakePolymorphicMatcher;
411 using ::testing::MatchResultListener;
412 using ::testing::NotNull;
413@@ -54,6 +56,12 @@
414 template<>
415 bool IsValidMatcher::MatchAndExplain(MirWindow* surface, MatchResultListener* listener) const;
416
417+template<>
418+bool IsValidMatcher::MatchAndExplain(MirBufferStream* stream, MatchResultListener* listener) const;
419+
420+template<>
421+bool IsValidMatcher::MatchAndExplain(MirRenderSurface* stream, MatchResultListener* listener) const;
422+
423 // To construct a polymorphic matcher, pass an instance of the class
424 // to MakePolymorphicMatcher(). Note the return type.
425 inline PolymorphicMatcher<IsValidMatcher> IsValid()
426
427=== modified file 'playground/egldiamond_render_surface.c'
428--- playground/egldiamond_render_surface.c 2017-03-14 04:41:33 +0000
429+++ playground/egldiamond_render_surface.c 2017-03-28 00:17:49 +0000
430@@ -322,8 +322,13 @@
431 future_driver_eglTerminate(egldisplay);
432 else
433 eglTerminate(egldisplay);
434+<<<<<<< TREE
435 mir_render_surface_release(render_surface);
436 mir_window_release_sync(window);
437+=======
438+ mir_render_surface_release_sync(render_surface);
439+ mir_surface_release_sync(surface);
440+>>>>>>> MERGE-SOURCE
441 mir_connection_release(connection);
442 return 0;
443 }
444
445=== modified file 'playground/mir_egl_platform_shim.c'
446--- playground/mir_egl_platform_shim.c 2017-03-10 19:47:57 +0000
447+++ playground/mir_egl_platform_shim.c 2017-03-28 00:17:49 +0000
448@@ -72,10 +72,19 @@
449 MirPixelFormat pixel_format = mir_connection_get_egl_pixel_format(info->connection, display, config);
450 //this particular [silly] driver has chosen the buffer stream as the way it wants to post
451 //its hardware content. I'd think most drivers would want MirPresentationChain for flexibility
452+<<<<<<< TREE
453 info->stream = ext->get_hardware_buffer_stream(surface,
454 info->current_physical_width,
455 info->current_physical_height,
456 pixel_format);
457+=======
458+
459+ info->stream = mir_render_surface_get_buffer_stream_sync(
460+ surface,
461+ info->current_physical_width, info->current_physical_height,
462+ pixel_format,
463+ mir_buffer_usage_hardware);
464+>>>>>>> MERGE-SOURCE
465
466 printf("The driver chose pixel format %d.\n", pixel_format);
467 return eglCreateWindowSurface(display, config, (EGLNativeWindowType) surface, attr);
468
469=== modified file 'src/client/CMakeLists.txt'
470--- src/client/CMakeLists.txt 2017-03-21 05:51:47 +0000
471+++ src/client/CMakeLists.txt 2017-03-28 00:17:49 +0000
472@@ -81,12 +81,15 @@
473 screencast_stream.cpp
474 buffer_vault.cpp
475 mir_buffer_stream_api.cpp
476+ synchronous_helper.cpp
477 error_stream.cpp
478 error_render_surface.cpp
479 buffer.cpp
480 error_buffer.cpp
481 mir_render_surface_api.cpp
482 render_surface.cpp
483+ mir_render_surface.h
484+ ${CMAKE_SOURCE_DIR}/src/include/client/mir_toolkit/mir_render_surface.h
485 presentation_chain.cpp
486 mir_presentation_chain_api.cpp
487 mir_buffer_api.cpp
488@@ -104,7 +107,11 @@
489 ${CMAKE_SOURCE_DIR}/include/client/mir_toolkit/mir_error.h
490 mir_extension_core.cpp
491 ${CMAKE_SOURCE_DIR}/include/client/mir_toolkit/mir_extension_core.h
492+<<<<<<< TREE
493 ${CMAKE_SOURCE_DIR}/include/client/mir_toolkit/extensions/drag_and_drop.h
494+=======
495+ no_tls_future-inl.h
496+>>>>>>> MERGE-SOURCE
497 )
498
499 # Ensure protobuf C++ headers have been produced before
500@@ -160,6 +167,8 @@
501
502 add_library(mirclient-debug-extension SHARED
503 mir_debug_api.cpp
504+ $<TARGET_OBJECTS:mirclientobjects>
505+ $<TARGET_OBJECTS:mirsharedinput>
506 )
507
508 target_link_libraries(mirclient-debug-extension
509
510=== modified file 'src/client/buffer_factory.cpp'
511--- src/client/buffer_factory.cpp 2017-03-10 19:47:57 +0000
512+++ src/client/buffer_factory.cpp 2017-03-28 00:17:49 +0000
513@@ -22,6 +22,7 @@
514 #include <algorithm>
515 #include <boost/throw_exception.hpp>
516 #include "protobuf_to_native_buffer.h"
517+#include <sstream>
518
519 namespace mcl = mir::client;
520 namespace geom = mir::geometry;
521@@ -92,7 +93,16 @@
522 });
523
524 if (request_it == allocation_requests.end())
525- BOOST_THROW_EXCEPTION(std::logic_error("unrequested buffer received"));
526+ {
527+ std::stringstream message;
528+ message << "Unrequested buffer received. Expected a buffer with one of the following sizes:" << std::endl;
529+ for (auto const& request : allocation_requests)
530+ {
531+ message << "\t(" << request->size.width << "×" << request->size.height << ")" << std::endl;
532+ }
533+ message << "Received buffer has size: (" << buffer.width() << "×" << buffer.height() << ")" << std::endl;
534+ BOOST_THROW_EXCEPTION(std::logic_error{message.str()});
535+ }
536
537 std::unique_ptr<mcl::MirBuffer> b;
538 if (buffer.has_error())
539
540=== modified file 'src/client/buffer_stream.cpp'
541--- src/client/buffer_stream.cpp 2017-03-20 11:24:19 +0000
542+++ src/client/buffer_stream.cpp 2017-03-28 00:17:49 +0000
543@@ -142,37 +142,52 @@
544 //Should be merged with mcl::BufferVault
545 struct BufferDepository
546 {
547- BufferDepository(
548+ static NoTLSFuture<std::unique_ptr<BufferDepository>> create(
549 std::shared_ptr<mcl::ClientBufferFactory> const& factory,
550 std::shared_ptr<mcl::AsyncBufferFactory> const& mirbuffer_factory,
551 std::shared_ptr<mcl::ServerBufferRequests> const& requests,
552 std::weak_ptr<mcl::SurfaceMap> const& surface_map,
553 geom::Size size, MirPixelFormat format, int usage,
554- unsigned int initial_nbuffers) :
555- vault(factory, mirbuffer_factory, requests, surface_map, size, format, usage, initial_nbuffers),
556- current(nullptr),
557- size_(size)
558+ unsigned int initial_nbuffers)
559 {
560- future = vault.withdraw();
561+ auto vault = std::make_unique<mcl::BufferVault>(
562+ factory,
563+ mirbuffer_factory,
564+ requests,
565+ surface_map,
566+ size,
567+ format,
568+ usage,
569+ initial_nbuffers);
570+
571+ auto future_buffer = vault->withdraw();
572+
573+ // Because NoTLSFuture<>.then() internally uses a std::function<void()> for the
574+ // continuation the lambda passed in has to be CopyConstructible, which means we can't
575+ // move-capture a std::unique_ptr<>. Dance around it with release().
576+ return future_buffer.then(
577+ [raw_vault = vault.release(), size](auto&& resolved_buffer)
578+ {
579+ std::unique_ptr<mcl::BufferVault> vault{raw_vault};
580+ return std::unique_ptr<BufferDepository>(
581+ new BufferDepository{
582+ resolved_buffer.get(),
583+ std::move(vault),
584+ size});
585+ });
586 }
587
588 void deposit(mp::Buffer const&, mir::optional_value<geom::Size>, MirPixelFormat)
589 {
590 }
591
592- void advance_current_buffer(std::unique_lock<std::mutex>& lk)
593- {
594- lk.unlock();
595- auto c = future.get();
596- lk.lock();
597- current = c;
598- }
599-
600 std::shared_ptr<mir::client::ClientBuffer> current_buffer()
601 {
602 std::unique_lock<std::mutex> lk(mutex);
603 if (!current)
604- advance_current_buffer(lk);
605+ BOOST_THROW_EXCEPTION(
606+ std::logic_error{
607+ "Current buffer requested before waiting for buffer to arrive"});
608 return current->client_buffer();
609 }
610
611@@ -180,7 +195,9 @@
612 {
613 std::unique_lock<std::mutex> lk(mutex);
614 if (!current)
615- advance_current_buffer(lk);
616+ BOOST_THROW_EXCEPTION(
617+ std::logic_error{
618+ "Current buffer requested before waiting for buffer to arrive"});
619 return current->rpc_id();
620 }
621
622@@ -188,16 +205,23 @@
623 {
624 std::unique_lock<std::mutex> lk(mutex);
625 if (!current)
626- advance_current_buffer(lk);
627+ BOOST_THROW_EXCEPTION(
628+ std::logic_error{
629+ "Attempted to submit current buffer without waiting for a buffer to become current"});
630 auto c = current;
631 current = nullptr;
632 lk.unlock();
633
634- vault.deposit(c);
635- auto wh = vault.wire_transfer_outbound(c, done);
636- auto f = vault.withdraw();
637- lk.lock();
638- future = std::move(f);
639+ vault->deposit(c);
640+ auto wh = vault->wire_transfer_outbound(c, done);
641+
642+ vault->withdraw().then(
643+ [this](auto&& new_buffer)
644+ {
645+ std::lock_guard<std::mutex> lk{mutex};
646+
647+ current = new_buffer.get();
648+ }).detach();
649 return wh;
650 }
651
652@@ -207,7 +231,7 @@
653 std::unique_lock<std::mutex> lk(mutex);
654 size_ = size;
655 }
656- vault.set_size(size);
657+ vault->set_size(size);
658 }
659
660 geom::Size size() const
661@@ -218,14 +242,14 @@
662
663 void lost_connection()
664 {
665- vault.disconnected();
666+ vault->disconnected();
667 }
668
669 MirWaitHandle* set_scale(float scale, mf::BufferStreamId)
670 {
671 scale_wait_handle.expect_result();
672 scale_wait_handle.result_received();
673- vault.set_scale(scale);
674+ vault->set_scale(scale);
675 return &scale_wait_handle;
676 }
677
678@@ -233,15 +257,24 @@
679 {
680 std::unique_lock<decltype(mutex)> lk(mutex);
681 interval = std::max(0, std::min(1, interval));
682- vault.set_interval(interval);
683- }
684-
685- // Future must be before vault, to ensure vault's destruction marks future
686- // as ready.
687- mir::client::NoTLSFuture<std::shared_ptr<mcl::MirBuffer>> future;
688-
689- mcl::BufferVault vault;
690+ vault->set_interval(interval);
691+ }
692+
693+
694+private:
695+ BufferDepository(
696+ std::shared_ptr<mcl::MirBuffer> initial_buffer,
697+ std::unique_ptr<mcl::BufferVault>&& vault,
698+ geom::Size size) :
699+ vault{std::move(vault)},
700+ current{initial_buffer},
701+ size_{size}
702+ {
703+ }
704+
705+ std::unique_ptr<mcl::BufferVault> vault;
706 std::mutex mutable mutex;
707+ std::mutex current_buffer_mutex;
708 std::shared_ptr<mcl::MirBuffer> current{nullptr};
709 MirWaitHandle scale_wait_handle;
710 geom::Size size_;
711@@ -249,12 +282,17 @@
712 }
713 }
714
715+<<<<<<< TREE
716 #pragma GCC diagnostic push
717 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
718 mcl::BufferStream::BufferStream(
719+=======
720+mcl::NoTLSFuture<std::unique_ptr<mcl::BufferStream>>
721+mcl::BufferStream::create(
722+>>>>>>> MERGE-SOURCE
723 MirConnection* connection,
724 MirRenderSurface* render_surface,
725- std::shared_ptr<MirWaitHandle> creation_wait_handle,
726+ std::shared_ptr<MirWaitHandle> const& creation_wait_handle,
727 mclr::DisplayServer& server,
728 std::shared_ptr<mcl::ClientPlatform> const& client_platform,
729 std::weak_ptr<mcl::SurfaceMap> const& map,
730@@ -264,22 +302,87 @@
731 std::string const& surface_name,
732 geom::Size ideal_size,
733 size_t nbuffers)
734+{
735+ auto protobuf_bs = mcl::make_protobuf_object(a_protobuf_bs);
736+
737+ if (!protobuf_bs->has_id())
738+ {
739+ if (!protobuf_bs->has_error())
740+ protobuf_bs->set_error("Error processing buffer stream create response, no ID (disconnected?)");
741+ }
742+
743+ if (protobuf_bs->has_error())
744+ {
745+ if (protobuf_bs->has_buffer())
746+ {
747+ for (int i = 0; i < protobuf_bs->buffer().fd_size(); i++)
748+ ::close(protobuf_bs->buffer().fd(i));
749+ }
750+
751+ BOOST_THROW_EXCEPTION(std::runtime_error("Can not create buffer stream: " + std::string(protobuf_bs->error())));
752+ }
753+
754+
755+ auto future_depository = BufferDepository::create(
756+ client_platform->create_buffer_factory(), factory,
757+ std::make_shared<Requests>(server, protobuf_bs->id().value()), map,
758+ ideal_size, static_cast<MirPixelFormat>(protobuf_bs->pixel_format()),
759+ protobuf_bs->buffer_usage(), nbuffers);
760+
761+ return future_depository.then(
762+ [=, raw_protobuf_bs = protobuf_bs.release(), raw_server = &server](auto&& depository)
763+ {
764+ std::unique_ptr<mp::BufferStream> protobuf_bs{raw_protobuf_bs};
765+ // Can't use make_unique because the constructor is private to it.
766+ return std::unique_ptr<BufferStream>{
767+ new BufferStream{
768+ *raw_server,
769+ connection,
770+ render_surface,
771+ creation_wait_handle,
772+ depository.get(),
773+ client_platform,
774+ map,
775+ std::move(protobuf_bs),
776+ perf_report,
777+ surface_name,
778+ ideal_size}};
779+ }
780+ );
781+}
782+
783+mcl::BufferStream::BufferStream(
784+ rpc::DisplayServer& server,
785+ MirConnection* connection,
786+ MirRenderSurface* render_surface,
787+ std::shared_ptr<MirWaitHandle> const& creation_wait_handle,
788+ std::unique_ptr<BufferDepository>&& depository,
789+ std::shared_ptr<mcl::ClientPlatform> const& client_platform,
790+ std::weak_ptr<mcl::SurfaceMap> const& map,
791+ std::unique_ptr<mp::BufferStream>&& incoming_protobuf_bs,
792+ std::shared_ptr<mcl::PerfReport> const& perf_report,
793+ std::string const& surface_name,
794+ geom::Size ideal_size)
795 : connection_(connection),
796 client_platform(client_platform),
797- protobuf_bs{mcl::make_protobuf_object<mir::protobuf::BufferStream>(a_protobuf_bs)},
798+ protobuf_bs{std::move(incoming_protobuf_bs)},
799 user_swap_interval(parse_env_for_swap_interval()),
800+<<<<<<< TREE
801 using_client_side_vsync(false),
802 interval_config{server, frontend::BufferStreamId{a_protobuf_bs.id().value()}},
803+=======
804+ interval_config{server, frontend::BufferStreamId{this->protobuf_bs->id().value()}},
805+>>>>>>> MERGE-SOURCE
806 scale_(1.0f),
807 perf_report(perf_report),
808 protobuf_void{mcl::make_protobuf_object<mir::protobuf::Void>()},
809+ buffer_depository{std::move(depository)},
810 ideal_buffer_size(ideal_size),
811- nbuffers(nbuffers),
812- creation_wait_handle(creation_wait_handle),
813+ creation_wait_handle{creation_wait_handle},
814 map(map),
815- factory(factory),
816 render_surface_(render_surface)
817 {
818+<<<<<<< TREE
819 /*
820 * Since we try to use client-side vsync where possible, a separate
821 * copy of the current swap interval is required to represent that
822@@ -306,9 +409,12 @@
823
824 BOOST_THROW_EXCEPTION(std::runtime_error("Can not create buffer stream: " + std::string(protobuf_bs->error())));
825 }
826+=======
827+>>>>>>> MERGE-SOURCE
828
829 try
830 {
831+<<<<<<< TREE
832 buffer_depository = std::make_unique<BufferDepository>(
833 client_platform->create_buffer_factory(), factory,
834 std::make_shared<Requests>(server, protobuf_bs->id().value(), client_platform),
835@@ -316,6 +422,8 @@
836 ideal_buffer_size, static_cast<MirPixelFormat>(protobuf_bs->pixel_format()),
837 protobuf_bs->buffer_usage(), nbuffers);
838
839+=======
840+>>>>>>> MERGE-SOURCE
841 egl_native_window_ = client_platform->create_egl_native_window(this);
842
843 // This might seem like something to provide during creation but
844
845=== modified file 'src/client/buffer_stream.h'
846--- src/client/buffer_stream.h 2017-03-20 11:24:19 +0000
847+++ src/client/buffer_stream.h 2017-03-28 00:17:49 +0000
848@@ -26,10 +26,15 @@
849 #include "mir/geometry/size.h"
850 #include "mir/optional_value.h"
851 #include "buffer_stream_configuration.h"
852+<<<<<<< TREE
853 #include "frame_clock.h"
854+=======
855+#include "no_tls_future-inl.h"
856+>>>>>>> MERGE-SOURCE
857
858 #include "mir_toolkit/client_types.h"
859
860+
861 #include <EGL/eglplatform.h>
862
863 #include <unordered_set>
864@@ -74,15 +79,19 @@
865 class BufferStream : public EGLNativeSurface, public MirBufferStream
866 {
867 public:
868+<<<<<<< TREE
869 BufferStream(
870 mir::client::rpc::DisplayServer& server,
871 std::weak_ptr<SurfaceMap> const& map);
872 #pragma GCC diagnostic push
873 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
874 BufferStream(
875+=======
876+ static NoTLSFuture<std::unique_ptr<BufferStream>> create(
877+>>>>>>> MERGE-SOURCE
878 MirConnection* connection,
879 MirRenderSurface* render_surface,
880- std::shared_ptr<MirWaitHandle> creation_wait_handle,
881+ std::shared_ptr<MirWaitHandle> const& creation_wait_handle,
882 mir::client::rpc::DisplayServer& server,
883 std::shared_ptr<ClientPlatform> const& native_window_factory,
884 std::weak_ptr<SurfaceMap> const& map,
885@@ -139,6 +148,19 @@
886 BufferStream& operator=(BufferStream const&) = delete;
887
888 private:
889+ BufferStream(
890+ rpc::DisplayServer& server,
891+ MirConnection* connection,
892+ MirRenderSurface* render_surface,
893+ std::shared_ptr<MirWaitHandle> const& creation_wait_handle,
894+ std::unique_ptr<BufferDepository>&& depository,
895+ std::shared_ptr<ClientPlatform> const& native_window_factory,
896+ std::weak_ptr<SurfaceMap> const& map,
897+ std::unique_ptr<mir::protobuf::BufferStream>&& protobuf_bs,
898+ std::shared_ptr<PerfReport> const& perf_report,
899+ std::string const& surface_name,
900+ geometry::Size ideal_size);
901+
902 void process_buffer(protobuf::Buffer const& buffer);
903 void process_buffer(protobuf::Buffer const& buffer, std::unique_lock<std::mutex>&);
904 MirWaitHandle* set_server_swap_interval(int i);
905@@ -165,13 +187,15 @@
906
907 std::unique_ptr<BufferDepository> buffer_depository;
908 geometry::Size ideal_buffer_size;
909- size_t const nbuffers;
910 std::string error_message;
911- std::shared_ptr<MirWaitHandle> creation_wait_handle;
912+ std::shared_ptr<MirWaitHandle> const creation_wait_handle;
913 std::weak_ptr<SurfaceMap> const map;
914+<<<<<<< TREE
915 std::shared_ptr<AsyncBufferFactory> const factory;
916 #pragma GCC diagnostic push
917 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
918+=======
919+>>>>>>> MERGE-SOURCE
920 MirRenderSurface* render_surface_;
921 #pragma GCC diagnostic pop
922
923
924=== modified file 'src/client/buffer_stream_configuration.cpp'
925--- src/client/buffer_stream_configuration.cpp 2017-01-18 02:29:37 +0000
926+++ src/client/buffer_stream_configuration.cpp 2017-03-28 00:17:49 +0000
927@@ -29,6 +29,14 @@
928 {
929 }
930
931+mcl::BufferStreamConfiguration::BufferStreamConfiguration(
932+ BufferStreamConfiguration&& from)
933+ : server{from.server},
934+ id{from.id},
935+ protobuf_void{std::move(from.protobuf_void)}
936+{
937+}
938+
939 void mcl::BufferStreamConfiguration::on_swap_interval_set(int interval)
940 {
941 std::unique_lock<decltype(mutex)> lock(mutex);
942
943=== modified file 'src/client/buffer_stream_configuration.h'
944--- src/client/buffer_stream_configuration.h 2017-01-18 02:29:37 +0000
945+++ src/client/buffer_stream_configuration.h 2017-03-28 00:17:49 +0000
946@@ -33,6 +33,7 @@
947 {
948 public:
949 BufferStreamConfiguration(rpc::DisplayServer& server, frontend::BufferStreamId id);
950+ BufferStreamConfiguration(BufferStreamConfiguration&& from);
951
952 void on_swap_interval_set(int interval);
953 int swap_interval() const;
954
955=== modified file 'src/client/buffer_vault.cpp'
956--- src/client/buffer_vault.cpp 2017-01-30 08:13:20 +0000
957+++ src/client/buffer_vault.cpp 2017-03-28 00:17:49 +0000
958@@ -28,6 +28,7 @@
959 #include "buffer_factory.h"
960 #include "buffer.h"
961 #include <algorithm>
962+#include <experimental/optional>
963 #include <boost/throw_exception.hpp>
964
965 namespace mcl = mir::client;
966@@ -271,14 +272,30 @@
967 }
968 }
969
970+ auto cb = deferred_cb;
971+ deferred_cb = {};
972+ std::experimental::optional<decltype(promises)::value_type> buffer_promise;
973+
974 if (!promises.empty())
975 {
976 buffers[buffer_id] = Owner::ContentProducer;
977- promises.front().set_value(buffer);
978- promises.pop_front();
979- }
980-
981- trigger_callback(std::move(lk));
982+ // Satisfying a promise might call continuation code on this stack.
983+ // We need to
984+ buffer_promise = std::move(promises.front());
985+ promises.pop_front();;
986+ }
987+
988+ lk.unlock();
989+
990+ if (buffer_promise)
991+ {
992+ buffer_promise->set_value(buffer);
993+ }
994+ if (cb)
995+ {
996+ cb();
997+ swap_buffers_wait_handle.result_received();
998+ }
999 }
1000
1001 void mcl::BufferVault::disconnected()
1002
1003=== added file 'src/client/client_buffer_stream_factory.h.THIS'
1004--- src/client/client_buffer_stream_factory.h.THIS 1970-01-01 00:00:00 +0000
1005+++ src/client/client_buffer_stream_factory.h.THIS 2017-03-28 00:17:49 +0000
1006@@ -0,0 +1,66 @@
1007+/*
1008+ * Copyright © 2015 Canonical Ltd.
1009+ *
1010+ * This program is free software: you can redistribute it and/or modify it
1011+ * under the terms of the GNU Lesser General Public License version 3,
1012+ * as published by the Free Software Foundation.
1013+ *
1014+ * This program is distributed in the hope that it will be useful,
1015+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1016+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1017+ * GNU Lesser General Public License for more details.
1018+ *
1019+ * You should have received a copy of the GNU Lesser General Public License
1020+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1021+ *
1022+ * Authored by: Robert Carr <robert.carr@canonical.com>
1023+ */
1024+
1025+#ifndef MIR_CLIENT_CLIENT_BUFFER_STREAM_FACTORY_H_
1026+#define MIR_CLIENT_CLIENT_BUFFER_STREAM_FACTORY_H_
1027+
1028+#include "mir_protobuf.pb.h"
1029+
1030+#include "mir_toolkit/client_types.h"
1031+
1032+#include <memory>
1033+
1034+class MirConnection;
1035+
1036+namespace mir
1037+{
1038+namespace client
1039+{
1040+class ClientBufferStream;
1041+class BufferStream;
1042+class ClientBufferStreamFactory
1043+{
1044+public:
1045+ virtual std::shared_ptr<ClientBufferStream> make_consumer_stream(
1046+ MirConnection* allocating_connection,
1047+ protobuf::DisplayServer& server,
1048+ protobuf::BufferStream const& protobuf_bs,
1049+ std::string const& surface_name) = 0;
1050+ virtual std::shared_ptr<ClientBufferStream> make_producer_stream(
1051+ MirConnection* allocating_connection,
1052+ protobuf::DisplayServer& server,
1053+ protobuf::BufferStream const& protobuf_bs,
1054+ std::string const& surface_name) = 0;
1055+
1056+ // For creating buffer stream owned by client.
1057+ virtual ClientBufferStream* make_producer_stream(
1058+ MirConnection* allocating_connection,
1059+ protobuf::DisplayServer& server,
1060+ protobuf::BufferStreamParameters const& params,
1061+ mir_buffer_stream_callback callback, void* context) = 0;
1062+
1063+protected:
1064+ ClientBufferStreamFactory() = default;
1065+ virtual ~ClientBufferStreamFactory() = default;
1066+ ClientBufferStreamFactory(const ClientBufferStreamFactory&) = delete;
1067+ ClientBufferStreamFactory& operator=(const ClientBufferStreamFactory&) = delete;
1068+};
1069+}
1070+}
1071+
1072+#endif // MIR_CLIENT_CLIENT_BUFFER_STREAM_FACTORY_H_
1073
1074=== modified file 'src/client/connection_configuration.h'
1075--- src/client/connection_configuration.h 2017-02-15 14:45:41 +0000
1076+++ src/client/connection_configuration.h 2017-03-28 00:17:49 +0000
1077@@ -37,6 +37,11 @@
1078 class Logger;
1079 }
1080
1081+namespace dispatch
1082+{
1083+class ActionQueue;
1084+}
1085+
1086 namespace client
1087 {
1088 namespace rpc
1089@@ -51,11 +56,17 @@
1090 class EventHandlerRegister;
1091 class AsyncBufferFactory;
1092
1093+namespace rpc
1094+{
1095+class MirBasicRpcChannel;
1096+}
1097+
1098 class ConnectionConfiguration
1099 {
1100 public:
1101 virtual ~ConnectionConfiguration() = default;
1102
1103+ virtual std::shared_ptr<dispatch::ActionQueue> the_delayed_queue() = 0;
1104 virtual std::shared_ptr<ConnectionSurfaceMap> the_surface_map() = 0;
1105 virtual std::shared_ptr<mir::client::rpc::MirBasicRpcChannel> the_rpc_channel() = 0;
1106 virtual std::shared_ptr<mir::logging::Logger> the_logger() = 0;
1107
1108=== modified file 'src/client/connection_surface_map.cpp'
1109--- src/client/connection_surface_map.cpp 2017-03-14 04:41:33 +0000
1110+++ src/client/connection_surface_map.cpp 2017-03-28 00:17:49 +0000
1111@@ -20,26 +20,78 @@
1112 #include "mir_surface.h"
1113 #include "presentation_chain.h"
1114
1115+#include "mir/dispatch/action_queue.h"
1116+
1117 #include <boost/throw_exception.hpp>
1118 #include <sstream>
1119
1120 namespace mcl=mir::client;
1121 namespace mf=mir::frontend;
1122
1123+<<<<<<< TREE
1124 using mir::client::ConnectionSurfaceMap;
1125 using mir::frontend::SurfaceId;
1126 using mir::frontend::BufferStreamId;
1127
1128 std::shared_ptr<MirWindow> ConnectionSurfaceMap::surface(SurfaceId id) const
1129-{
1130+=======
1131+mcl::ConnectionSurfaceMap::ConnectionSurfaceMap(
1132+ std::shared_ptr<dispatch::ActionQueue> delayed_queue)
1133+ : delayed_queue{delayed_queue}
1134+{
1135+}
1136+
1137+void mcl::ConnectionSurfaceMap::with_surface_do(
1138+ mf::SurfaceId surface_id, std::function<void(MirSurface*)> const& exec) const
1139+>>>>>>> MERGE-SOURCE
1140+{
1141+ {
1142+ std::lock_guard<decltype(reserved_guard)> lock{reserved_guard};
1143+ auto const it = surface_reservations.find(surface_id);
1144+ if (it != surface_reservations.end())
1145+ {
1146+ it->second.push_back(exec);
1147+ return;
1148+ }
1149+ }
1150+
1151 std::shared_lock<decltype(guard)> lk(guard);
1152 auto const found = surfaces.find(id);
1153 return found != surfaces.end() ? found->second : nullptr;
1154 }
1155
1156+<<<<<<< TREE
1157 void mcl::ConnectionSurfaceMap::insert(mf::SurfaceId surface_id, std::shared_ptr<MirWindow> const& surface)
1158+=======
1159+void mcl::ConnectionSurfaceMap::reserve(mf::SurfaceId surface_id)
1160+{
1161+ std::lock_guard<decltype(reserved_guard)> lock{reserved_guard};
1162+ surface_reservations[surface_id] = {};
1163+}
1164+
1165+
1166+
1167+void mcl::ConnectionSurfaceMap::insert(mf::SurfaceId surface_id, std::shared_ptr<MirSurface> const& surface)
1168+>>>>>>> MERGE-SOURCE
1169 {
1170 std::lock_guard<decltype(guard)> lk(guard);
1171+ std::lock_guard<decltype(reserved_guard)> lock{reserved_guard};
1172+ for (auto& func : surface_reservations[surface_id])
1173+ {
1174+ delayed_queue->enqueue(
1175+ [this, surface_id, exec = std::move(func)]()
1176+ {
1177+ std::shared_lock<decltype(guard)> lk(guard);
1178+ auto const it = surfaces.find(surface_id);
1179+ if (it != surfaces.end())
1180+ {
1181+ auto const surface = it->second;
1182+ lk.unlock();
1183+ exec(surface.get());
1184+ }
1185+ });
1186+ }
1187+ surface_reservations.erase(surface_id);
1188 surfaces[surface_id] = surface;
1189 }
1190
1191
1192=== modified file 'src/client/connection_surface_map.h'
1193--- src/client/connection_surface_map.h 2017-03-14 04:41:33 +0000
1194+++ src/client/connection_surface_map.h 2017-03-28 00:17:49 +0000
1195@@ -23,19 +23,43 @@
1196
1197 #include <shared_mutex>
1198 #include <unordered_map>
1199+#include <vector>
1200
1201 class MirPresentationChain;
1202 class MirRenderSurface;
1203 namespace mir
1204 {
1205+namespace dispatch
1206+{
1207+class ActionQueue;
1208+}
1209 namespace client
1210 {
1211 class MirBuffer;
1212 class ConnectionSurfaceMap : public SurfaceMap
1213 {
1214 public:
1215+<<<<<<< TREE
1216 virtual std::shared_ptr<MirWindow> surface(frontend::SurfaceId) const override;
1217 void insert(frontend::SurfaceId surface_id, std::shared_ptr<MirWindow> const& surface);
1218+=======
1219+ ConnectionSurfaceMap(std::shared_ptr<dispatch::ActionQueue> delayed_queue);
1220+
1221+ void with_surface_do(frontend::SurfaceId surface_id, std::function<void(MirSurface*)> const& exec) const override;
1222+ /**
1223+ * Notify the surface map that a surface will be constructed.
1224+ *
1225+ * After this call, calls to with_surface_do(surface_id, functor) will succeed, but defer execution
1226+ * of functor until a subsequent call to insert(surface_id, surf).
1227+ *
1228+ * Any functor queued will be executed on the delayed queue, not in the stack of
1229+ * the insert() call.
1230+ *
1231+ * \param [in] surface_id ID of the surface about to be created.
1232+ */
1233+ void reserve(frontend::SurfaceId surface_id);
1234+ void insert(frontend::SurfaceId surface_id, std::shared_ptr<MirSurface> const& surface);
1235+>>>>>>> MERGE-SOURCE
1236 void erase(frontend::SurfaceId surface_id);
1237
1238 virtual std::shared_ptr<MirBufferStream> stream(frontend::BufferStreamId) const override;
1239@@ -57,8 +81,16 @@
1240 std::shared_ptr<MirRenderSurface> render_surface(void* render_surface_key) const;
1241 #pragma GCC diagnostic pop
1242 private:
1243+ std::shared_ptr<dispatch::ActionQueue> const delayed_queue;
1244+
1245 std::shared_timed_mutex mutable guard;
1246+<<<<<<< TREE
1247 std::unordered_map<frontend::SurfaceId, std::shared_ptr<MirWindow>> surfaces;
1248+=======
1249+ std::unordered_map<frontend::SurfaceId, std::shared_ptr<MirSurface>> surfaces;
1250+ std::mutex mutable reserved_guard;
1251+ std::unordered_map<frontend::SurfaceId, std::vector<std::function<void(MirSurface*)>>> mutable surface_reservations;
1252+>>>>>>> MERGE-SOURCE
1253 std::shared_timed_mutex mutable stream_guard;
1254 std::unordered_map<frontend::BufferStreamId, std::shared_ptr<MirBufferStream>> streams;
1255 std::unordered_map<frontend::BufferStreamId, std::shared_ptr<MirPresentationChain>> chains;
1256
1257=== added file 'src/client/default_client_buffer_stream_factory.cpp.THIS'
1258--- src/client/default_client_buffer_stream_factory.cpp.THIS 1970-01-01 00:00:00 +0000
1259+++ src/client/default_client_buffer_stream_factory.cpp.THIS 2017-03-28 00:17:49 +0000
1260@@ -0,0 +1,87 @@
1261+/*
1262+ * Copyright © 2015 Canonical Ltd.
1263+ *
1264+ * This program is free software: you can redistribute it and/or modify it
1265+ * under the terms of the GNU Lesser General Public License version 3,
1266+ * as published by the Free Software Foundation.
1267+ *
1268+ * This program is distributed in the hope that it will be useful,
1269+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1270+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1271+ * GNU Lesser General Public License for more details.
1272+ *
1273+ * You should have received a copy of the GNU Lesser General Public License
1274+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1275+ *
1276+ * Authored by: Robert Carr <robert.carr@canonical.com>
1277+ */
1278+#include "default_client_buffer_stream_factory.h"
1279+#include "buffer_stream.h"
1280+#include "perf_report.h"
1281+#include "logging/perf_report.h"
1282+#include "lttng/perf_report.h"
1283+
1284+namespace mcl = mir::client;
1285+namespace ml = mir::logging;
1286+namespace mp = mir::protobuf;
1287+
1288+namespace
1289+{
1290+
1291+std::shared_ptr<mcl::PerfReport>
1292+make_perf_report(std::shared_ptr<ml::Logger> const& logger)
1293+{
1294+ // TODO: It seems strange that this directly uses getenv
1295+ const char* report_target = getenv("MIR_CLIENT_PERF_REPORT");
1296+ if (report_target && !strncmp(report_target, "log", strlen(report_target)))
1297+ {
1298+ return std::make_shared<mcl::logging::PerfReport>(logger);
1299+ }
1300+ else if (report_target && !strncmp(report_target, "lttng", strlen(report_target)))
1301+ {
1302+ return std::make_shared<mcl::lttng::PerfReport>();
1303+ }
1304+ else
1305+ {
1306+ return std::make_shared<mcl::NullPerfReport>();
1307+ }
1308+}
1309+
1310+}
1311+
1312+mcl::DefaultClientBufferStreamFactory::DefaultClientBufferStreamFactory(
1313+ std::shared_ptr<mcl::ClientPlatform> const& client_platform,
1314+ std::shared_ptr<ml::Logger> const& logger)
1315+ : client_platform(client_platform),
1316+ logger(logger)
1317+{
1318+}
1319+
1320+std::shared_ptr<mcl::ClientBufferStream> mcl::DefaultClientBufferStreamFactory::make_consumer_stream(
1321+ MirConnection* allocating_connection,
1322+ mp::DisplayServer& server,
1323+ mp::BufferStream const& protobuf_bs,
1324+ std::string const& surface_name)
1325+{
1326+ return std::make_shared<mcl::BufferStream>(allocating_connection, server, mcl::BufferStreamMode::Consumer, client_platform, protobuf_bs, make_perf_report(logger), surface_name);
1327+}
1328+
1329+std::shared_ptr<mcl::ClientBufferStream> mcl::DefaultClientBufferStreamFactory::make_producer_stream(
1330+ MirConnection* allocating_connection,
1331+ mp::DisplayServer& server,
1332+ mp::BufferStream const& protobuf_bs,
1333+ std::string const& surface_name)
1334+{
1335+ return std::make_shared<mcl::BufferStream>(allocating_connection, server, mcl::BufferStreamMode::Producer, client_platform, protobuf_bs, make_perf_report(logger), surface_name);
1336+}
1337+
1338+
1339+mcl::ClientBufferStream* mcl::DefaultClientBufferStreamFactory::make_producer_stream(
1340+ MirConnection* allocating_connection,
1341+ mp::DisplayServer& server,
1342+ mp::BufferStreamParameters const& params,
1343+ mir_buffer_stream_callback callback,
1344+ void* context)
1345+{
1346+ return new mcl::BufferStream(allocating_connection, server, client_platform, params, make_perf_report(logger), callback, context);
1347+}
1348
1349=== added file 'src/client/default_client_buffer_stream_factory.h.THIS'
1350--- src/client/default_client_buffer_stream_factory.h.THIS 1970-01-01 00:00:00 +0000
1351+++ src/client/default_client_buffer_stream_factory.h.THIS 2017-03-28 00:17:49 +0000
1352@@ -0,0 +1,70 @@
1353+/*
1354+ * Copyright © 2015 Canonical Ltd.
1355+ *
1356+ * This program is free software: you can redistribute it and/or modify it
1357+ * under the terms of the GNU Lesser General Public License version 3,
1358+ * as published by the Free Software Foundation.
1359+ *
1360+ * This program is distributed in the hope that it will be useful,
1361+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1362+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1363+ * GNU Lesser General Public License for more details.
1364+ *
1365+ * You should have received a copy of the GNU Lesser General Public License
1366+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1367+ *
1368+ * Authored by: Robert Carr <robert.carr@canonical.com>
1369+ */
1370+
1371+#ifndef MIR_CLIENT_DEFAULT_CLIENT_BUFFER_STREAM_FACTORY_H_
1372+#define MIR_CLIENT_DEFAULT_CLIENT_BUFFER_STREAM_FACTORY_H_
1373+
1374+#include "client_buffer_stream_factory.h"
1375+
1376+class MirConnection;
1377+
1378+namespace mir
1379+{
1380+namespace logging
1381+{
1382+class Logger;
1383+}
1384+namespace client
1385+{
1386+class ClientBufferFactory;
1387+class ClientPlatform;
1388+
1389+class DefaultClientBufferStreamFactory : public ClientBufferStreamFactory
1390+{
1391+public:
1392+ DefaultClientBufferStreamFactory(
1393+ std::shared_ptr<ClientPlatform> const& native_window_factory,
1394+ std::shared_ptr<logging::Logger> const& logger);
1395+ virtual ~DefaultClientBufferStreamFactory() = default;
1396+
1397+ std::shared_ptr<ClientBufferStream> make_consumer_stream(
1398+ MirConnection* allocating_connection,
1399+ protobuf::DisplayServer& server,
1400+ protobuf::BufferStream const& protobuf_bs,
1401+ std::string const& surface_name) override;
1402+ std::shared_ptr<ClientBufferStream> make_producer_stream(
1403+ MirConnection* allocating_connection,
1404+ protobuf::DisplayServer& server,
1405+ protobuf::BufferStream const& protobuf_bs,
1406+ std::string const& surface_name) override;
1407+
1408+ ClientBufferStream* make_producer_stream(
1409+ MirConnection* allocating_connection,
1410+ protobuf::DisplayServer& server,
1411+ protobuf::BufferStreamParameters const& params,
1412+ mir_buffer_stream_callback callback, void* context) override;
1413+
1414+private:
1415+ std::shared_ptr<ClientPlatform> const client_platform;
1416+ std::shared_ptr<logging::Logger> const logger;
1417+
1418+};
1419+}
1420+}
1421+
1422+#endif // MIR_CLIENT_DEFAULT_CLIENT_BUFFER_STREAM_FACTORY_H_
1423
1424=== modified file 'src/client/default_connection_configuration.cpp'
1425--- src/client/default_connection_configuration.cpp 2017-02-15 14:45:41 +0000
1426+++ src/client/default_connection_configuration.cpp 2017-03-28 00:17:49 +0000
1427@@ -37,8 +37,10 @@
1428 #include "probing_client_platform_factory.h"
1429 #include "mir_event_distributor.h"
1430 #include "buffer_factory.h"
1431+#include "mir/dispatch/action_queue.h"
1432
1433 namespace mcl = mir::client;
1434+namespace md = mir::dispatch;
1435
1436 namespace
1437 {
1438@@ -53,12 +55,23 @@
1439 {
1440 }
1441
1442+std::shared_ptr<md::ActionQueue>
1443+mcl::DefaultConnectionConfiguration::the_delayed_queue()
1444+{
1445+ return delayed_queue(
1446+ []()
1447+ {
1448+ return std::make_shared<md::ActionQueue>();
1449+ });
1450+}
1451+
1452 std::shared_ptr<mcl::ConnectionSurfaceMap>
1453 mcl::DefaultConnectionConfiguration::the_surface_map()
1454 {
1455- return surface_map([]
1456+ return surface_map(
1457+ [this]()
1458 {
1459- return std::make_shared<mcl::ConnectionSurfaceMap>();
1460+ return std::make_shared<mcl::ConnectionSurfaceMap>(the_delayed_queue());
1461 });
1462 }
1463
1464
1465=== modified file 'src/client/default_connection_configuration.h'
1466--- src/client/default_connection_configuration.h 2017-02-15 14:45:41 +0000
1467+++ src/client/default_connection_configuration.h 2017-03-28 00:17:49 +0000
1468@@ -50,6 +50,7 @@
1469 public:
1470 DefaultConnectionConfiguration(std::string const& socket_file);
1471
1472+ std::shared_ptr<dispatch::ActionQueue> the_delayed_queue() override;
1473 std::shared_ptr<ConnectionSurfaceMap> the_surface_map() override;
1474 std::shared_ptr<mir::client::rpc::MirBasicRpcChannel> the_rpc_channel() override;
1475 std::shared_ptr<mir::logging::Logger> the_logger() override;
1476@@ -69,6 +70,7 @@
1477 virtual std::shared_ptr<input::receiver::InputReceiverReport> the_input_receiver_report();
1478
1479 protected:
1480+ CachedPtr<dispatch::ActionQueue> delayed_queue;
1481 CachedPtr<mir::client::rpc::MirBasicRpcChannel> rpc_channel;
1482 CachedPtr<mir::logging::Logger> logger;
1483 CachedPtr<ClientPlatformFactory> client_platform_factory;
1484
1485=== modified file 'src/client/error_render_surface.cpp'
1486--- src/client/error_render_surface.cpp 2017-01-18 02:29:37 +0000
1487+++ src/client/error_render_surface.cpp 2017-03-28 00:17:49 +0000
1488@@ -54,10 +54,7 @@
1489 return false;
1490 }
1491
1492-MirBufferStream* mcl::ErrorRenderSurface::get_buffer_stream(
1493- int /*width*/, int /*height*/,
1494- MirPixelFormat /*format*/,
1495- MirBufferUsage /*buffer_usage*/)
1496+void mcl::ErrorRenderSurface::get_buffer_stream(int, int, MirPixelFormat, MirBufferUsage, mir_buffer_stream_callback, void*)
1497 {
1498 BOOST_THROW_EXCEPTION(std::runtime_error(error));
1499 }
1500
1501=== modified file 'src/client/error_render_surface.h'
1502--- src/client/error_render_surface.h 2017-03-10 19:47:57 +0000
1503+++ src/client/error_render_surface.h 2017-03-28 00:17:49 +0000
1504@@ -39,10 +39,13 @@
1505 void set_size(mir::geometry::Size) override;
1506 bool valid() const override;
1507 char const* get_error_message() const override;
1508- MirBufferStream* get_buffer_stream(
1509- int width, int height,
1510+ void get_buffer_stream(
1511+ int width,
1512+ int height,
1513 MirPixelFormat format,
1514- MirBufferUsage buffer_usage) override;
1515+ MirBufferUsage buffer_usage,
1516+ mir_buffer_stream_callback callback,
1517+ void* context) override;
1518 MirPresentationChain* get_presentation_chain() override;
1519 private:
1520 std::string const error;
1521
1522=== modified file 'src/client/mir_buffer_stream_api.cpp'
1523--- src/client/mir_buffer_stream_api.cpp 2017-01-24 07:37:03 +0000
1524+++ src/client/mir_buffer_stream_api.cpp 2017-03-28 00:17:49 +0000
1525@@ -30,25 +30,14 @@
1526 #include "mir/uncaught.h"
1527 #include "mir/require.h"
1528
1529+#include "synchronous_helper.h"
1530+
1531 #include <stdexcept>
1532 #include <boost/throw_exception.hpp>
1533
1534 namespace mcl = mir::client;
1535 namespace mp = mir::protobuf;
1536
1537-namespace
1538-{
1539-// assign_result is compatible with all 2-parameter callbacks
1540-void assign_result(void* result, void** context)
1541-{
1542- if (context)
1543- *context = result;
1544-}
1545-
1546-}
1547-
1548-
1549-
1550 MirWaitHandle* mir_connection_create_buffer_stream(MirConnection *connection,
1551 int width, int height,
1552 MirPixelFormat format,
1553@@ -72,9 +61,20 @@
1554 MirBufferUsage buffer_usage)
1555 try
1556 {
1557+<<<<<<< TREE
1558 MirBufferStream *stream = nullptr;
1559 mir_connection_create_buffer_stream(connection, width, height, format, buffer_usage,
1560 reinterpret_cast<MirBufferStreamCallback>(assign_result), &stream)->wait_for_all();
1561+=======
1562+ MirBufferStream* stream = nullptr;
1563+ make_synchronous_call(
1564+ connection,
1565+ mir_connection_create_buffer_stream,
1566+ connection,
1567+ width, height, format, buffer_usage,
1568+ &assign_result<MirBufferStream>,
1569+ &stream);
1570+>>>>>>> MERGE-SOURCE
1571 return stream;
1572 }
1573 catch (std::exception const& ex)
1574@@ -94,7 +94,12 @@
1575
1576 void mir_buffer_stream_release_sync(MirBufferStream *buffer_stream)
1577 {
1578- mir_buffer_stream_release(buffer_stream, nullptr, nullptr)->wait_for_all();
1579+ make_synchronous_call(
1580+ buffer_stream->connection(),
1581+ &mir_buffer_stream_release,
1582+ buffer_stream,
1583+ &assign_result<MirBufferStream>,
1584+ static_cast<void*>(nullptr));
1585 }
1586
1587 void mir_buffer_stream_get_current_buffer(MirBufferStream* buffer_stream, MirNativeBuffer** buffer_package_out)
1588@@ -132,6 +137,7 @@
1589 }
1590
1591 void mir_buffer_stream_swap_buffers_sync(MirBufferStream* buffer_stream)
1592+<<<<<<< TREE
1593 try
1594 {
1595 buffer_stream->swap_buffers_sync();
1596@@ -139,6 +145,15 @@
1597 catch (std::exception const& ex)
1598 {
1599 MIR_LOG_UNCAUGHT_EXCEPTION(ex);
1600+=======
1601+{
1602+ make_synchronous_call(
1603+ buffer_stream->connection(),
1604+ &mir_buffer_stream_swap_buffers,
1605+ buffer_stream,
1606+ &assign_result<MirBufferStream>,
1607+ static_cast<void*>(nullptr));
1608+>>>>>>> MERGE-SOURCE
1609 }
1610
1611 bool mir_buffer_stream_get_graphics_region(
1612
1613=== modified file 'src/client/mir_connection.cpp'
1614--- src/client/mir_connection.cpp 2017-03-21 05:51:47 +0000
1615+++ src/client/mir_connection.cpp 2017-03-28 00:17:49 +0000
1616@@ -27,8 +27,12 @@
1617 #include "mir/client_platform.h"
1618 #include "mir/client_platform_factory.h"
1619 #include "rpc/mir_basic_rpc_channel.h"
1620+#include "rpc/mir_protobuf_rpc_channel.h"
1621 #include "mir/dispatch/dispatchable.h"
1622+#include "mir/dispatch/multiplexing_dispatchable.h"
1623 #include "mir/dispatch/threaded_dispatcher.h"
1624+#include "mir/dispatch/multiplexing_dispatchable.h"
1625+#include "mir/dispatch/action_queue.h"
1626 #include "mir/input/input_devices.h"
1627 #include "connection_configuration.h"
1628 #include "display_configuration.h"
1629@@ -53,6 +57,7 @@
1630 #include "mir/logging/logger.h"
1631 #include "mir/platform_message.h"
1632 #include "mir_error.h"
1633+#include "mir/require.h"
1634
1635 #include <algorithm>
1636 #include <cstddef>
1637@@ -63,6 +68,7 @@
1638 #include <boost/throw_exception.hpp>
1639
1640 namespace mcl = mir::client;
1641+namespace mclr = mir::client::rpc;
1642 namespace md = mir::dispatch;
1643 namespace mircv = mir::input::receiver;
1644 namespace mev = mir::events;
1645@@ -309,8 +315,13 @@
1646 {
1647 }
1648
1649+MirConnection::MirConnection(mir::client::ConnectionConfiguration& conf) :
1650+ MirConnection(conf, DispatchType::automatic)
1651+{
1652+}
1653+
1654 MirConnection::MirConnection(
1655- mir::client::ConnectionConfiguration& conf) :
1656+ mir::client::ConnectionConfiguration& conf, DispatchType dispatch) :
1657 deregisterer{this},
1658 surface_map(conf.the_surface_map()),
1659 buffer_factory(conf.the_buffer_factory()),
1660@@ -330,13 +341,26 @@
1661 display_configuration(conf.the_display_configuration()),
1662 input_devices{conf.the_input_devices()},
1663 lifecycle_control(conf.the_lifecycle_control()),
1664+ event_handler_register(conf.the_event_handler_register()),
1665+ dispatcher{std::make_shared<md::MultiplexingDispatchable>()},
1666+ eventloop{dispatch == DispatchType::automatic ?
1667+ std::make_unique<md::ThreadedDispatcher>("RPC Dispatch", dispatcher) :
1668+ nullptr
1669+ },
1670 ping_handler{conf.the_ping_handler()},
1671+ pong_callback(google::protobuf::NewPermanentCallback(&google::protobuf::DoNothing)),
1672+ delayed_queue{conf.the_delayed_queue()},
1673 error_handler{conf.the_error_handler()},
1674- event_handler_register(conf.the_event_handler_register()),
1675- pong_callback(google::protobuf::NewPermanentCallback(&google::protobuf::DoNothing)),
1676- eventloop{new md::ThreadedDispatcher{"RPC Thread", std::dynamic_pointer_cast<md::Dispatchable>(channel)}},
1677 nbuffers(get_nbuffers_from_env())
1678 {
1679+ dispatcher->add_watch(channel);
1680+ dispatcher->add_watch(delayed_queue);
1681+ if (eventloop)
1682+ {
1683+ // Need a second thread ensure RPC is not blocked if the delayed_queue blocks,
1684+ // as it does when waiting for surface creation.
1685+ eventloop->add_thread();
1686+ }
1687 connect_result->set_error("connect not called");
1688 {
1689 std::lock_guard<std::mutex> lock(connection_guard);
1690@@ -419,38 +443,41 @@
1691 if (request_it == surface_requests.end())
1692 return;
1693
1694- auto surface_proto = request->response;
1695- auto callback = request->cb;
1696- auto context = request->context;
1697+ auto surface_proto = request->response;
1698 auto const& spec = request->spec;
1699 std::string name{spec.surface_name.is_set() ?
1700 spec.surface_name.value() : ""};
1701+ surface_map->reserve(mf::SurfaceId{surface_proto->id().value()});
1702
1703- std::shared_ptr<MirBufferStream> default_stream {nullptr};
1704+ mcl::NoTLSFuture<std::unique_ptr<mcl::BufferStream>> default_stream;
1705 if (surface_proto->buffer_stream().has_id())
1706 {
1707 try
1708 {
1709- default_stream = std::make_shared<mcl::BufferStream>(
1710+ default_stream = mcl::BufferStream::create(
1711 this, nullptr, request->wh, server, platform, surface_map, buffer_factory,
1712 surface_proto->buffer_stream(), make_perf_report(logger), name,
1713- mir::geometry::Size{surface_proto->width(), surface_proto->height()}, nbuffers);
1714- surface_map->insert(default_stream->rpc_id(), default_stream);
1715+ mir::geometry::Size{surface_proto->width(), surface_proto->height()},
1716+ nbuffers);
1717 }
1718 catch (std::exception const& error)
1719 {
1720 if (!surface_proto->has_error())
1721 surface_proto->set_error(error.what());
1722- // Clean up surface_proto's direct fds; BufferStream has cleaned up any owned by
1723- // surface_proto->buffer_stream()
1724- for (auto i = 0; i < surface_proto->fd_size(); i++)
1725- ::close(surface_proto->fd(i));
1726 }
1727 }
1728
1729+<<<<<<< TREE
1730 std::shared_ptr<MirWindow> surf {nullptr};
1731+=======
1732+>>>>>>> MERGE-SOURCE
1733 if (surface_proto->has_error() || !surface_proto->has_id())
1734 {
1735+ // Clean up surface_proto's direct fds; BufferStream has cleaned up any owned by
1736+ // surface_proto->buffer_stream()
1737+ for (auto i = 0; i < surface_proto->fd_size(); i++)
1738+ ::close(surface_proto->fd(i));
1739+
1740 std::string reason;
1741 if (surface_proto->has_error())
1742 reason += surface_proto->error();
1743@@ -459,19 +486,63 @@
1744 if (!surface_proto->has_id())
1745 reason += "Server assigned surface no id";
1746 auto id = next_error_id(lock);
1747+<<<<<<< TREE
1748 surf = std::make_shared<MirWindow>(reason, this, id, request->wh);
1749+=======
1750+ auto surf = std::make_shared<MirSurface>(reason, this, id, request->wh);
1751+>>>>>>> MERGE-SOURCE
1752 surface_map->insert(id, surf);
1753+
1754+ request->cb(surf.get(), request->context);
1755+ request->wh->result_received();
1756+ }
1757+ else if (default_stream.valid())
1758+ {
1759+ default_stream.then(
1760+ [this, request = *request_it](auto&& resolved_stream) -> void
1761+ {
1762+ std::shared_ptr<MirSurface> surf;
1763+ std::shared_ptr<MirBufferStream> stream;
1764+ try
1765+ {
1766+ stream = resolved_stream.get();
1767+ surface_map->insert(stream->rpc_id(), stream);
1768+ }
1769+ catch (std::exception const& error)
1770+ {
1771+ request->response->set_error(error.what());
1772+ }
1773+
1774+ surf = std::make_shared<MirSurface>(
1775+ this,
1776+ server,
1777+ &debug,
1778+ stream,
1779+ input_platform,
1780+ request->spec,
1781+ *request->response,
1782+ request->wh);
1783+ surface_map->insert(mf::SurfaceId{request->response->id().value()}, surf);
1784+
1785+ request->cb(surf.get(), request->context);
1786+ request->wh->result_received();
1787+ }).detach();
1788 }
1789 else
1790 {
1791+<<<<<<< TREE
1792 surf = std::make_shared<MirWindow>(
1793 this, server, &debug, default_stream, spec, *surface_proto, request->wh);
1794+=======
1795+ auto surf = std::make_shared<MirSurface>(
1796+ this, server, &debug, nullptr, input_platform, spec, *surface_proto, request->wh);
1797+>>>>>>> MERGE-SOURCE
1798 surface_map->insert(mf::SurfaceId{surface_proto->id().value()}, surf);
1799+
1800+ request->cb(surf.get(), request->context);
1801+ request->wh->result_received();
1802 }
1803
1804- callback(surf.get(), context);
1805- request->wh->result_received();
1806-
1807 surface_requests.erase(request_it);
1808 }
1809
1810@@ -515,17 +586,17 @@
1811
1812 void MirConnection::released(StreamRelease data)
1813 {
1814+ {
1815+ std::unique_lock<decltype(mutex)> lk(mutex);
1816+ if (data.rs)
1817+ surface_map->erase(data.rs);
1818+ surface_map->erase(mf::BufferStreamId(data.rpc_id));
1819+ }
1820+
1821 if (data.callback)
1822 data.callback(data.stream, data.context);
1823 if (data.handle)
1824 data.handle->result_received();
1825-
1826- {
1827- std::unique_lock<decltype(mutex)> lk(mutex);
1828- if (data.rs)
1829- surface_map->erase(data.rs);
1830- surface_map->erase(mf::BufferStreamId(data.rpc_id));
1831- }
1832 }
1833
1834 void MirConnection::released(SurfaceRelease data)
1835@@ -701,6 +772,36 @@
1836 return &disconnect_wait_handle;
1837 }
1838
1839+mir::Fd MirConnection::watch_fd() const
1840+{
1841+ return eventloop ? mir::Fd{} : dispatcher->watch_fd();
1842+}
1843+
1844+void MirConnection::dispatch()
1845+{
1846+ mir::require(!eventloop);
1847+
1848+ dispatcher->dispatch(md::FdEvent::readable);
1849+}
1850+
1851+void MirConnection::add_dispatchee(std::shared_ptr<mir::dispatch::Dispatchable> const& dispatchee)
1852+{
1853+ dispatcher->add_watch(dispatchee);
1854+ if (eventloop)
1855+ {
1856+ eventloop->add_thread();
1857+ }
1858+}
1859+
1860+void MirConnection::remove_dispatchee(std::shared_ptr<mir::dispatch::Dispatchable> const& dispatchee)
1861+{
1862+ dispatcher->remove_watch(dispatchee);
1863+ if (eventloop)
1864+ {
1865+ eventloop->remove_thread();
1866+ }
1867+}
1868+
1869 void MirConnection::done_platform_operation(
1870 MirPlatformOperationCallback callback, void* context)
1871 {
1872@@ -880,16 +981,34 @@
1873
1874 try
1875 {
1876- auto stream = std::make_shared<mcl::BufferStream>(
1877- this, request->rs, request->wh, server, platform, surface_map, buffer_factory,
1878- *protobuf_bs, make_perf_report(logger), std::string{},
1879- mir::geometry::Size{request->parameters.width(), request->parameters.height()}, nbuffers);
1880- surface_map->insert(mf::BufferStreamId(protobuf_bs->id().value()), stream);
1881-
1882- if (request->mbs_callback)
1883- request->mbs_callback(stream.get(), request->context);
1884-
1885- request->wh->result_received();
1886+ auto future_stream = mcl::BufferStream::create(
1887+ this,
1888+ request->rs,
1889+ request->wh,
1890+ server,
1891+ platform,
1892+ surface_map,
1893+ buffer_factory,
1894+ *protobuf_bs,
1895+ make_perf_report(logger),
1896+ std::string{},
1897+ mir::geometry::Size{request->parameters.width(), request->parameters.height()},
1898+ nbuffers);
1899+
1900+ future_stream.then(
1901+ [this, request](auto&& resolved_stream) -> void
1902+ {
1903+ std::shared_ptr<mcl::BufferStream> stream{resolved_stream.get()};
1904+ auto& protobuf_bs = request->response;
1905+
1906+ surface_map->insert(mf::BufferStreamId(protobuf_bs->id().value()), stream);
1907+
1908+ request->mbs_callback(
1909+ static_cast<MirBufferStream*>(stream.get()),
1910+ request->context);
1911+
1912+ request->wh->result_received();
1913+ }).detach();
1914 }
1915 catch (std::exception const& error)
1916 {
1917@@ -939,17 +1058,25 @@
1918 return request->wh.get();
1919 }
1920
1921-std::shared_ptr<mir::client::BufferStream> MirConnection::create_client_buffer_stream_with_id(
1922+mcl::NoTLSFuture<std::unique_ptr<mcl::BufferStream>>
1923+MirConnection::create_client_buffer_stream_with_id(
1924 int width, int height,
1925 MirRenderSurface* render_surface,
1926 mir::protobuf::BufferStream const& a_protobuf_bs)
1927 {
1928- auto stream = std::make_shared<mcl::BufferStream>(
1929- this, render_surface, nullptr, server, platform, surface_map, buffer_factory,
1930- a_protobuf_bs, make_perf_report(logger), std::string{},
1931- mir::geometry::Size{width, height}, nbuffers);
1932- surface_map->insert(render_surface->stream_id(), stream);
1933- return stream;
1934+ return mcl::BufferStream::create(
1935+ this,
1936+ render_surface,
1937+ nullptr,
1938+ server,
1939+ platform,
1940+ surface_map,
1941+ buffer_factory,
1942+ a_protobuf_bs,
1943+ make_perf_report(logger),
1944+ std::string{},
1945+ mir::geometry::Size{width, height},
1946+ nbuffers);
1947 }
1948 #pragma GCC diagnostic pop
1949
1950@@ -1322,8 +1449,15 @@
1951 server.release_buffers(&request, ignored.get(), gp::NewCallback(ignore));
1952 }
1953
1954+void MirConnection::process_next_request_first()
1955+{
1956+ channel->process_next_request_first();
1957+}
1958+
1959 void MirConnection::release_render_surface_with_content(
1960- void* render_surface)
1961+ void* render_surface,
1962+ mir_render_surface_callback callback,
1963+ void* ctx)
1964 {
1965 auto rs = surface_map->render_surface(render_surface);
1966 if (!rs->valid())
1967@@ -1332,13 +1466,23 @@
1968 return;
1969 }
1970
1971- StreamRelease stream_release{
1972- nullptr,
1973- nullptr,
1974- nullptr,
1975- nullptr,
1976- rs->stream_id().as_value(),
1977- render_surface};
1978+<<<<<<< TREE
1979+ StreamRelease stream_release{
1980+ nullptr,
1981+ nullptr,
1982+ nullptr,
1983+ nullptr,
1984+ rs->stream_id().as_value(),
1985+ render_surface};
1986+=======
1987+ StreamRelease stream_release{
1988+ reinterpret_cast<MirBufferStream*>(render_surface),
1989+ nullptr,
1990+ reinterpret_cast<mir_buffer_stream_callback>(callback),
1991+ ctx,
1992+ rs->stream_id().as_value(),
1993+ render_surface};
1994+>>>>>>> MERGE-SOURCE
1995
1996 mp::BufferStreamId buffer_stream_id;
1997 buffer_stream_id.set_value(rs->stream_id().as_value());
1998
1999=== modified file 'src/client/mir_connection.h'
2000--- src/client/mir_connection.h 2017-03-14 04:41:33 +0000
2001+++ src/client/mir_connection.h 2017-03-28 00:17:49 +0000
2002@@ -34,6 +34,7 @@
2003 #include "mir_surface.h"
2004 #include "display_configuration.h"
2005 #include "error_handler.h"
2006+#include "no_tls_future-inl.h"
2007
2008 #include <atomic>
2009 #include <memory>
2010@@ -42,6 +43,8 @@
2011 #include <unordered_set>
2012 #include <unordered_map>
2013
2014+#include "mir/fd.h"
2015+
2016 namespace mir
2017 {
2018 namespace input
2019@@ -85,8 +88,17 @@
2020 namespace dispatch
2021 {
2022 class ThreadedDispatcher;
2023-}
2024-}
2025+class Dispatchable;
2026+class MultiplexingDispatchable;
2027+class ActionQueue;
2028+}
2029+}
2030+
2031+enum class DispatchType
2032+{
2033+ automatic,
2034+ manual
2035+};
2036
2037 struct MirConnection : mir::client::ClientContext
2038 {
2039@@ -94,6 +106,7 @@
2040 MirConnection(std::string const& error_message);
2041
2042 MirConnection(mir::client::ConnectionConfiguration& conf);
2043+ MirConnection(mir::client::ConnectionConfiguration &conf, DispatchType dispatch);
2044 ~MirConnection() noexcept;
2045
2046 MirConnection(MirConnection const &) = delete;
2047@@ -119,6 +132,12 @@
2048
2049 MirWaitHandle* disconnect();
2050
2051+ mir::Fd watch_fd() const;
2052+ void dispatch();
2053+
2054+ void add_dispatchee(std::shared_ptr<mir::dispatch::Dispatchable> const& dispatchee);
2055+ void remove_dispatchee(std::shared_ptr<mir::dispatch::Dispatchable> const& dispatchee);
2056+
2057 MirWaitHandle* platform_operation(
2058 MirPlatformMessage const* request,
2059 MirPlatformOperationCallback callback, void* context) override;
2060@@ -151,7 +170,7 @@
2061 MirRenderSurface* render_surface,
2062 MirBufferStreamCallback mbs_callback,
2063 void *context);
2064- std::shared_ptr<mir::client::BufferStream> create_client_buffer_stream_with_id(
2065+ mir::client::NoTLSFuture<std::unique_ptr<mir::client::BufferStream>> create_client_buffer_stream_with_id(
2066 int width, int height,
2067 MirRenderSurface* render_surface,
2068 mir::protobuf::BufferStream const& a_protobuf_bs);
2069@@ -221,10 +240,13 @@
2070 void* context) -> MirRenderSurface*;
2071 #pragma GCC diagnostic pop
2072 void release_render_surface_with_content(
2073- void* render_surface);
2074+ void* render_surface,
2075+ mir_render_surface_callback callback,
2076+ void* ctx);
2077
2078 void* request_interface(char const* name, int version);
2079
2080+ void process_next_request_first();
2081 private:
2082 //google cant have callbacks with more than 2 args
2083 struct SurfaceCreationRequest
2084@@ -242,7 +264,7 @@
2085 std::shared_ptr<MirWaitHandle> wh;
2086 };
2087 std::vector<std::shared_ptr<SurfaceCreationRequest>> surface_requests;
2088- void surface_created(SurfaceCreationRequest*);
2089+ void surface_created(SurfaceCreationRequest*);
2090
2091 struct StreamCreationRequest
2092 {
2093@@ -350,16 +372,20 @@
2094
2095 std::shared_ptr<mir::client::LifecycleControl> const lifecycle_control;
2096
2097+
2098+ std::shared_ptr<mir::client::EventHandlerRegister> const event_handler_register;
2099+
2100+ std::shared_ptr<mir::dispatch::MultiplexingDispatchable> const dispatcher;
2101+ std::unique_ptr<mir::dispatch::ThreadedDispatcher> const eventloop;
2102+
2103 std::shared_ptr<mir::client::PingHandler> const ping_handler;
2104
2105+ std::unique_ptr<google::protobuf::Closure> const pong_callback;
2106+
2107+ std::shared_ptr<mir::dispatch::ActionQueue> const delayed_queue;
2108+
2109 std::shared_ptr<mir::client::ErrorHandler> error_handler;
2110
2111- std::shared_ptr<mir::client::EventHandlerRegister> const event_handler_register;
2112-
2113- std::unique_ptr<google::protobuf::Closure> const pong_callback;
2114-
2115- std::unique_ptr<mir::dispatch::ThreadedDispatcher> const eventloop;
2116-
2117
2118 struct SurfaceRelease;
2119 struct StreamRelease;
2120
2121=== modified file 'src/client/mir_connection_api.cpp'
2122--- src/client/mir_connection_api.cpp 2017-02-15 07:38:33 +0000
2123+++ src/client/mir_connection_api.cpp 2017-03-28 00:17:49 +0000
2124@@ -29,9 +29,11 @@
2125 #include "display_configuration.h"
2126 #include "error_connections.h"
2127 #include "mir/uncaught.h"
2128+#include "synchronous_helper.h"
2129
2130 #include <cstddef>
2131 #include <cstring>
2132+#include <poll.h>
2133
2134 namespace mcl = mir::client;
2135 namespace mp = mir::protobuf;
2136@@ -39,12 +41,105 @@
2137
2138 namespace
2139 {
2140+<<<<<<< TREE
2141 // assign_result is compatible with all 2-parameter callbacks
2142 void assign_result(void* result, void** context)
2143 {
2144 if (context)
2145 *context = result;
2146 }
2147+=======
2148+class DefaultMirConnectionAPI : public mcl::MirConnectionAPI
2149+{
2150+public:
2151+ MirWaitHandle* connect(
2152+ mcl::ConfigurationFactory configuration,
2153+ char const* socket_file,
2154+ char const* name,
2155+ mir_connected_callback callback,
2156+ void* context) override
2157+ {
2158+ try
2159+ {
2160+ std::string sock;
2161+ if (socket_file)
2162+ sock = socket_file;
2163+ else
2164+ {
2165+ auto socket_env = getenv("MIR_SOCKET");
2166+ if (socket_env && socket_env[0])
2167+ sock = socket_env;
2168+ else
2169+ sock = mir::default_server_socket;
2170+ }
2171+
2172+ auto const conf = configuration(sock);
2173+
2174+ auto connection = std::make_unique<MirConnection>(*conf);
2175+ auto const result = connection->connect(name, callback, context);
2176+ connection.release();
2177+ return result;
2178+ }
2179+ catch (std::exception const& x)
2180+ {
2181+ MirConnection* error_connection = new MirConnection(x.what());
2182+ mcl::ErrorConnections::instance().insert(error_connection);
2183+ callback(error_connection, context);
2184+ return nullptr;
2185+ }
2186+ }
2187+
2188+ void release(MirConnection* connection) override
2189+ {
2190+ if (!mcl::ErrorConnections::instance().contains(connection))
2191+ {
2192+ try
2193+ {
2194+ auto wait_handle = connection->disconnect();
2195+ if (connection->watch_fd() != mir::Fd::invalid)
2196+ {
2197+ pollfd fd;
2198+ fd.fd = connection->watch_fd();
2199+ fd.events = POLLIN;
2200+ while(wait_handle->is_pending() && (poll(&fd, 1, -1) > 0))
2201+ {
2202+ connection->dispatch();
2203+ }
2204+ }
2205+ else
2206+ {
2207+ wait_handle->wait_for_all();
2208+ }
2209+ }
2210+ catch (std::exception const& ex)
2211+ {
2212+ // We're implementing a C API so no exceptions are to be
2213+ // propagated. And that's OK because if disconnect() fails,
2214+ // we don't care why. We're finished with the connection anyway.
2215+
2216+ MIR_LOG_UNCAUGHT_EXCEPTION(ex);
2217+ }
2218+ }
2219+ else
2220+ {
2221+ mcl::ErrorConnections::instance().remove(connection);
2222+ }
2223+
2224+ delete connection;
2225+ }
2226+
2227+ mcl::ConfigurationFactory configuration_factory() override
2228+ {
2229+ return [](std::string const& socket) {
2230+ return std::unique_ptr<mcl::ConnectionConfiguration>{
2231+ new mcl::DefaultConnectionConfiguration{socket}
2232+ };
2233+ };
2234+ }
2235+};
2236+
2237+DefaultMirConnectionAPI default_api;
2238+>>>>>>> MERGE-SOURCE
2239 }
2240
2241 MirWaitHandle* mir_connect(
2242@@ -94,6 +189,7 @@
2243 char const* app_name)
2244 {
2245 MirConnection* conn = nullptr;
2246+<<<<<<< TREE
2247 auto wh = mir_connect(server, app_name,
2248 reinterpret_cast<MirConnectedCallback>
2249 (assign_result),
2250@@ -104,9 +200,62 @@
2251 wh->wait_for_all();
2252 }
2253
2254+=======
2255+ mir_wait_for(mir_connect(server, app_name,
2256+ assign_result,
2257+ &conn));
2258+>>>>>>> MERGE-SOURCE
2259 return conn;
2260 }
2261
2262+MirConnection* mir_connect_with_manual_dispatch(
2263+ char const* server,
2264+ char const* app_name,
2265+ mir_connected_callback callback,
2266+ void* context)
2267+{
2268+ try
2269+ {
2270+ std::string sock;
2271+ if (server)
2272+ sock = server;
2273+ else
2274+ {
2275+ auto socket_env = getenv("MIR_SOCKET");
2276+ if (socket_env)
2277+ sock = socket_env;
2278+ else
2279+ sock = mir::default_server_socket;
2280+ }
2281+
2282+ mcl::DefaultConnectionConfiguration conf{sock};
2283+
2284+ std::unique_ptr<MirConnection> connection{new MirConnection(conf, DispatchType::manual)};
2285+ connection->connect(app_name, callback, context);
2286+ return connection.release();
2287+ }
2288+ catch (std::exception const& x)
2289+ {
2290+ MirConnection* error_connection = new MirConnection(x.what());
2291+ mcl::ErrorConnections::instance().insert(error_connection);
2292+ callback(error_connection, context);
2293+ return error_connection;
2294+ }
2295+}
2296+
2297+MirConnection* mir_connect_with_manual_dispatch_sync(
2298+ char const* server,
2299+ char const* app_name)
2300+{
2301+ MirConnection* result = nullptr;
2302+
2303+ auto connection = mir_connect_with_manual_dispatch(server, app_name, &assign_result, &result);
2304+
2305+ dispatch_connection_until(connection, [&result]() { return result != nullptr; });
2306+
2307+ return connection;
2308+}
2309+
2310 bool mir_connection_is_valid(MirConnection* connection)
2311 {
2312 return MirConnection::is_valid(connection);
2313@@ -139,6 +288,16 @@
2314 MIR_LOG_UNCAUGHT_EXCEPTION(ex);
2315 }
2316
2317+int mir_connection_get_event_fd(MirConnection* connection)
2318+{
2319+ return connection->watch_fd();
2320+}
2321+
2322+void mir_connection_dispatch(MirConnection* connection)
2323+{
2324+ connection->dispatch();
2325+}
2326+
2327 void mir_connection_get_platform(
2328 MirConnection* connection,
2329 MirPlatformPackage* platform_package)
2330
2331=== modified file 'src/client/mir_prompt_session_api.cpp'
2332--- src/client/mir_prompt_session_api.cpp 2017-03-10 19:47:57 +0000
2333+++ src/client/mir_prompt_session_api.cpp 2017-03-28 00:17:49 +0000
2334@@ -25,6 +25,8 @@
2335 #include "mir/require.h"
2336 #include "mir/uncaught.h"
2337
2338+#include "synchronous_helper.h"
2339+
2340 #include <stdexcept>
2341 #include <boost/throw_exception.hpp>
2342
2343@@ -46,6 +48,17 @@
2344 prompt_session->register_prompt_session_state_change_callback(state_change_callback, context);
2345 prompt_session->start(application_pid, null_callback, nullptr)->wait_for_all();
2346
2347+<<<<<<< TREE
2348+=======
2349+ make_synchronous_call(
2350+ connection,
2351+ std::mem_fn(&MirPromptSession::start),
2352+ prompt_session,
2353+ application_pid,
2354+ &assign_result<MirPromptSession>,
2355+ static_cast<void*>(nullptr));
2356+
2357+>>>>>>> MERGE-SOURCE
2358 return prompt_session;
2359 }
2360 catch (std::exception const& ex)
2361
2362=== modified file 'src/client/mir_render_surface_api.cpp'
2363--- src/client/mir_render_surface_api.cpp 2017-03-14 04:41:33 +0000
2364+++ src/client/mir_render_surface_api.cpp 2017-03-28 00:17:49 +0000
2365@@ -163,10 +163,13 @@
2366 }
2367
2368 void mir_render_surface_release(
2369- MirRenderSurface* render_surface)
2370+ MirRenderSurface* render_surface,
2371+ mir_render_surface_callback callback,
2372+ void* ctx)
2373 try
2374 {
2375 mir::require(render_surface);
2376+<<<<<<< TREE
2377 auto connection = connection_map.connection(render_surface);
2378 connection_map.erase(render_surface);
2379 connection->release_render_surface_with_content(render_surface);
2380@@ -180,17 +183,114 @@
2381 MirRenderSurface* render_surface,
2382 int width, int height,
2383 MirPixelFormat format)
2384-try
2385-{
2386+=======
2387+ auto connection = connection_map.connection(static_cast<void*>(render_surface));
2388+ connection_map.erase(static_cast<void*>(render_surface));
2389+ connection->release_render_surface_with_content(render_surface, callback, ctx);
2390+}
2391+catch (std::exception const& ex)
2392+{
2393+ callback(render_surface, ctx);
2394+ MIR_LOG_UNCAUGHT_EXCEPTION(ex);
2395+}
2396+
2397+void mir_render_surface_get_buffer_stream(
2398+ MirRenderSurface* render_surface,
2399+ int width,
2400+ int height,
2401+ MirPixelFormat format,
2402+ MirBufferUsage usage,
2403+ mir_buffer_stream_callback callback,
2404+ void* context)
2405+try
2406+{
2407+ mir::require(render_surface);
2408+ auto connection = connection_map.connection(static_cast<void*>(render_surface));
2409+ auto rs = connection->connection_surface_map()->render_surface(render_surface);
2410+ rs->get_buffer_stream(width, height, format, usage, callback, context);
2411+}
2412+catch (std::exception const& ex)
2413+{
2414+ MIR_LOG_UNCAUGHT_EXCEPTION(ex);
2415+}
2416+
2417+MirBufferStream* mir_render_surface_get_buffer_stream_sync(
2418+ MirRenderSurface* render_surface,
2419+ int width,
2420+ int height,
2421+ MirPixelFormat format,
2422+ MirBufferUsage usage)
2423+>>>>>>> MERGE-SOURCE
2424+try
2425+{
2426+<<<<<<< TREE
2427 mir::require(render_surface);
2428 auto connection = connection_map.connection(render_surface);
2429 auto rs = connection->connection_surface_map()->render_surface(render_surface);
2430 return rs->get_buffer_stream(width, height, format, mir_buffer_usage_software);
2431+=======
2432+ struct BufferStreamResult
2433+ {
2434+ std::mutex lock;
2435+ std::condition_variable notify;
2436+ bool done{false};
2437+ MirBufferStream* result;
2438+ } ready;
2439+
2440+ mir_render_surface_get_buffer_stream(
2441+ render_surface,
2442+ width, height,
2443+ format,
2444+ usage,
2445+ [](MirBufferStream* stream, void* context)
2446+ {
2447+ auto result = reinterpret_cast<BufferStreamResult*>(context);
2448+
2449+ {
2450+ std::lock_guard<std::mutex> lock{result->lock};
2451+ result->result = stream;
2452+ result->done = true;
2453+ }
2454+ result->notify.notify_all();
2455+ },
2456+ &ready);
2457+
2458+ std::unique_lock<std::mutex> lock{ready.lock};
2459+ ready.notify.wait(lock, [&ready]() { return ready.done; });
2460+
2461+ return ready.result;
2462+>>>>>>> MERGE-SOURCE
2463 }
2464 catch (std::exception const& ex)
2465 {
2466 MIR_LOG_UNCAUGHT_EXCEPTION(ex);
2467- return nullptr;
2468+ std::terminate();
2469+}
2470+
2471+void mir_render_surface_release_sync(MirRenderSurface* render_surface)
2472+{
2473+ struct Waiter
2474+ {
2475+ std::condition_variable notifier;
2476+ std::mutex lock;
2477+ bool done{false};
2478+ } waiter;
2479+
2480+ mir_render_surface_release(
2481+ render_surface,
2482+ [](MirRenderSurface*, void* ctx)
2483+ {
2484+ auto waiter = reinterpret_cast<Waiter*>(ctx);
2485+ {
2486+ std::lock_guard<std::mutex> lock{waiter->lock};
2487+ waiter->done = true;
2488+ }
2489+ waiter->notifier.notify_all();
2490+ },
2491+ &waiter);
2492+
2493+ std::unique_lock<std::mutex> lock(waiter.lock);
2494+ waiter.notifier.wait(lock, [&waiter]() { return waiter.done; });
2495 }
2496
2497 MirPresentationChain* mir_render_surface_get_presentation_chain(
2498
2499=== modified file 'src/client/mir_screencast.cpp'
2500--- src/client/mir_screencast.cpp 2017-03-10 19:47:57 +0000
2501+++ src/client/mir_screencast.cpp 2017-03-28 00:17:49 +0000
2502@@ -104,8 +104,9 @@
2503 {
2504 }
2505
2506-MirScreencast::MirScreencast(std::string const& error)
2507- : protobuf_screencast{mcl::make_protobuf_object<mir::protobuf::Screencast>()}
2508+MirScreencast::MirScreencast(MirConnection* connection, std::string const& error)
2509+ : connection{connection},
2510+ protobuf_screencast{mcl::make_protobuf_object<mir::protobuf::Screencast>()}
2511 {
2512 protobuf_screencast->set_error(error);
2513 }
2514@@ -178,7 +179,12 @@
2515 }
2516
2517 void MirScreencast::screencast_created(
2518+<<<<<<< TREE
2519 MirScreencastCallback callback, void* context)
2520+=======
2521+ mir_screencast_callback callback,
2522+ void* context)
2523+>>>>>>> MERGE-SOURCE
2524 {
2525 if (!protobuf_screencast->has_error() && connection)
2526 {
2527@@ -219,3 +225,8 @@
2528 std::lock_guard<decltype(mutex)> lock(mutex);
2529 return buffer_stream.get();
2530 }
2531+
2532+MirConnection* MirScreencast::get_connection()
2533+{
2534+ return connection;
2535+}
2536
2537=== modified file 'src/client/mir_screencast.h'
2538--- src/client/mir_screencast.h 2017-01-24 07:37:03 +0000
2539+++ src/client/mir_screencast.h 2017-03-28 00:17:49 +0000
2540@@ -68,7 +68,7 @@
2541 struct MirScreencast
2542 {
2543 public:
2544- MirScreencast(std::string const& error);
2545+ MirScreencast(MirConnection* connection, std::string const& error);
2546 MirScreencast(
2547 MirScreencastSpec const& spec,
2548 mir::client::rpc::DisplayServer& server,
2549@@ -85,6 +85,7 @@
2550
2551 MirBufferStream* get_buffer_stream();
2552
2553+ MirConnection* get_connection();
2554 private:
2555 void screencast_created(
2556 MirScreencastCallback callback, void* context);
2557
2558=== modified file 'src/client/mir_screencast_api.cpp'
2559--- src/client/mir_screencast_api.cpp 2017-01-18 02:29:37 +0000
2560+++ src/client/mir_screencast_api.cpp 2017-03-28 00:17:49 +0000
2561@@ -25,6 +25,8 @@
2562 #include "mir/require.h"
2563 #include "mir/uncaught.h"
2564
2565+#include "synchronous_helper.h"
2566+
2567 #include <stdexcept>
2568 #include <boost/throw_exception.hpp>
2569
2570@@ -35,7 +37,18 @@
2571 {
2572 auto& server = spec->connection->display_server();
2573 auto screencast = std::make_unique<MirScreencast>(*spec, server, null_callback, nullptr);
2574- screencast->creation_wait_handle()->wait_for_all();
2575+
2576+ if (spec->connection->watch_fd() != mir::Fd::invalid)
2577+ {
2578+ dispatch_connection_until(spec->connection, [&screencast]()
2579+ {
2580+ return !screencast->creation_wait_handle()->is_pending();
2581+ });
2582+ }
2583+ else
2584+ {
2585+ screencast->creation_wait_handle()->wait_for_all();
2586+ }
2587
2588 auto raw_screencast = screencast.get();
2589 screencast.release();
2590@@ -92,7 +105,7 @@
2591 catch (std::exception const& ex)
2592 {
2593 MIR_LOG_UNCAUGHT_EXCEPTION(ex);
2594- return new MirScreencast(ex.what());
2595+ return new MirScreencast(spec->connection, ex.what());
2596 }
2597
2598 bool mir_screencast_is_valid(MirScreencast *screencast)
2599@@ -117,7 +130,11 @@
2600
2601 void mir_screencast_release_sync(MirScreencast* screencast)
2602 {
2603- screencast->release(null_callback, nullptr)->wait_for_all();
2604+ make_synchronous_call(screencast->get_connection(),
2605+ std::mem_fn(&MirScreencast::release),
2606+ screencast,
2607+ &assign_result<MirScreencast>,
2608+ static_cast<void*>(nullptr));
2609 delete screencast;
2610 }
2611
2612
2613=== modified file 'src/client/mir_surface.cpp'
2614--- src/client/mir_surface.cpp 2017-03-23 17:23:58 +0000
2615+++ src/client/mir_surface.cpp 2017-03-28 00:17:49 +0000
2616@@ -194,6 +194,15 @@
2617 spec.event_handler.value().context);
2618 }
2619
2620+<<<<<<< TREE
2621+=======
2622+ if (surface_proto.fd_size() > 0 && handle_event_callback)
2623+ {
2624+ input_dispatcher = input_platform->create_input_receiver(surface_proto.fd(0), keymapper, handle_event_callback);
2625+ connection()->add_dispatchee(input_dispatcher);
2626+ }
2627+
2628+>>>>>>> MERGE-SOURCE
2629 std::lock_guard<decltype(handle_mutex)> lock(handle_mutex);
2630 valid_surfaces.insert(this);
2631
2632@@ -220,7 +229,10 @@
2633
2634 std::lock_guard<decltype(mutex)> lock(mutex);
2635
2636- input_thread.reset();
2637+ if (input_dispatcher)
2638+ {
2639+ connection()->remove_dispatchee(input_dispatcher);
2640+ }
2641
2642 for (auto i = 0, end = surface->fd_size(); i != end; ++i)
2643 close(surface->fd(i));
2644@@ -466,7 +478,12 @@
2645 {
2646 std::lock_guard<decltype(mutex)> lock(mutex);
2647
2648- input_thread.reset();
2649+ if (input_dispatcher)
2650+ {
2651+ connection()->remove_dispatchee(input_dispatcher);
2652+ input_dispatcher.reset();
2653+ }
2654+
2655 handle_event_callback = [](auto){};
2656
2657 if (callback)
2658@@ -474,6 +491,17 @@
2659 handle_event_callback = std::bind(callback, this,
2660 std::placeholders::_1,
2661 context);
2662+<<<<<<< TREE
2663+=======
2664+
2665+ if (surface->fd_size() > 0 && handle_event_callback)
2666+ {
2667+ input_dispatcher = input_platform->create_input_receiver(surface->fd(0),
2668+ keymapper,
2669+ handle_event_callback);
2670+ connection()->add_dispatchee(input_dispatcher);
2671+ }
2672+>>>>>>> MERGE-SOURCE
2673 }
2674 }
2675
2676
2677=== modified file 'src/client/mir_surface.h'
2678--- src/client/mir_surface.h 2017-03-23 17:23:58 +0000
2679+++ src/client/mir_surface.h 2017-03-28 00:17:49 +0000
2680@@ -44,7 +44,7 @@
2681 {
2682 namespace dispatch
2683 {
2684-class ThreadedDispatcher;
2685+class Dispatchable;
2686 }
2687 namespace input
2688 {
2689@@ -263,9 +263,13 @@
2690 std::shared_ptr<mir::client::FrameClock> const frame_clock;
2691
2692 std::function<void(MirEvent const*)> handle_event_callback;
2693+<<<<<<< TREE
2694 std::function<void(MirWindowEvent const*)> handle_drag_and_drop_start_callback = [](auto){};
2695
2696 std::shared_ptr<mir::dispatch::ThreadedDispatcher> input_thread;
2697+=======
2698+ std::shared_ptr<mir::dispatch::Dispatchable> input_dispatcher;
2699+>>>>>>> MERGE-SOURCE
2700
2701 //a bit batty, but the creation handle has to exist for as long as the MirSurface does,
2702 //as we don't really manage the lifetime of MirWaitHandle sensibly.
2703@@ -274,7 +278,6 @@
2704 MirPixelFormat format;
2705 MirBufferUsage usage;
2706 uint32_t output_id;
2707-
2708 };
2709
2710 #pragma GCC diagnostic pop
2711
2712=== modified file 'src/client/mir_surface_api.cpp'
2713--- src/client/mir_surface_api.cpp 2017-03-14 04:41:33 +0000
2714+++ src/client/mir_surface_api.cpp 2017-03-28 00:17:49 +0000
2715@@ -30,6 +30,7 @@
2716 #include "error_connections.h"
2717 #include "connection_surface_map.h"
2718 #include "mir/uncaught.h"
2719+#include "synchronous_helper.h"
2720
2721 #include <boost/exception/diagnostic_information.hpp>
2722 #include <functional>
2723@@ -37,6 +38,7 @@
2724
2725 namespace mcl = mir::client;
2726
2727+<<<<<<< TREE
2728 namespace
2729 {
2730 MirWaitHandle* mir_configure_cursor_helper(MirWindow* window, MirCursorConfiguration const* cursor)
2731@@ -895,6 +897,8 @@
2732 MIR_LOG_UNCAUGHT_EXCEPTION(ex);
2733 }
2734
2735+=======
2736+>>>>>>> MERGE-SOURCE
2737 MirSurfaceSpec* mir_connection_create_spec_for_normal_surface(MirConnection* connection,
2738 int width, int height,
2739 MirPixelFormat format)
2740@@ -969,7 +973,20 @@
2741
2742 MirSurface* mir_surface_create_sync(MirSurfaceSpec* requested_specification)
2743 {
2744+<<<<<<< TREE
2745 return mir_create_window_sync(requested_specification);
2746+=======
2747+ MirSurface* surface = nullptr;
2748+
2749+ make_synchronous_call(
2750+ requested_specification->connection,
2751+ &mir_surface_create,
2752+ requested_specification,
2753+ &assign_result<MirSurface>,
2754+ &surface);
2755+
2756+ return surface;
2757+>>>>>>> MERGE-SOURCE
2758 }
2759
2760 MirWaitHandle* mir_surface_create(MirSurfaceSpec* requested_specification,
2761@@ -1172,7 +1189,15 @@
2762
2763 void mir_surface_release_sync(MirSurface* surface)
2764 {
2765+<<<<<<< TREE
2766 mir_window_release_sync(surface);
2767+=======
2768+ make_synchronous_call(surface->connection(),
2769+ mir_surface_release,
2770+ surface,
2771+ &assign_result<MirSurface>,
2772+ static_cast<void*>(nullptr));
2773+>>>>>>> MERGE-SOURCE
2774 }
2775
2776 MirSurfaceType mir_surface_get_type(MirSurface* surf)
2777
2778=== modified file 'src/client/mir_wait_api.cpp'
2779--- src/client/mir_wait_api.cpp 2014-03-31 14:36:08 +0000
2780+++ src/client/mir_wait_api.cpp 2017-03-28 00:17:49 +0000
2781@@ -30,3 +30,12 @@
2782 if (wait_handle)
2783 wait_handle->wait_for_one();
2784 }
2785+
2786+bool mir_wait_handle_ready(MirWaitHandle* wait_handle)
2787+{
2788+ if (wait_handle)
2789+ {
2790+ return !wait_handle->is_pending();
2791+ }
2792+ return true;
2793+}
2794
2795=== modified file 'src/client/no_tls_future-inl.h'
2796--- src/client/no_tls_future-inl.h 2017-01-18 02:29:37 +0000
2797+++ src/client/no_tls_future-inl.h 2017-03-28 00:17:49 +0000
2798@@ -395,6 +395,7 @@
2799 NoTLSPromiseBase& operator=(NoTLSPromiseBase&& other)
2800 {
2801 state = std::move(other.state);
2802+ return *this;
2803 }
2804
2805 NoTLSPromiseBase(NoTLSPromiseBase const&) = delete;
2806
2807=== modified file 'src/client/render_surface.cpp'
2808--- src/client/render_surface.cpp 2017-03-14 02:26:28 +0000
2809+++ src/client/render_surface.cpp 2017-03-28 00:17:49 +0000
2810@@ -25,6 +25,7 @@
2811 #include "mir/client_platform.h"
2812
2813 #include <boost/throw_exception.hpp>
2814+#include <mir/require.h>
2815
2816 namespace mcl = mir::client;
2817 namespace geom = mir::geometry;
2818@@ -55,27 +56,46 @@
2819 return mf::BufferStreamId(protobuf_bs->id().value());
2820 }
2821
2822-MirBufferStream* mcl::RenderSurface::get_buffer_stream(
2823- int width, int height,
2824+void mcl::RenderSurface::get_buffer_stream(
2825+ int width,
2826+ int height,
2827 MirPixelFormat format,
2828- MirBufferUsage buffer_usage)
2829+ MirBufferUsage buffer_usage,
2830+ mir_buffer_stream_callback callback,
2831+ void* context)
2832 {
2833 if (chain_from_id || stream_from_id)
2834+ {
2835+ callback(nullptr, context);
2836 BOOST_THROW_EXCEPTION(std::logic_error("Content already handed out"));
2837+ }
2838
2839 protobuf_bs->set_pixel_format(format);
2840 protobuf_bs->set_buffer_usage(buffer_usage);
2841- stream_from_id = connection_->create_client_buffer_stream_with_id(width,
2842- height,
2843- this,
2844- *protobuf_bs);
2845- if (buffer_usage == mir_buffer_usage_hardware)
2846- {
2847- platform->use_egl_native_window(
2848- wrapped_native_window, dynamic_cast<EGLNativeSurface*>(stream_from_id.get()));
2849- }
2850-
2851- return stream_from_id.get();
2852+
2853+ connection_->create_client_buffer_stream_with_id(
2854+ width,
2855+ height,
2856+ this,
2857+ *protobuf_bs).then(
2858+ [
2859+ this,
2860+ buffer_usage,
2861+ callback,
2862+ context
2863+ ](auto&& resolved_future)
2864+ {
2865+ auto bs = resolved_future.get();
2866+
2867+ if (buffer_usage == mir_buffer_usage_hardware)
2868+ {
2869+ platform->use_egl_native_window(
2870+ wrapped_native_window, dynamic_cast<EGLNativeSurface*>(bs.get()));
2871+ }
2872+
2873+ stream_from_id = std::move(bs);
2874+ callback(static_cast<MirBufferStream*>(stream_from_id.get()), context);
2875+ }).detach();
2876 }
2877
2878 MirPresentationChain* mcl::RenderSurface::get_presentation_chain()
2879
2880=== modified file 'src/client/render_surface.h'
2881--- src/client/render_surface.h 2017-03-10 19:47:57 +0000
2882+++ src/client/render_surface.h 2017-03-28 00:17:49 +0000
2883@@ -56,10 +56,13 @@
2884 mir::frontend::BufferStreamId stream_id() const override;
2885 char const* get_error_message() const override;
2886 bool valid() const override;
2887- MirBufferStream* get_buffer_stream(
2888- int width, int height,
2889+ void get_buffer_stream(
2890+ int width,
2891+ int height,
2892 MirPixelFormat format,
2893- MirBufferUsage buffer_usage) override;
2894+ MirBufferUsage buffer_usage,
2895+ mir_buffer_stream_callback callback,
2896+ void* context) override;
2897 MirPresentationChain* get_presentation_chain() override;
2898
2899 private:
2900
2901=== modified file 'src/client/rpc/make_rpc_channel.h'
2902--- src/client/rpc/make_rpc_channel.h 2017-01-18 02:29:37 +0000
2903+++ src/client/rpc/make_rpc_channel.h 2017-03-28 00:17:49 +0000
2904@@ -41,6 +41,7 @@
2905 {
2906 class MirBasicRpcChannel;
2907 class RpcReport;
2908+class MirBasicRpcChannel;
2909
2910 std::shared_ptr<mir::client::rpc::MirBasicRpcChannel>
2911 make_rpc_channel(
2912
2913=== modified file 'src/client/rpc/mir_basic_rpc_channel.h'
2914--- src/client/rpc/mir_basic_rpc_channel.h 2017-01-30 05:18:36 +0000
2915+++ src/client/rpc/mir_basic_rpc_channel.h 2017-03-28 00:17:49 +0000
2916@@ -19,6 +19,8 @@
2917 #ifndef MIR_CLIENT_RPC_MIR_BASIC_RPC_CHANNEL_H_
2918 #define MIR_CLIENT_RPC_MIR_BASIC_RPC_CHANNEL_H_
2919
2920+#include "mir/dispatch/dispatchable.h"
2921+
2922 #include <memory>
2923 #include <map>
2924 #include <mutex>
2925@@ -105,6 +107,7 @@
2926 }
2927
2928 class MirBasicRpcChannel
2929+ : public mir::dispatch::Dispatchable
2930 {
2931 public:
2932 virtual ~MirBasicRpcChannel();
2933@@ -115,11 +118,16 @@
2934 google::protobuf::MessageLite* response,
2935 google::protobuf::Closure* complete) = 0;
2936
2937+<<<<<<< TREE
2938 virtual void discard_future_calls() = 0;
2939 virtual void wait_for_outstanding_calls() = 0;
2940
2941+=======
2942+ virtual void process_next_request_first() = 0;
2943+>>>>>>> MERGE-SOURCE
2944 protected:
2945 MirBasicRpcChannel();
2946+
2947 mir::protobuf::wire::Invocation invocation_for(
2948 std::string const& method_name,
2949 google::protobuf::MessageLite const* request,
2950
2951=== modified file 'src/client/rpc/mir_protobuf_rpc_channel.cpp'
2952--- src/client/rpc/mir_protobuf_rpc_channel.cpp 2017-03-17 17:20:09 +0000
2953+++ src/client/rpc/mir_protobuf_rpc_channel.cpp 2017-03-28 00:17:49 +0000
2954@@ -374,7 +374,7 @@
2955 {
2956 for(auto i = 0; i < seq.buffer_request().buffer().fd_size(); i++)
2957 close(seq.buffer_request().buffer().fd(i));
2958- throw e;
2959+ throw;
2960 }
2961 }
2962 else
2963@@ -395,13 +395,22 @@
2964 // But that's a job for later...
2965 try
2966 {
2967+<<<<<<< TREE
2968 auto e = MirEvent::deserialize(event.raw());
2969+=======
2970+ std::shared_ptr<MirEvent> e = mev::deserialize_event(event.raw());
2971+>>>>>>> MERGE-SOURCE
2972 if (e)
2973 {
2974 rpc_report->event_parsing_succeeded(*e);
2975
2976+<<<<<<< TREE
2977 int window_id = 0;
2978 bool is_window_event = true;
2979+=======
2980+ auto const send_e = [e](MirSurface* surface)
2981+ { surface->handle_event(*e); };
2982+>>>>>>> MERGE-SOURCE
2983
2984 switch (e->type())
2985 {
2986
2987=== modified file 'src/client/rpc/mir_protobuf_rpc_channel.h'
2988--- src/client/rpc/mir_protobuf_rpc_channel.h 2017-01-30 05:18:36 +0000
2989+++ src/client/rpc/mir_protobuf_rpc_channel.h 2017-03-28 00:17:49 +0000
2990@@ -53,8 +53,7 @@
2991
2992 class MirProtobufRpcChannel :
2993 public MirBasicRpcChannel,
2994- public StreamTransport::Observer,
2995- public dispatch::Dispatchable
2996+ public StreamTransport::Observer
2997 {
2998 public:
2999 MirProtobufRpcChannel(std::unique_ptr<StreamTransport> transport,
3000@@ -91,7 +90,7 @@
3001 *
3002 * No messages are discarded, only delayed.
3003 */
3004- void process_next_request_first();
3005+ void process_next_request_first() override;
3006
3007 void call_method(
3008 std::string const& method_name,
3009@@ -112,6 +111,7 @@
3010 detail::SendBuffer header_bytes;
3011 detail::SendBuffer body_bytes;
3012
3013+
3014 void receive_file_descriptors(google::protobuf::MessageLite* response);
3015 template<class MessageType>
3016 void receive_any_file_descriptors_for(MessageType* response);
3017
3018=== modified file 'src/client/symbols.map'
3019--- src/client/symbols.map 2017-03-21 05:51:47 +0000
3020+++ src/client/symbols.map 2017-03-28 00:17:49 +0000
3021@@ -346,17 +346,23 @@
3022 mir_connection_create_render_surface;
3023 mir_connection_create_render_surface_sync;
3024 mir_render_surface_get_buffer_stream;
3025+ mir_render_surface_get_buffer_stream_sync;
3026 mir_render_surface_get_presentation_chain;
3027 mir_render_surface_is_valid;
3028 mir_render_surface_get_error_message;
3029 mir_render_surface_get_size;
3030 mir_render_surface_set_size;
3031 mir_render_surface_release;
3032+<<<<<<< TREE
3033 mir_connection_present_mode_supported;
3034 mir_presentation_chain_set_mode;
3035 mir_window_spec_add_render_surface;
3036 mir_window_spec_set_cursor_render_surface;
3037 mir_cursor_configuration_from_render_surface;
3038+=======
3039+ mir_render_surface_release_sync;
3040+ mir_surface_spec_add_render_surface;
3041+>>>>>>> MERGE-SOURCE
3042
3043 #private functions needed temporarily by nested passthrough
3044 #should not be published along with the rest of the NBS symbols
3045@@ -395,6 +401,11 @@
3046 mir_input_device_state_event_time;
3047 mir_input_device_state_event_device_pointer_buttons;
3048 mir_surface_spec_set_pointer_confinement;
3049+ mir_connect_with_manual_dispatch;
3050+ mir_connect_with_manual_dispatch_sync;
3051+ mir_connection_get_event_fd;
3052+ mir_connection_dispatch;
3053+ mir_wait_handle_ready;
3054 } MIR_CLIENT_0.22;
3055
3056 MIR_CLIENT_0.25 { # New functions in Mir 0.25
3057@@ -552,6 +563,7 @@
3058 mir_window_request_persistent_id;
3059 mir_window_request_persistent_id_sync;
3060 } MIR_CLIENT_0.25;
3061+<<<<<<< TREE
3062
3063 MIR_CLIENT_0.26.1 { # New functions in Mir 0.26.1
3064 global:
3065@@ -616,3 +628,12 @@
3066 mir_touchscreen_config_set_mapping_mode;
3067 mir_touchscreen_config_set_output_id;
3068 } MIR_CLIENT_0.26.1;
3069+=======
3070+
3071+MIR_CLIENT_DETAIL_0.26 {
3072+ global:
3073+ extern "C++" {
3074+ mir::client::DefaultConnectionConfiguration::the_delayed_queue*;
3075+ };
3076+} MIR_CLIENT_DETAIL_0.25;
3077+>>>>>>> MERGE-SOURCE
3078
3079=== added file 'src/client/synchronous_helper.cpp'
3080--- src/client/synchronous_helper.cpp 1970-01-01 00:00:00 +0000
3081+++ src/client/synchronous_helper.cpp 2017-03-28 00:17:49 +0000
3082@@ -0,0 +1,33 @@
3083+/*
3084+ * Copyright © 2015 Canonical Ltd.
3085+ *
3086+ * This program is free software: you can redistribute it and/or modify it
3087+ * under the terms of the GNU Lesser General Public License version 3,
3088+ * as published by the Free Software Foundation.
3089+ *
3090+ * This program is distributed in the hope that it will be useful,
3091+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
3092+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3093+ * GNU Lesser General Public License for more details.
3094+ *
3095+ * You should have received a copy of the GNU Lesser General Public License
3096+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
3097+ *
3098+ * Authored by: Christopher James Halse Rogers <christopher.halse.rogers@canonical.com>
3099+ */
3100+
3101+#include "synchronous_helper.h"
3102+
3103+#include <poll.h>
3104+
3105+void dispatch_connection_until(MirConnection* connection, std::function<bool()> predicate)
3106+{
3107+ pollfd fd;
3108+ fd.fd = connection->watch_fd();
3109+ fd.events = POLLIN;
3110+ while(!predicate() && (poll(&fd, 1, -1) > 0))
3111+ {
3112+ connection->dispatch();
3113+ }
3114+}
3115+
3116
3117=== added file 'src/client/synchronous_helper.h'
3118--- src/client/synchronous_helper.h 1970-01-01 00:00:00 +0000
3119+++ src/client/synchronous_helper.h 2017-03-28 00:17:49 +0000
3120@@ -0,0 +1,160 @@
3121+/*
3122+ * Copyright © 2015 Canonical Ltd.
3123+ *
3124+ * This program is free software: you can redistribute it and/or modify it
3125+ * under the terms of the GNU Lesser General Public License version 3,
3126+ * as published by the Free Software Foundation.
3127+ *
3128+ * This program is distributed in the hope that it will be useful,
3129+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
3130+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3131+ * GNU Lesser General Public License for more details.
3132+ *
3133+ * You should have received a copy of the GNU Lesser General Public License
3134+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
3135+ *
3136+ * Authored by: Christopher James Halse Rogers <christopher.halse.rogers@canonical.com>
3137+ */
3138+
3139+#ifndef MIR_CLIENT_SYNCHRONOUS_H_
3140+#define MIR_CLIENT_SYNCHRONOUS_H_
3141+
3142+#include "mir_connection.h"
3143+#include "mir_wait_handle.h"
3144+
3145+#include <functional>
3146+#include <type_traits>
3147+
3148+template<typename Result>
3149+void assign_result(Result* result, void* ctx)
3150+{
3151+ auto assignee = reinterpret_cast<Result**>(ctx);
3152+ if (assignee)
3153+ {
3154+ *assignee = result;
3155+ }
3156+}
3157+
3158+template<typename Callback>
3159+struct SynchronousContext
3160+{
3161+ Callback real_callback;
3162+ bool complete;
3163+ void* userdata;
3164+};
3165+
3166+template<typename Callable, class Tuple, std::size_t...I>
3167+void apply_substituting_last_arg(
3168+ Callable&& function,
3169+ Tuple&& args,
3170+ std::index_sequence<I...>,
3171+ void* context)
3172+{
3173+ return std::forward<Callable>(function)(
3174+ std::get<I>(std::forward<Tuple>(args))...,
3175+ context);
3176+}
3177+
3178+
3179+template<typename... Args>
3180+void synchronous_wrapper(Args... args)
3181+{
3182+ std::tuple<Args...> arguments{args...};
3183+ constexpr std::size_t arg_count = sizeof...(Args);
3184+
3185+ auto wrapped_context = reinterpret_cast<SynchronousContext<void(*)(Args...)>*>(std::get<arg_count - 1>(arguments));
3186+ if (wrapped_context->real_callback)
3187+ {
3188+ apply_substituting_last_arg(
3189+ wrapped_context->real_callback,
3190+ std::forward_as_tuple(args...),
3191+ std::make_index_sequence<arg_count - 1>(),
3192+ wrapped_context->userdata);
3193+ }
3194+ wrapped_context->complete = true;
3195+}
3196+
3197+
3198+template<typename Callable, typename Tuple, std::size_t...I>
3199+constexpr decltype(auto) call_impl(Callable&& function, Tuple&& args, std::index_sequence<I...>)
3200+{
3201+ return std::forward<Callable>(function)(std::get<I>(std::forward<Tuple>((args)))...);
3202+}
3203+
3204+template<typename Callable, typename Tuple>
3205+constexpr decltype(auto) apply(Callable&& function, Tuple&& args)
3206+{
3207+ return call_impl(
3208+ std::forward<Callable>(function),
3209+ std::forward<Tuple>(args),
3210+ std::make_index_sequence<std::tuple_size<std::decay_t<Tuple>>{}>{});
3211+}
3212+
3213+void dispatch_connection_until(MirConnection* connection, std::function<bool()> predicate);
3214+
3215+
3216+/**
3217+ * \brief Make a synchronous RPC call
3218+ *
3219+ * This wrapper takes care of manually dispatching the MirConnection if it is in
3220+ * manual dispatch mode, or waiting for the operation to complete if in automatic
3221+ * dispatch mode.
3222+ *
3223+ * Given a function mir_foo_do_thing(MirFoo* target, int arg, foo_callback callback, void* context)
3224+ * the correct way to call this function is
3225+ * make_synchronous_call(connection,
3226+ * &mir_foo_do_thing,
3227+ * target,
3228+ * arg,
3229+ * callback,
3230+ * static_cast<void*>(context));
3231+ *
3232+ * The last two parameters must be the callback function and the void* to pass to that callback.
3233+ * The last argument must have a pointer type; NULL or nullptr must be explicitly cast to
3234+ * void*.
3235+ */
3236+template<typename Callable, typename... Args>
3237+void make_synchronous_call(MirConnection* connection,
3238+ Callable&& function,
3239+ Args&&... args)
3240+{
3241+ static_assert(
3242+ std::is_same<typename std::result_of<Callable(Args...)>::type, MirWaitHandle*>::value,
3243+ "Second parameter must be a function that returns a MirWaitHandle*");
3244+
3245+ if (connection->watch_fd() != mir::Fd::invalid)
3246+ {
3247+ std::tuple<Args...> arguments{args...};
3248+ constexpr int arg_count = sizeof...(Args);
3249+ auto callback = std::get<arg_count - 2>(arguments);
3250+ auto context = std::get<arg_count - 1>(arguments);
3251+
3252+ static_assert(
3253+ std::is_pointer<typename std::tuple_element<arg_count - 1, std::tuple<Args...>>::type>::value,
3254+ "The final argument must be a pointer type");
3255+ static_assert(
3256+ std::is_pointer<typename std::tuple_element<arg_count - 2, std::tuple<Args...>>::type>::value,
3257+ "The second last argument must be a function pointer");
3258+
3259+ SynchronousContext<decltype(callback)> wrapper_context {
3260+ callback,
3261+ false,
3262+ context
3263+ };
3264+
3265+ std::get<arg_count - 2>(arguments) = &synchronous_wrapper;
3266+ std::get<arg_count - 1>(arguments) =
3267+ reinterpret_cast<typename std::tuple_element<arg_count - 1, std::tuple<Args...>>::type>(&wrapper_context);
3268+
3269+ connection->process_next_request_first();
3270+ apply(std::forward<Callable>(function), arguments);
3271+
3272+ dispatch_connection_until(connection, [&wrapper_context](){ return wrapper_context.complete; });
3273+ }
3274+ else
3275+ {
3276+ mir_wait_for(std::forward<Callable>(function)(std::forward<Args>(args)...));
3277+ }
3278+}
3279+
3280+#endif // MIR_CLIENT_SYNCHRONOUS_H_
3281
3282=== added file 'src/common/dispatch/threaded_dispatcher.cpp.moved'
3283--- src/common/dispatch/threaded_dispatcher.cpp.moved 1970-01-01 00:00:00 +0000
3284+++ src/common/dispatch/threaded_dispatcher.cpp.moved 2017-03-28 00:17:49 +0000
3285@@ -0,0 +1,294 @@
3286+/*
3287+ * Copyright © 2015 Canonical Ltd.
3288+ *
3289+ * This program is free software: you can redistribute it and/or modify it
3290+ * under the terms of the GNU Lesser General Public License version 3,
3291+ * as published by the Free Software Foundation.
3292+ *
3293+ * This program is distributed in the hope that it will be useful,
3294+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
3295+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3296+ * GNU Lesser General Public License for more details.
3297+ *
3298+ * You should have received a copy of the GNU Lesser General Public License
3299+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
3300+ *
3301+ * Authored by: Christopher James Halse Rogers <christopher.halse.rogers@canonical.com>
3302+ */
3303+
3304+#include "mir/dispatch/threaded_dispatcher.h"
3305+#include "mir/dispatch/dispatchable.h"
3306+#include "mir/thread_name.h"
3307+
3308+#include "mir/raii.h"
3309+#include "mir/logging/logger.h"
3310+
3311+#include <fcntl.h>
3312+#include <poll.h>
3313+#include <unistd.h>
3314+#include <system_error>
3315+#include <signal.h>
3316+#include <boost/exception/all.hpp>
3317+#include <algorithm>
3318+#include <unordered_map>
3319+#include <sys/eventfd.h>
3320+
3321+namespace md = mir::dispatch;
3322+
3323+class md::ThreadedDispatcher::ThreadShutdownRequestHandler : public md::Dispatchable
3324+{
3325+public:
3326+ ThreadShutdownRequestHandler()
3327+ : event_semaphore{eventfd(0, EFD_CLOEXEC | EFD_SEMAPHORE)},
3328+ shutting_down{false}
3329+ {
3330+ if (event_semaphore == mir::Fd::invalid)
3331+ {
3332+ BOOST_THROW_EXCEPTION((std::system_error{errno,
3333+ std::system_category(),
3334+ "Failed to create shutdown eventfd"}));
3335+ }
3336+ }
3337+
3338+ mir::Fd watch_fd() const override
3339+ {
3340+ return event_semaphore;
3341+ }
3342+
3343+ bool dispatch(md::FdEvents events) override
3344+ {
3345+ if (events & md::FdEvent::error)
3346+ {
3347+ return false;
3348+ }
3349+
3350+ eventfd_t dummy;
3351+ if (eventfd_read(event_semaphore, &dummy) < 0)
3352+ {
3353+ BOOST_THROW_EXCEPTION((std::system_error{errno,
3354+ std::system_category(),
3355+ "Failed to clear shutdown notification"}));
3356+ }
3357+ std::lock_guard<decltype(running_flag_guard)> lock{running_flag_guard};
3358+ *running_flags.at(std::this_thread::get_id()) = false;
3359+
3360+ return true;
3361+ }
3362+
3363+ md::FdEvents relevant_events() const override
3364+ {
3365+ return md::FdEvent::readable;
3366+ }
3367+
3368+ std::thread::id terminate_one_thread()
3369+ {
3370+ // First we tell a thread to die, any thread...
3371+ if (eventfd_write(event_semaphore, 1) < 0)
3372+ {
3373+ BOOST_THROW_EXCEPTION((std::system_error{errno,
3374+ std::system_category(),
3375+ "Failed to trigger thread shutdown"}));
3376+ }
3377+
3378+ // ...now we wait for a thread to die and tell us its ID...
3379+ // We wait for a surprisingly long time because our threads are potentially blocked
3380+ // in client code that we don't control.
3381+ //
3382+ // If the client is entirely unresponsive for a whole minute, it deserves to die.
3383+ std::unique_lock<decltype(terminating_thread_mutex)> lock{terminating_thread_mutex};
3384+ if (!thread_terminating.wait_for (lock,
3385+ std::chrono::seconds{60},
3386+ [this]() { return !terminating_threads.empty(); }))
3387+ {
3388+ BOOST_THROW_EXCEPTION((std::runtime_error{"Thread failed to shutdown"}));
3389+ }
3390+
3391+ auto killed_thread_id = terminating_threads.back();
3392+ terminating_threads.pop_back();
3393+ return killed_thread_id;
3394+ }
3395+
3396+ void terminate_all_threads_async()
3397+ {
3398+ eventfd_t thread_count;
3399+ {
3400+ std::lock_guard<std::mutex> lock(running_flag_guard);
3401+ thread_count = running_flags.size();
3402+ shutting_down = true;
3403+ }
3404+ if (eventfd_write(event_semaphore, thread_count) < 0)
3405+ {
3406+ BOOST_THROW_EXCEPTION((std::system_error{errno,
3407+ std::system_category(),
3408+ "Failed to trigger thread shutdown"}));
3409+ }
3410+ }
3411+
3412+ void register_thread(bool& run_flag)
3413+ {
3414+ std::lock_guard<decltype(running_flag_guard)> lock{running_flag_guard};
3415+
3416+ running_flags[std::this_thread::get_id()] = &run_flag;
3417+ if (shutting_down)
3418+ {
3419+ if (eventfd_write(event_semaphore, 1) < 0)
3420+ {
3421+ BOOST_THROW_EXCEPTION((std::system_error{errno,
3422+ std::system_category(),
3423+ "Failed to trigger thread shutdown"}));
3424+ }
3425+ }
3426+ }
3427+
3428+ void unregister_thread()
3429+ {
3430+ {
3431+ std::lock_guard<decltype(terminating_thread_mutex)> lock{terminating_thread_mutex};
3432+ terminating_threads.push_back(std::this_thread::get_id());
3433+ }
3434+ thread_terminating.notify_one();
3435+ {
3436+ std::lock_guard<decltype(running_flag_guard)> lock{running_flag_guard};
3437+
3438+ if (running_flags.erase(std::this_thread::get_id()) != 1)
3439+ {
3440+ BOOST_THROW_EXCEPTION((std::logic_error{"Attempted to unregister a not-registered thread"}));
3441+ }
3442+ }
3443+ }
3444+
3445+private:
3446+ mir::Fd event_semaphore;
3447+
3448+ std::mutex terminating_thread_mutex;
3449+ std::condition_variable thread_terminating;
3450+ std::vector<std::thread::id> terminating_threads;
3451+
3452+ std::mutex running_flag_guard;
3453+ std::unordered_map<std::thread::id, bool*> running_flags;
3454+ bool shutting_down;
3455+};
3456+
3457+md::ThreadedDispatcher::ThreadedDispatcher(std::string const& name, std::shared_ptr<Dispatchable> const& dispatchee)
3458+ : ThreadedDispatcher(name, dispatchee, [](){ throw; })
3459+{
3460+}
3461+
3462+md::ThreadedDispatcher::ThreadedDispatcher(std::string const& name,
3463+ std::shared_ptr<md::Dispatchable> const& dispatchee,
3464+ std::function<void()> const& exception_handler)
3465+ : name_base{name},
3466+ thread_exiter{std::make_shared<ThreadShutdownRequestHandler>()},
3467+ dispatcher{std::make_shared<MultiplexingDispatchable>()},
3468+ exception_handler{exception_handler}
3469+{
3470+
3471+ // We rely on exactly one thread at a time getting a shutdown message
3472+ dispatcher->add_watch(thread_exiter, md::DispatchReentrancy::sequential);
3473+
3474+ // But our target dispatchable is welcome to be dispatched on as many threads
3475+ // as desired.
3476+ dispatcher->add_watch(dispatchee, md::DispatchReentrancy::reentrant);
3477+
3478+ threadpool.emplace_back(&dispatch_loop, name_base, thread_exiter, dispatcher, exception_handler);
3479+}
3480+
3481+md::ThreadedDispatcher::~ThreadedDispatcher() noexcept
3482+{
3483+ std::lock_guard<decltype(thread_pool_mutex)> lock{thread_pool_mutex};
3484+
3485+ thread_exiter->terminate_all_threads_async();
3486+
3487+ for (auto& thread : threadpool)
3488+ {
3489+ if (thread.get_id() == std::this_thread::get_id())
3490+ {
3491+ // We're being destroyed from within the dispatch callback
3492+ // Attempting to join the eventloop will result in a trivial deadlock.
3493+ //
3494+ // The std::thread destructor will call std::terminate() for us, let's
3495+ // leave a useful message.
3496+ mir::logging::log(mir::logging::Severity::critical,
3497+ "Destroying ThreadedDispatcher from within a dispatch callback. This is a programming error.",
3498+ "Dispatch");
3499+ }
3500+ else
3501+ {
3502+ thread.join();
3503+ }
3504+ }
3505+}
3506+
3507+void md::ThreadedDispatcher::add_thread()
3508+{
3509+ std::lock_guard<decltype(thread_pool_mutex)> lock{thread_pool_mutex};
3510+ threadpool.emplace_back(&dispatch_loop, name_base, thread_exiter, dispatcher, exception_handler);
3511+}
3512+
3513+void md::ThreadedDispatcher::remove_thread()
3514+{
3515+ auto terminated_thread_id = thread_exiter->terminate_one_thread();
3516+
3517+ // Find that thread in our vector, join() it, then remove it.
3518+ std::lock_guard<decltype(thread_pool_mutex)> threadpool_lock{thread_pool_mutex};
3519+
3520+ auto dying_thread = std::find_if(threadpool.begin(),
3521+ threadpool.end(),
3522+ [this, &terminated_thread_id](std::thread const& candidate)
3523+ {
3524+ return candidate.get_id() == terminated_thread_id;
3525+ });
3526+ dying_thread->join();
3527+ threadpool.erase(dying_thread);
3528+}
3529+
3530+void md::ThreadedDispatcher::dispatch_loop(std::string const& name,
3531+ std::shared_ptr<ThreadShutdownRequestHandler> thread_register,
3532+ std::shared_ptr<Dispatchable> dispatcher,
3533+ std::function<void()> const& exception_handler)
3534+{
3535+ sigset_t all_signals;
3536+ sigfillset(&all_signals);
3537+
3538+ if (auto error = pthread_sigmask(SIG_BLOCK, &all_signals, NULL))
3539+ BOOST_THROW_EXCEPTION((std::system_error{error,
3540+ std::system_category(),
3541+ "Failed to block signals on IO thread"}));
3542+
3543+ mir::set_thread_name(name);
3544+
3545+ // This does not have to be std::atomic<bool> because thread_register is guaranteed to
3546+ // only ever be dispatch()ed from one thread at a time.
3547+ bool running{true};
3548+
3549+ auto thread_registrar = mir::raii::paired_calls(
3550+ [&running, thread_register]()
3551+ {
3552+ thread_register->register_thread(running);
3553+ },
3554+ [thread_register]()
3555+ {
3556+ thread_register->unregister_thread();
3557+ });
3558+
3559+ try
3560+ {
3561+ struct pollfd waiter;
3562+ waiter.fd = dispatcher->watch_fd();
3563+ waiter.events = POLL_IN;
3564+ while (running)
3565+ {
3566+ if (poll(&waiter, 1, -1) < 0)
3567+ {
3568+ BOOST_THROW_EXCEPTION((std::system_error{errno,
3569+ std::system_category(),
3570+ "Failed to wait for event"}));
3571+ }
3572+ dispatcher->dispatch(md::FdEvent::readable);
3573+ }
3574+ }
3575+ catch(...)
3576+ {
3577+ exception_handler();
3578+ }
3579+}
3580
3581=== modified file 'src/include/client/mir/mir_render_surface.h'
3582--- src/include/client/mir/mir_render_surface.h 2017-03-10 19:47:57 +0000
3583+++ src/include/client/mir/mir_render_surface.h 2017-03-28 00:17:49 +0000
3584@@ -32,10 +32,13 @@
3585 virtual mir::geometry::Size size() const = 0;
3586 virtual void set_size(mir::geometry::Size) = 0;
3587 virtual bool valid() const = 0;
3588- virtual MirBufferStream* get_buffer_stream(
3589- int width, int height,
3590+ virtual void get_buffer_stream(
3591+ int width,
3592+ int height,
3593 MirPixelFormat format,
3594- MirBufferUsage buffer_usage) = 0;
3595+ MirBufferUsage buffer_usage,
3596+ mir_buffer_stream_callback callback,
3597+ void* context) = 0;
3598 virtual MirPresentationChain* get_presentation_chain() = 0;
3599 virtual char const* get_error_message() const = 0;
3600 virtual ~MirRenderSurface() = default;
3601
3602=== modified file 'src/server/scene/mediating_display_changer.cpp'
3603--- src/server/scene/mediating_display_changer.cpp 2017-03-13 08:12:52 +0000
3604+++ src/server/scene/mediating_display_changer.cpp 2017-03-28 00:17:49 +0000
3605@@ -336,7 +336,7 @@
3606 */
3607 previously_set_alarm = std::move(preview_configuration_timeout);
3608 preview_configuration_timeout = nullptr;
3609- currently_previewing_session = std::weak_ptr<frontend::Session>{};
3610+ currently_previewing_session = std::weak_ptr<frontend::Session>{} ;
3611 }
3612
3613 if (previously_set_alarm->cancel())
3614
3615=== modified file 'tests/acceptance-tests/CMakeLists.txt'
3616--- tests/acceptance-tests/CMakeLists.txt 2017-03-15 09:30:18 +0000
3617+++ tests/acceptance-tests/CMakeLists.txt 2017-03-28 00:17:49 +0000
3618@@ -1,5 +1,13 @@
3619 include(CMakeDependentOption)
3620
3621+<<<<<<< TREE
3622+=======
3623+include_directories(
3624+ ${CMAKE_SOURCE_DIR}
3625+ ${UMOCKDEV_INCLUDE_DIRS}
3626+)
3627+
3628+>>>>>>> MERGE-SOURCE
3629 set(
3630 SOURCES
3631
3632
3633=== modified file 'tests/acceptance-tests/test_client_library.cpp'
3634--- tests/acceptance-tests/test_client_library.cpp 2017-03-10 19:47:57 +0000
3635+++ tests/acceptance-tests/test_client_library.cpp 2017-03-28 00:17:49 +0000
3636@@ -20,9 +20,19 @@
3637
3638 #include "mir_test_framework/headless_in_process_server.h"
3639 #include "mir_test_framework/stub_platform_helpers.h"
3640+<<<<<<< TREE
3641+=======
3642+#include "mir_test_framework/using_stub_client_platform.h"
3643+#include "mir_test_framework/fake_input_device.h"
3644+#include "mir_test_framework/stub_server_platform_factory.h"
3645+>>>>>>> MERGE-SOURCE
3646 #include "mir_test_framework/any_surface.h"
3647+#include "mir/test/fd_utils.h"
3648+#include "mir/test/signal.h"
3649 #include "mir/test/validity_matchers.h"
3650+#include "mir/test/signal.h"
3651 #include "src/include/common/mir/protobuf/protocol_version.h"
3652+#include "mir/test/signal.h"
3653
3654 #include "mir_protobuf.pb.h"
3655
3656@@ -38,10 +48,16 @@
3657 #include <fcntl.h>
3658
3659 #include <errno.h>
3660+#include <mir/input/input_device_info.h>
3661+#include <mir/input/device_capability.h>
3662
3663 namespace mf = mir::frontend;
3664 namespace mc = mir::compositor;
3665 namespace mtf = mir_test_framework;
3666+namespace mt = mir::test;
3667+namespace mi = mir::input;
3668+namespace mis = mir::input::synthesis;
3669+
3670 namespace
3671 {
3672 #pragma GCC diagnostic push
3673@@ -1120,8 +1136,371 @@
3674 mir_connection_release(connection);
3675 }
3676
3677+<<<<<<< TREE
3678 #pragma GCC diagnostic push
3679 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
3680+=======
3681+namespace
3682+{
3683+struct ThreadTrackingCallbacks
3684+{
3685+ ThreadTrackingCallbacks()
3686+ : client_thread{pthread_self()}
3687+ {
3688+ }
3689+
3690+ static void connection_ready(MirConnection* /*connection*/, void* ctx)
3691+ {
3692+ auto data = reinterpret_cast<ThreadTrackingCallbacks*>(ctx);
3693+ EXPECT_EQ(pthread_self(), data->client_thread);
3694+ data->connection_ready_called.raise();
3695+ }
3696+
3697+ static void event_delegate(MirSurface* /*surf*/, MirEvent const* event, void* ctx)
3698+ {
3699+ auto data = reinterpret_cast<ThreadTrackingCallbacks*>(ctx);
3700+
3701+ EXPECT_THAT(pthread_self(), Eq(data->client_thread));
3702+ data->event_received.raise();
3703+ if (mir_event_get_type(event) == mir_event_type_input)
3704+ {
3705+ data->input_event_received.raise();
3706+ }
3707+ }
3708+
3709+ static void surface_created(MirSurface* surf, void* ctx)
3710+ {
3711+ auto data = reinterpret_cast<ThreadTrackingCallbacks*>(ctx);
3712+ EXPECT_THAT(pthread_self(), Eq(data->client_thread));
3713+ data->surf = surf;
3714+
3715+ mir_surface_set_event_handler(data->surf, &ThreadTrackingCallbacks::event_delegate, data);
3716+ }
3717+
3718+ static void swap_buffers_complete(MirBufferStream* /*stream*/, void* ctx)
3719+ {
3720+ auto data = reinterpret_cast<ThreadTrackingCallbacks*>(ctx);
3721+ EXPECT_EQ(pthread_self(), data->client_thread);
3722+ data->buffers_swapped.raise();
3723+ }
3724+
3725+ pthread_t const client_thread;
3726+ MirSurface* surf{nullptr};
3727+ mt::Signal buffers_swapped;
3728+ mt::Signal connection_ready_called;
3729+ mt::Signal event_received;
3730+ mt::Signal input_event_received;
3731+};
3732+
3733+void pump_eventloop_until(MirConnection* connection, std::function<bool()> predicate, std::chrono::steady_clock::time_point timeout)
3734+{
3735+ using namespace std::literals::chrono_literals;
3736+
3737+ auto fd = mir::Fd{mir::IntOwnedFd{mir_connection_get_event_fd(connection)}};
3738+
3739+ while (!predicate() && (std::chrono::steady_clock::now() < timeout))
3740+ {
3741+ if (mt::fd_becomes_readable(fd, 10ms))
3742+ {
3743+ mir_connection_dispatch(connection);
3744+ }
3745+ }
3746+ if (!predicate())
3747+ {
3748+ BOOST_THROW_EXCEPTION((std::runtime_error{"Timeout waiting for state change"}));
3749+ }
3750+}
3751+}
3752+
3753+TEST_F(ClientLibrary, manual_dispatch_handles_callbacks_in_parent_thread)
3754+{
3755+ using namespace std::literals::chrono_literals;
3756+
3757+ auto const test_timeout = std::chrono::steady_clock::now() + 10min;
3758+
3759+ ThreadTrackingCallbacks data;
3760+
3761+ auto connection = mir_connect_with_manual_dispatch(new_connection().c_str(), __PRETTY_FUNCTION__, &ThreadTrackingCallbacks::connection_ready, &data);
3762+
3763+ ASSERT_THAT(connection, Ne(nullptr));
3764+
3765+ pump_eventloop_until(
3766+ connection,
3767+ [&data]()
3768+ {
3769+ return data.connection_ready_called.raised();
3770+ },
3771+ test_timeout);
3772+
3773+ ASSERT_THAT(connection, IsValid());
3774+
3775+ auto surface_spec = mir_connection_create_spec_for_normal_surface(connection,
3776+ 233, 355,
3777+ mir_pixel_format_argb_8888);
3778+ auto surf_wh = mir_surface_create(surface_spec,
3779+ &ThreadTrackingCallbacks::surface_created,
3780+ &data);
3781+ mir_surface_spec_release(surface_spec);
3782+
3783+ pump_eventloop_until(
3784+ connection,
3785+ [surf_wh]()
3786+ {
3787+ return mir_wait_handle_ready(surf_wh);
3788+ },
3789+ test_timeout);
3790+
3791+ EXPECT_THAT(data.surf, IsValid());
3792+
3793+ auto buffer_stream = mir_surface_get_buffer_stream(data.surf);
3794+ auto swap_wh = mir_buffer_stream_swap_buffers(buffer_stream, ThreadTrackingCallbacks::swap_buffers_complete, &data);
3795+
3796+ pump_eventloop_until(
3797+ connection,
3798+ [swap_wh]()
3799+ {
3800+ return mir_wait_handle_ready(swap_wh);
3801+ },
3802+ test_timeout);
3803+ EXPECT_TRUE(data.buffers_swapped.raised());
3804+
3805+ mir_surface_release_sync(data.surf);
3806+ mir_connection_release(connection);
3807+}
3808+
3809+TEST_F(ClientLibrary, manual_dispatch_handles_events_in_parent_thread)
3810+{
3811+ using namespace testing;
3812+ using namespace std::literals::chrono_literals;
3813+
3814+ auto const test_timeout = std::chrono::steady_clock::now() + 10min;
3815+
3816+ auto fake_keyboard = mtf::add_fake_input_device(
3817+ mi::InputDeviceInfo{"keyboard", "keyboard-unique-id", mi::DeviceCapability::keyboard});
3818+
3819+ ThreadTrackingCallbacks data;
3820+
3821+ connection = mir_connect_with_manual_dispatch(new_connection().c_str(), __PRETTY_FUNCTION__, &ThreadTrackingCallbacks::connection_ready, &data);
3822+
3823+ ASSERT_THAT(connection, Ne(nullptr));
3824+
3825+ pump_eventloop_until(
3826+ connection,
3827+ [&data]()
3828+ {
3829+ return data.connection_ready_called.raised();
3830+ },
3831+ test_timeout);
3832+
3833+ ASSERT_THAT(connection, IsValid());
3834+
3835+ auto surface_spec = mir_connection_create_spec_for_normal_surface(connection,
3836+ 233, 355,
3837+ mir_pixel_format_argb_8888);
3838+ auto surf_wh = mir_surface_create(surface_spec,
3839+ &ThreadTrackingCallbacks::surface_created,
3840+ &data);
3841+ mir_surface_spec_release(surface_spec);
3842+
3843+
3844+ pump_eventloop_until(
3845+ connection,
3846+ [surf_wh]()
3847+ {
3848+ return mir_wait_handle_ready(surf_wh);
3849+ },
3850+ test_timeout);
3851+
3852+ EXPECT_THAT(data.surf, IsValid());
3853+
3854+ // We need to swap buffers so that the surface is fully realised and
3855+ // will be a valid focus target.
3856+ //
3857+ // The shell will not focus a surface with no content.
3858+ auto buffer_stream = mir_surface_get_buffer_stream(data.surf);
3859+ mir_buffer_stream_swap_buffers_sync(buffer_stream);
3860+
3861+ pump_eventloop_until(
3862+ connection,
3863+ [&data]()
3864+ {
3865+ return mir_surface_get_focus(data.surf) == mir_surface_focused;
3866+ },
3867+ test_timeout);
3868+
3869+ ASSERT_THAT(mir_surface_get_focus(data.surf), Eq(mir_surface_focused));
3870+
3871+ fake_keyboard->emit_event(mis::a_key_down_event());
3872+
3873+ pump_eventloop_until(
3874+ connection,
3875+ [&data]()
3876+ {
3877+ return data.input_event_received.raised();
3878+ },
3879+ test_timeout);
3880+
3881+ mir_surface_release_sync(data.surf);
3882+ mir_connection_release(connection);
3883+}
3884+
3885+namespace
3886+{
3887+struct SignalData
3888+{
3889+ mir::test::Signal focus_received;
3890+ mir::test::Signal now_blocking;
3891+ mir::test::Signal event_received;
3892+ mir::test::Signal buffer_stream_destroyed;
3893+};
3894+
3895+void notifying_event_handler(MirSurface*, MirEvent const* ev, void* ctx)
3896+{
3897+ auto signals = *reinterpret_cast<std::shared_ptr<SignalData>*>(ctx);
3898+ // We trigger an input event once we've noticed the surface callback is blocking
3899+ // so we need to only raise the flag on an input event; otherwise we may spuriously
3900+ // fail if we receive a surface event (like the focus event) before we hit
3901+ // the wait in blocking_surface_callback()
3902+ if (mir_event_get_type(ev) == mir_event_type_input)
3903+ {
3904+ signals->event_received.raise();
3905+ }
3906+ if (mir_event_get_type(ev) == mir_event_type_surface)
3907+ {
3908+ auto surface_event = mir_event_get_surface_event(ev);
3909+ if (mir_surface_event_get_attribute(surface_event) == mir_surface_attrib_focus &&
3910+ mir_surface_event_get_attribute_value(surface_event) == mir_surface_focused)
3911+ {
3912+ signals->focus_received.raise();
3913+ }
3914+ }
3915+}
3916+
3917+void notify_buffer_stream_destroyed(MirBufferStream*, void* ctx)
3918+{
3919+ auto& signal = *reinterpret_cast<mt::Signal*>(ctx);
3920+ signal.raise();
3921+}
3922+
3923+void blocking_buffer_stream_callback(MirBufferStream* stream, void* ctx)
3924+{
3925+ auto signals = *reinterpret_cast<std::shared_ptr<SignalData>*>(ctx);
3926+ signals->now_blocking.raise();
3927+ EXPECT_TRUE(signals->event_received.wait_for(std::chrono::seconds{5}));
3928+ mir_buffer_stream_release(stream, &notify_buffer_stream_destroyed, &signals->buffer_stream_destroyed);
3929+}
3930+}
3931+
3932+TEST_F(ClientLibrary, rpc_blocking_doesnt_block_event_delivery_with_auto_dispatch)
3933+{
3934+ using namespace testing;
3935+
3936+ connection = mir_connect_sync(new_connection().c_str(), __PRETTY_FUNCTION__);
3937+
3938+ auto fake_keyboard = mtf::add_fake_input_device(
3939+ mi::InputDeviceInfo{"keyboard", "keyboard-unique-id", mi::DeviceCapability::keyboard});
3940+
3941+
3942+ ASSERT_THAT(connection, IsValid());
3943+ auto signals = std::make_shared<SignalData>();
3944+
3945+ auto surface_spec = mir_connection_create_spec_for_normal_surface(connection,
3946+ 233, 355,
3947+ mir_pixel_format_argb_8888);
3948+ mir_surface_spec_set_event_handler(surface_spec, &notifying_event_handler, &signals);
3949+
3950+ auto surf = mir_surface_create_sync(surface_spec);
3951+ mir_surface_spec_release(surface_spec);
3952+
3953+ ASSERT_THAT(surf, IsValid());
3954+
3955+ auto buffer_stream = mir_surface_get_buffer_stream(surf);
3956+
3957+ // Ensure that the surface is focused.
3958+ mir_buffer_stream_swap_buffers_sync(buffer_stream);
3959+ ASSERT_TRUE(signals->focus_received.wait_for(std::chrono::seconds{5}));
3960+
3961+ auto wh = mir_connection_create_buffer_stream(
3962+ connection,
3963+ 800, 600,
3964+ mir_pixel_format_abgr_8888,
3965+ mir_buffer_usage_software,
3966+ &blocking_buffer_stream_callback, &signals);
3967+
3968+ EXPECT_TRUE(signals->now_blocking.wait_for(std::chrono::seconds{5}));
3969+ EXPECT_FALSE(signals->event_received.raised());
3970+
3971+ fake_keyboard->emit_event(mis::a_key_down_event());
3972+
3973+ EXPECT_TRUE(signals->event_received.wait_for(std::chrono::seconds{5}));
3974+ EXPECT_TRUE(signals->buffer_stream_destroyed.wait_for(std::chrono::seconds{5}));
3975+
3976+ mir_wait_for(wh);
3977+ mir_surface_release_sync(surf);
3978+ mir_connection_release(connection);
3979+}
3980+
3981+namespace
3982+{
3983+void async_release_completed(MirSurface*, void* ctx)
3984+{
3985+ auto called = reinterpret_cast<bool*>(ctx);
3986+ *called = true;
3987+}
3988+
3989+void async_creation_completed(MirSurface* surf, void* ctx)
3990+{
3991+ mir_surface_release(surf, &async_release_completed, ctx);
3992+}
3993+}
3994+
3995+TEST_F(ClientLibrary, sync_call_completes_before_previous_undispatched_call)
3996+{
3997+ using namespace std::literals::chrono_literals;
3998+ using namespace testing;
3999+
4000+ auto timeout = std::chrono::steady_clock::now() + 60s;
4001+
4002+ ThreadTrackingCallbacks data;
4003+
4004+ auto connection = mir_connect_with_manual_dispatch(new_connection().c_str(), __PRETTY_FUNCTION__, &ThreadTrackingCallbacks::connection_ready, &data);
4005+ ASSERT_THAT(connection, Ne(nullptr));
4006+
4007+ pump_eventloop_until(connection, [connection]() { return mir_connection_is_valid(connection); }, timeout);
4008+
4009+ bool async_call_completed{false};
4010+
4011+ auto surface_spec = mir_connection_create_spec_for_normal_surface(connection,
4012+ 233, 355,
4013+ mir_pixel_format_argb_8888);
4014+ mir_surface_create(surface_spec, &async_creation_completed, &async_call_completed);
4015+
4016+ EXPECT_FALSE(async_call_completed);
4017+ auto surf = mir_surface_create_sync(surface_spec);
4018+ mir_surface_spec_release(surface_spec);
4019+
4020+ EXPECT_THAT(surf, IsValid());
4021+ EXPECT_FALSE(async_call_completed);
4022+
4023+ mir_surface_release_sync(surf);
4024+ EXPECT_FALSE(async_call_completed);
4025+
4026+ pump_eventloop_until(connection, [&async_call_completed]() { return async_call_completed;}, timeout);
4027+
4028+}
4029+
4030+TEST_F(ClientLibrary, can_connect_synchronously_with_manual_dispatch)
4031+{
4032+ using namespace testing;
4033+
4034+ auto connection = mir_connect_with_manual_dispatch_sync(new_connection().c_str(), __PRETTY_FUNCTION__);
4035+
4036+ EXPECT_THAT(connection, IsValid());
4037+
4038+ mir_connection_release(connection);
4039+}
4040+
4041+>>>>>>> MERGE-SOURCE
4042 TEST_F(ClientLibrary, can_get_persistent_surface_id)
4043 {
4044 auto connection = mir_connect_sync(new_connection().c_str(), __PRETTY_FUNCTION__);
4045@@ -1225,6 +1604,7 @@
4046 mir_buffer_stream_release_sync(stream);
4047 mir_connection_release(connection);
4048 }
4049+<<<<<<< TREE
4050
4051 TEST_F(ClientLibrary, client_api_version)
4052 {
4053@@ -1232,3 +1612,117 @@
4054 MIR_CLIENT_API_VERSION_MINOR,
4055 MIR_CLIENT_API_VERSION_PATCH) == mir_get_client_api_version());
4056 }
4057+=======
4058+
4059+TEST_F(ClientLibrary, synchronously_creating_buffer_stream_results_in_valid_buffer_stream)
4060+{
4061+ using namespace testing;
4062+
4063+ auto connection = mir_connect_with_manual_dispatch_sync(new_connection().c_str(), __PRETTY_FUNCTION__);
4064+
4065+ ASSERT_THAT(connection, IsValid());
4066+
4067+ int const width{640}, height{480};
4068+ auto stream = mir_connection_create_buffer_stream_sync(
4069+ connection,
4070+ width, height,
4071+ mir_pixel_format_abgr_8888,
4072+ mir_buffer_usage_software);
4073+
4074+ EXPECT_THAT(stream, IsValid());
4075+
4076+ MirGraphicsRegion region;
4077+ mir_buffer_stream_get_graphics_region(stream, &region);
4078+
4079+ EXPECT_THAT(region.vaddr, NotNull());
4080+ EXPECT_THAT(region.width, Eq(width));
4081+ EXPECT_THAT(region.height, Eq(height));
4082+ EXPECT_THAT(region.stride, Ge(width));
4083+ EXPECT_THAT(region.pixel_format, Eq(mir_pixel_format_abgr_8888));
4084+
4085+ mir_buffer_stream_release_sync(stream);
4086+ mir_connection_release(connection);
4087+}
4088+
4089+TEST_F(ClientLibrary, default_surface_stream_is_valid_in_created_callback)
4090+{
4091+ connection = mir_connect_sync(new_connection().c_str(), __PRETTY_FUNCTION__);
4092+ ASSERT_TRUE(mir_connection_is_valid(connection));
4093+
4094+ auto surface_spec = mir_connection_create_spec_for_normal_surface(
4095+ connection,
4096+ 800, 600,
4097+ mir_pixel_format_argb_8888);
4098+
4099+ mt::Signal done;
4100+
4101+ mir_surface_create(
4102+ surface_spec,
4103+ [](MirSurface* surf, void* ctx)
4104+ {
4105+ auto stream = mir_surface_get_buffer_stream(surf);
4106+ EXPECT_THAT(stream, NotNull());
4107+ EXPECT_TRUE(mir_buffer_stream_is_valid(stream));
4108+
4109+ MirNativeBuffer* package;
4110+ mir_buffer_stream_get_current_buffer(stream, &package);
4111+
4112+ EXPECT_THAT(package, NotNull());
4113+
4114+ mir_surface_release(
4115+ surf,
4116+ [](MirSurface*, void* ctx)
4117+ {
4118+ auto done = reinterpret_cast<mt::Signal*>(ctx);
4119+
4120+ done->raise();
4121+ },
4122+ ctx);
4123+ },
4124+ &done);
4125+ mir_surface_spec_release(surface_spec);
4126+
4127+ // ASSERT_TRUE rather than EXPECT_TRUE so that the test dies on client deadlock.
4128+ ASSERT_TRUE(done.wait_for(std::chrono::seconds{20}));
4129+
4130+ mir_connection_release(connection);
4131+}
4132+
4133+TEST_F(ClientLibrary, buffer_stream_is_valid_in_created_callback)
4134+{
4135+ connection = mir_connect_sync(new_connection().c_str(), __PRETTY_FUNCTION__);
4136+ ASSERT_TRUE(mir_connection_is_valid(connection));
4137+
4138+ mt::Signal done;
4139+
4140+ mir_connection_create_buffer_stream(
4141+ connection,
4142+ 800, 600,
4143+ mir_pixel_format_argb_8888,
4144+ mir_buffer_usage_software,
4145+ [](MirBufferStream* stream, void* ctx)
4146+ {
4147+ EXPECT_THAT(stream, IsValid());
4148+
4149+ MirNativeBuffer* package;
4150+ mir_buffer_stream_get_current_buffer(stream, &package);
4151+
4152+ EXPECT_THAT(package, NotNull());
4153+
4154+ mir_buffer_stream_release(
4155+ stream,
4156+ [](MirBufferStream*, void* ctx)
4157+ {
4158+ auto done = reinterpret_cast<mt::Signal*>(ctx);
4159+
4160+ done->raise();
4161+ },
4162+ ctx);
4163+ },
4164+ &done);
4165+
4166+ ASSERT_TRUE(done.wait_for(std::chrono::seconds{20}));
4167+
4168+ mir_connection_release(connection);
4169+}
4170+>>>>>>> MERGE-SOURCE
4171
4172=== modified file 'tests/acceptance-tests/test_client_surfaces.cpp'
4173--- tests/acceptance-tests/test_client_surfaces.cpp 2017-03-14 04:41:33 +0000
4174+++ tests/acceptance-tests/test_client_surfaces.cpp 2017-03-28 00:17:49 +0000
4175@@ -28,6 +28,7 @@
4176 #include "mir_test_framework/any_surface.h"
4177 #include "mir/test/validity_matchers.h"
4178 #include "mir/test/fake_shared.h"
4179+#include "mir/test/signal.h"
4180
4181 #include <gmock/gmock.h>
4182 #include <gtest/gtest.h>
4183@@ -391,4 +392,43 @@
4184
4185 mir_connection_release(im_connection);
4186 }
4187+<<<<<<< TREE
4188 #pragma GCC diagnostic pop
4189+=======
4190+
4191+TEST_F(ClientSurfaces, default_buffer_stream_is_fully_constructed_in_surface_created_callback)
4192+{
4193+ using namespace testing;
4194+ using namespace std::chrono_literals;
4195+
4196+ auto surface_spec = mir_connection_create_spec_for_normal_surface(
4197+ connection,
4198+ 800, 600,
4199+ mir_pixel_format_argb_8888);
4200+
4201+ mt::Signal surface_released;
4202+ mir_surface_create(
4203+ surface_spec,
4204+ [](MirSurface* surf, void* ctx)
4205+ {
4206+ EXPECT_THAT(surf, IsValid());
4207+ auto buffer_stream = mir_surface_get_buffer_stream(surf);
4208+ MirGraphicsRegion region;
4209+ mir_buffer_stream_get_graphics_region(buffer_stream, &region);
4210+ EXPECT_THAT(region.vaddr, NotNull());
4211+
4212+ mir_surface_release(
4213+ surf,
4214+ [](MirSurface*, void* ctx)
4215+ {
4216+ auto& done = *reinterpret_cast<mt::Signal*>(ctx);
4217+ done.raise();
4218+ },
4219+ ctx);
4220+ },
4221+ &surface_released);
4222+ mir_surface_spec_release(surface_spec);
4223+
4224+ EXPECT_TRUE(surface_released.wait_for(10s));
4225+}
4226+>>>>>>> MERGE-SOURCE
4227
4228=== modified file 'tests/acceptance-tests/test_render_surface.cpp'
4229--- tests/acceptance-tests/test_render_surface.cpp 2017-03-10 19:47:57 +0000
4230+++ tests/acceptance-tests/test_render_surface.cpp 2017-03-28 00:17:49 +0000
4231@@ -23,11 +23,14 @@
4232 #include "mir/geometry/size.h"
4233 #include "mir_test_framework/headless_in_process_server.h"
4234 #include "mir/test/validity_matchers.h"
4235+#include "mir/test/signal.h"
4236
4237 #include <gtest/gtest.h>
4238 #include <gmock/gmock.h>
4239+#include "mir/test/signal.h"
4240
4241 namespace mtf = mir_test_framework;
4242+namespace mt = mir::test;
4243 namespace geom = mir::geometry;
4244
4245 namespace
4246@@ -54,7 +57,7 @@
4247 EXPECT_TRUE(mir_render_surface_is_valid(rs));
4248 EXPECT_THAT(mir_render_surface_get_error_message(rs), StrEq(""));
4249
4250- mir_render_surface_release(rs);
4251+ mir_render_surface_release_sync(rs);
4252 mir_connection_release(connection);
4253 }
4254
4255@@ -73,9 +76,13 @@
4256 return {width, height};
4257 };
4258 auto physical_size = determine_physical_size(rs);
4259- auto bs = mir_render_surface_get_buffer_stream(
4260+
4261+ mt::Signal done;
4262+
4263+ mir_render_surface_get_buffer_stream(
4264 rs,
4265 physical_size.width.as_int(), physical_size.height.as_int(),
4266+<<<<<<< TREE
4267 mir_pixel_format_abgr_8888);
4268
4269 ASSERT_THAT(bs, NotNull());
4270@@ -83,6 +90,22 @@
4271 EXPECT_THAT(mir_buffer_stream_get_error_message(bs), StrEq(""));
4272
4273 mir_render_surface_release(rs);
4274+=======
4275+ mir_pixel_format_abgr_8888,
4276+ mir_buffer_usage_hardware,
4277+ [](MirBufferStream* bs, void* ctx)
4278+ {
4279+ ASSERT_THAT(bs, NotNull());
4280+ EXPECT_THAT(bs, IsValid());
4281+
4282+ reinterpret_cast<mt::Signal*>(ctx)->raise();
4283+ },
4284+ &done);
4285+
4286+ ASSERT_TRUE(done.wait_for(std::chrono::seconds{20}));
4287+
4288+ mir_render_surface_release_sync(rs);
4289+>>>>>>> MERGE-SOURCE
4290 mir_connection_release(connection);
4291 }
4292
4293@@ -94,23 +117,21 @@
4294 auto rs = mir_connection_create_render_surface_sync(
4295 connection, logical_size.width.as_int(), logical_size.height.as_int());
4296
4297- auto bs = mir_render_surface_get_buffer_stream(
4298+ auto bs = mir_render_surface_get_buffer_stream_sync(
4299 rs,
4300 physical_size.width.as_int(), physical_size.height.as_int(),
4301 mir_pixel_format_abgr_8888);
4302
4303- ASSERT_THAT(bs, NotNull());
4304- EXPECT_TRUE(mir_buffer_stream_is_valid(bs));
4305- EXPECT_THAT(mir_buffer_stream_get_error_message(bs), StrEq(""));
4306+ EXPECT_THAT(bs, IsValid());
4307
4308- auto bs2 = mir_render_surface_get_buffer_stream(
4309+ auto bs2 = mir_render_surface_get_buffer_stream_sync(
4310 rs,
4311 physical_size.width.as_int(), physical_size.height.as_int(),
4312 mir_pixel_format_abgr_8888);
4313
4314 EXPECT_THAT(bs2, Eq(nullptr));
4315
4316- mir_render_surface_release(rs);
4317+ mir_render_surface_release_sync(rs);
4318 mir_connection_release(connection);
4319 }
4320
4321@@ -121,9 +142,13 @@
4322
4323 auto rs = mir_connection_create_render_surface_sync(
4324 connection, logical_size.width.as_int(), logical_size.height.as_int());
4325- auto bs = mir_render_surface_get_buffer_stream(
4326+
4327+ mt::Signal done;
4328+
4329+ mir_render_surface_get_buffer_stream(
4330 rs,
4331 physical_size.width.as_int(), physical_size.height.as_int(),
4332+<<<<<<< TREE
4333 mir_pixel_format_abgr_8888);
4334
4335 ASSERT_THAT(bs, NotNull());
4336@@ -131,6 +156,22 @@
4337 EXPECT_THAT(mir_buffer_stream_get_error_message(bs), StrEq(""));
4338
4339 mir_render_surface_release(rs);
4340+=======
4341+ mir_pixel_format_abgr_8888,
4342+ mir_buffer_usage_hardware,
4343+ [](MirBufferStream* bs, void* ctx)
4344+ {
4345+ ASSERT_THAT(bs, NotNull());
4346+ EXPECT_THAT(bs, IsValid());
4347+
4348+ reinterpret_cast<mt::Signal*>(ctx)->raise();
4349+ },
4350+ &done);
4351+
4352+ ASSERT_TRUE(done.wait_for(std::chrono::seconds{20}));
4353+
4354+ mir_render_surface_release_sync(rs);
4355+>>>>>>> MERGE-SOURCE
4356 mir_connection_release(connection);
4357 }
4358
4359@@ -152,8 +193,13 @@
4360 EXPECT_THAT(window, IsValid());
4361 EXPECT_THAT(mir_window_get_buffer_stream(window), Eq(nullptr));
4362
4363+<<<<<<< TREE
4364 mir_render_surface_release(rs);
4365 mir_window_release_sync(window);
4366+=======
4367+ mir_render_surface_release_sync(rs);
4368+ mir_surface_release_sync(surface);
4369+>>>>>>> MERGE-SOURCE
4370 mir_connection_release(connection);
4371 }
4372
4373@@ -166,19 +212,55 @@
4374
4375 auto rs = mir_connection_create_render_surface_sync(
4376 connection, logical_size.width.as_int(), logical_size.height.as_int());
4377+<<<<<<< TREE
4378 auto spec = mir_create_normal_window_spec(connection, width, height);
4379 mir_window_spec_set_pixel_format(spec, format);
4380 mir_window_spec_add_render_surface(spec, rs, width, height, 0, 0);
4381 auto window = mir_create_window_sync(spec);
4382 mir_window_spec_release(spec);
4383 auto bs = mir_render_surface_get_buffer_stream(rs, 640, 480, format);
4384-
4385+=======
4386+ auto spec = mir_connection_create_spec_for_normal_surface(connection,
4387+ width, height,
4388+ format);
4389+ mir_surface_spec_add_render_surface(spec, rs, width, height, 0, 0);
4390+ auto surface = mir_surface_create_sync(spec);
4391+ mir_surface_spec_release(spec);
4392+ mt::Signal done;
4393+
4394+ mir_render_surface_get_buffer_stream(
4395+ rs,
4396+ 640, 480,
4397+ format,
4398+ usage,
4399+ [](MirBufferStream* bs, void* ctx)
4400+ {
4401+ ASSERT_THAT(bs, NotNull());
4402+ EXPECT_THAT(bs, IsValid());
4403+
4404+ reinterpret_cast<mt::Signal*>(ctx)->raise();
4405+ },
4406+ &done);
4407+
4408+>>>>>>> MERGE-SOURCE
4409+
4410+<<<<<<< TREE
4411 EXPECT_THAT(window, IsValid());
4412 EXPECT_THAT(mir_window_get_buffer_stream(window), Eq(nullptr));
4413 EXPECT_TRUE(mir_buffer_stream_is_valid(bs));
4414
4415 mir_render_surface_release(rs);
4416 mir_window_release_sync(window);
4417+=======
4418+ EXPECT_THAT(surface, IsValid());
4419+
4420+ EXPECT_THAT(mir_surface_get_buffer_stream(surface), Eq(nullptr));
4421+
4422+ ASSERT_TRUE(done.wait_for(std::chrono::seconds{20}));
4423+
4424+ mir_render_surface_release_sync(rs);
4425+ mir_surface_release_sync(surface);
4426+>>>>>>> MERGE-SOURCE
4427 mir_connection_release(connection);
4428 }
4429
4430@@ -194,7 +276,7 @@
4431 ASSERT_THAT(pc, NotNull());
4432 EXPECT_TRUE(mir_presentation_chain_is_valid(pc));
4433
4434- mir_render_surface_release(rs);
4435+ mir_render_surface_release_sync(rs);
4436 mir_connection_release(connection);
4437 }
4438
4439@@ -214,7 +296,7 @@
4440
4441 EXPECT_THAT(pc2, Eq(nullptr));
4442
4443- mir_render_surface_release(rs);
4444+ mir_render_surface_release_sync(rs);
4445 mir_connection_release(connection);
4446 }
4447
4448@@ -238,8 +320,13 @@
4449 EXPECT_THAT(mir_window_get_buffer_stream(window), Eq(nullptr));
4450 EXPECT_TRUE(mir_presentation_chain_is_valid(pc));
4451
4452+<<<<<<< TREE
4453 mir_render_surface_release(rs);
4454 mir_window_release_sync(window);
4455+=======
4456+ mir_render_surface_release_sync(rs);
4457+ mir_surface_release_sync(surface);
4458+>>>>>>> MERGE-SOURCE
4459 mir_connection_release(connection);
4460 }
4461
4462@@ -254,7 +341,7 @@
4463 ASSERT_THAT(pc, NotNull());
4464 EXPECT_TRUE(mir_presentation_chain_is_valid(pc));
4465
4466- mir_render_surface_release(rs);
4467+ mir_render_surface_release_sync(rs);
4468 mir_connection_release(connection);
4469 }
4470
4471@@ -270,14 +357,14 @@
4472 ASSERT_THAT(pc, NotNull());
4473 EXPECT_TRUE(mir_presentation_chain_is_valid(pc));
4474
4475- auto bs = mir_render_surface_get_buffer_stream(
4476+ auto bs = mir_render_surface_get_buffer_stream_sync(
4477 rs,
4478 physical_size.width.as_int(), physical_size.height.as_int(),
4479 mir_pixel_format_abgr_8888);
4480
4481 EXPECT_THAT(bs, Eq(nullptr));
4482
4483- mir_render_surface_release(rs);
4484+ mir_render_surface_release_sync(rs);
4485 mir_connection_release(connection);
4486 }
4487
4488@@ -288,20 +375,148 @@
4489
4490 auto rs = mir_connection_create_render_surface_sync(
4491 connection, logical_size.width.as_int(), logical_size.height.as_int());
4492- auto bs = mir_render_surface_get_buffer_stream(
4493+ auto bs = mir_render_surface_get_buffer_stream_sync(
4494 rs,
4495 physical_size.width.as_int(), physical_size.height.as_int(),
4496 mir_pixel_format_abgr_8888);
4497
4498- ASSERT_THAT(bs, NotNull());
4499- EXPECT_TRUE(mir_buffer_stream_is_valid(bs));
4500+ EXPECT_THAT(bs, IsValid());
4501
4502 auto pc = mir_render_surface_get_presentation_chain(rs);
4503
4504 EXPECT_THAT(pc, Eq(nullptr));
4505
4506- mir_render_surface_release(rs);
4507- mir_connection_release(connection);
4508+ mir_render_surface_release_sync(rs);
4509+ mir_connection_release(connection);
4510+}
4511+
4512+TEST_F(RenderSurfaceTest, asynchronous_render_surface_destruction_works_with_realised_buffer_stream)
4513+{
4514+ auto physical_size = logical_size;
4515+ auto connection = mir_connect_sync(new_connection().c_str(), __PRETTY_FUNCTION__);
4516+
4517+ auto rs = mir_connection_create_render_surface_sync(
4518+ connection, logical_size.width.as_int(), logical_size.height.as_int());
4519+ mir_render_surface_get_buffer_stream_sync(
4520+ rs,
4521+ physical_size.width.as_int(), physical_size.height.as_int(),
4522+ mir_pixel_format_abgr_8888,
4523+ mir_buffer_usage_hardware);
4524+
4525+ struct Context
4526+ {
4527+ MirRenderSurface* rs;
4528+ mt::Signal done;
4529+ } context;
4530+
4531+ context.rs = rs;
4532+
4533+ mir_render_surface_release(
4534+ rs,
4535+ [](MirRenderSurface* rs, void* ctx)
4536+ {
4537+ auto& context = *reinterpret_cast<Context*>(ctx);
4538+ EXPECT_THAT(rs, Eq(context.rs));
4539+ /*
4540+ * Should really test that the render surface isn't valid here, but that fails.
4541+ *
4542+ EXPECT_THAT(rs, Not(IsValid()));
4543+ */
4544+ context.done.raise();
4545+ },
4546+ &context);
4547+
4548+ ASSERT_TRUE(context.done.wait_for(std::chrono::seconds{20}));
4549+
4550+ mir_connection_release(connection);
4551+}
4552+
4553+TEST_F(RenderSurfaceTest, asynchronous_render_surface_destruction_works_with_realised_presentation_chain)
4554+{
4555+ auto connection = mir_connect_sync(new_connection().c_str(), __PRETTY_FUNCTION__);
4556+
4557+ auto rs = mir_connection_create_render_surface_sync(
4558+ connection, logical_size.width.as_int(), logical_size.height.as_int());
4559+ mir_render_surface_get_presentation_chain(rs);
4560+
4561+ struct Context
4562+ {
4563+ MirRenderSurface* rs;
4564+ mt::Signal done;
4565+ } context;
4566+
4567+ context.rs = rs;
4568+
4569+ mir_render_surface_release(
4570+ rs,
4571+ [](MirRenderSurface* rs, void* ctx)
4572+ {
4573+ auto& context = *reinterpret_cast<Context*>(ctx);
4574+ EXPECT_THAT(rs, Eq(context.rs));
4575+ /*
4576+ * Should really test that the render surface isn't valid here, but that fails.
4577+ *
4578+ EXPECT_THAT(rs, Not(IsValid()));
4579+ */
4580+ context.done.raise();
4581+ },
4582+ &context);
4583+
4584+ ASSERT_TRUE(context.done.wait_for(std::chrono::seconds{20}));
4585+
4586+ mir_connection_release(connection);
4587+}
4588+
4589+TEST_F(RenderSurfaceTest, asynchronous_render_surface_destruction_works_with_no_backing_object)
4590+{
4591+ auto connection = mir_connect_sync(new_connection().c_str(), __PRETTY_FUNCTION__);
4592+
4593+ auto rs = mir_connection_create_render_surface_sync(
4594+ connection, logical_size.width.as_int(), logical_size.height.as_int());
4595+
4596+ struct Context
4597+ {
4598+ MirRenderSurface* rs;
4599+ mt::Signal done;
4600+ } context;
4601+
4602+ context.rs = rs;
4603+
4604+ mir_render_surface_release(
4605+ rs,
4606+ [](MirRenderSurface* rs, void* ctx)
4607+ {
4608+ auto& context = *reinterpret_cast<Context*>(ctx);
4609+ EXPECT_THAT(rs, Eq(context.rs));
4610+ /*
4611+ * Should really test that the render surface isn't valid here, but that fails.
4612+ *
4613+ EXPECT_THAT(rs, Not(IsValid()));
4614+ */
4615+ context.done.raise();
4616+ },
4617+ &context);
4618+
4619+ ASSERT_TRUE(context.done.wait_for(std::chrono::seconds{20}));
4620+
4621+ mir_connection_release(connection);
4622+}
4623+
4624+TEST_F(RenderSurfaceTest, asynchronous_destruction_calls_callback_on_failure)
4625+{
4626+ auto not_a_valid_client_side_rs = reinterpret_cast<MirRenderSurface*>(0x0ff01bb1);
4627+
4628+ mt::Signal callback_called;
4629+
4630+ mir_render_surface_release(
4631+ not_a_valid_client_side_rs,
4632+ [](MirRenderSurface*, void* ctx)
4633+ {
4634+ reinterpret_cast<mt::Signal*>(ctx)->raise();
4635+ },
4636+ &callback_called);
4637+
4638+ EXPECT_TRUE(callback_called.wait_for(std::chrono::seconds{20}));
4639 }
4640
4641 TEST_F(RenderSurfaceTest, stores_user_set_size_for_driver_to_access)
4642
4643=== modified file 'tests/acceptance-tests/test_server_shutdown.cpp'
4644--- tests/acceptance-tests/test_server_shutdown.cpp 2017-03-09 12:52:48 +0000
4645+++ tests/acceptance-tests/test_server_shutdown.cpp 2017-03-28 00:17:49 +0000
4646@@ -25,7 +25,7 @@
4647 #include "mir_test_framework/executable_path.h"
4648 #include "mir/test/doubles/null_logger.h"
4649
4650-#include <gtest/gtest.h>
4651+#include </usr/include/gtest/gtest.h>
4652
4653 namespace mt = mir::test;
4654 namespace mtf = mir_test_framework;
4655
4656=== added file 'tests/include/mir/test/doubles/mock_client_buffer_stream_factory.h.THIS'
4657--- tests/include/mir/test/doubles/mock_client_buffer_stream_factory.h.THIS 1970-01-01 00:00:00 +0000
4658+++ tests/include/mir/test/doubles/mock_client_buffer_stream_factory.h.THIS 2017-03-28 00:17:49 +0000
4659@@ -0,0 +1,59 @@
4660+/*
4661+ * Copyright © 2015 Canonical Ltd.
4662+ *
4663+ * This program is free software: you can redistribute it and/or modify it
4664+ * under the terms of the GNU General Public License version 3,
4665+ * as published by the Free Software Foundation.
4666+ *
4667+ * This program is distributed in the hope that it will be useful,
4668+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
4669+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
4670+ * GNU General Public License for more details.
4671+ *
4672+ * You should have received a copy of the GNU General Public License
4673+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
4674+ *
4675+ * Authored by: Robert Carr <robert.carr@canonical.com>
4676+ */
4677+
4678+#ifndef MIR_TEST_DOUBLES_MOCK_CLIENT_BUFFER_STREAM_FACTORY_H_
4679+#define MIR_TEST_DOUBLES_MOCK_CLIENT_BUFFER_STREAM_FACTORY_H_
4680+
4681+#include "src/client/client_buffer_stream_factory.h"
4682+#include "src/client/buffer_stream.h"
4683+
4684+#include <gtest/gtest.h>
4685+#include <gmock/gmock.h>
4686+
4687+namespace mir
4688+{
4689+namespace test
4690+{
4691+namespace doubles
4692+{
4693+
4694+struct MockClientBufferStreamFactory : public client::ClientBufferStreamFactory
4695+{
4696+ MOCK_METHOD4(make_consumer_stream, std::shared_ptr<client::ClientBufferStream>(
4697+ MirConnection*,
4698+ protobuf::DisplayServer&,
4699+ protobuf::BufferStream const&,
4700+ std::string const&));
4701+ MOCK_METHOD4(make_producer_stream, std::shared_ptr<client::ClientBufferStream>(
4702+ MirConnection*,
4703+ protobuf::DisplayServer&,
4704+ protobuf::BufferStream const&,
4705+ std::string const&));
4706+ MOCK_METHOD5(make_producer_stream, client::ClientBufferStream*(
4707+ MirConnection*,
4708+ protobuf::DisplayServer&,
4709+ protobuf::BufferStreamParameters const&,
4710+ mir_buffer_stream_callback callback,
4711+ void* context));
4712+};
4713+
4714+}
4715+}
4716+}
4717+
4718+#endif // MIR_TEST_DOUBLES_MOCK_CLIENT_BUFFER_STREAM_FACTORY_H_
4719
4720=== modified file 'tests/include/mir/test/doubles/mock_mir_buffer_stream.h'
4721--- tests/include/mir/test/doubles/mock_mir_buffer_stream.h 2017-03-10 19:47:57 +0000
4722+++ tests/include/mir/test/doubles/mock_mir_buffer_stream.h 2017-03-28 00:17:49 +0000
4723@@ -50,6 +50,7 @@
4724 MOCK_METHOD0(get_create_wait_handle, MirWaitHandle*(void));
4725 MOCK_CONST_METHOD0(rpc_id, frontend::BufferStreamId(void));
4726 MOCK_CONST_METHOD0(valid, bool(void));
4727+ MOCK_CONST_METHOD0(has_buffer, bool(void));
4728 MOCK_METHOD1(buffer_available, void(mir::protobuf::Buffer const&));
4729 MOCK_METHOD0(buffer_unavailable, void());
4730 MOCK_METHOD1(set_size, void(geometry::Size));
4731
4732=== modified file 'tests/include/mir/test/doubles/stub_buffer_stream_factory.h'
4733--- tests/include/mir/test/doubles/stub_buffer_stream_factory.h 2017-03-13 08:12:52 +0000
4734+++ tests/include/mir/test/doubles/stub_buffer_stream_factory.h 2017-03-28 00:17:49 +0000
4735@@ -21,7 +21,10 @@
4736
4737 #include "mir/frontend/client_buffers.h"
4738 #include "mir/scene/buffer_stream_factory.h"
4739+#include "mir/frontend/buffer_sink.h"
4740 #include "stub_buffer_stream.h"
4741+#include "stub_buffer.h"
4742+#include "mir_test_framework/stub_platform_native_buffer.h"
4743
4744 namespace mir
4745 {
4746@@ -32,8 +35,20 @@
4747
4748 struct StubClientBuffers : frontend::ClientBuffers
4749 {
4750+<<<<<<< TREE
4751 graphics::BufferID add_buffer(std::shared_ptr<graphics::Buffer> const&) override
4752 {
4753+=======
4754+ StubClientBuffers(std::shared_ptr<frontend::BufferSink> const& sink)
4755+ : sink{sink}
4756+ {
4757+ }
4758+
4759+ graphics::BufferID add_buffer(graphics::BufferProperties const& props) override
4760+ {
4761+ StubBuffer buf{std::make_shared<mir_test_framework::NativeBuffer>(props), props.size};
4762+ sink->add_buffer(buf);
4763+>>>>>>> MERGE-SOURCE
4764 return {};
4765 }
4766 void remove_buffer(graphics::BufferID) override
4767@@ -50,6 +65,7 @@
4768 {
4769 }
4770 std::shared_ptr<graphics::Buffer> buffer;
4771+ std::shared_ptr<frontend::BufferSink> const sink;
4772 };
4773
4774 struct StubBufferStreamFactory : public scene::BufferStreamFactory
4775@@ -61,9 +77,9 @@
4776 frontend::BufferStreamId, std::shared_ptr<frontend::ClientBuffers> const&,
4777 graphics::BufferProperties const&) { return std::make_shared<StubBufferStream>(); }
4778 std::shared_ptr<frontend::ClientBuffers> create_buffer_map(
4779- std::shared_ptr<frontend::BufferSink> const&)
4780+ std::shared_ptr<frontend::BufferSink> const& sink)
4781 {
4782- return std::make_shared<StubClientBuffers>();
4783+ return std::make_shared<StubClientBuffers>(sink);
4784 }
4785 };
4786 }
4787
4788=== added file 'tests/include/mir/test/doubles/stub_client_buffer_stream_factory.h.THIS'
4789--- tests/include/mir/test/doubles/stub_client_buffer_stream_factory.h.THIS 1970-01-01 00:00:00 +0000
4790+++ tests/include/mir/test/doubles/stub_client_buffer_stream_factory.h.THIS 2017-03-28 00:17:49 +0000
4791@@ -0,0 +1,66 @@
4792+/*
4793+ * Copyright © 2015 Canonical Ltd.
4794+ *
4795+ * This program is free software: you can redistribute it and/or modify it
4796+ * under the terms of the GNU General Public License version 3,
4797+ * as published by the Free Software Foundation.
4798+ *
4799+ * This program is distributed in the hope that it will be useful,
4800+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
4801+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
4802+ * GNU General Public License for more details.
4803+ *
4804+ * You should have received a copy of the GNU General Public License
4805+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
4806+ *
4807+ * Authored by: Robert Carr <robert.carr@canonical.com>
4808+ */
4809+
4810+#ifndef MIR_TEST_DOUBLES_STUB_CLIENT_BUFFER_STREAM_FACTORY_H_
4811+#define MIR_TEST_DOUBLES_STUB_CLIENT_BUFFER_STREAM_FACTORY_H_
4812+
4813+#include "src/client/client_buffer_stream_factory.h"
4814+#include "src/client/buffer_stream.h"
4815+
4816+namespace mir
4817+{
4818+namespace test
4819+{
4820+namespace doubles
4821+{
4822+
4823+struct StubClientBufferStreamFactory : public client::ClientBufferStreamFactory
4824+{
4825+ std::shared_ptr<client::ClientBufferStream> make_consumer_stream(
4826+ MirConnection* /* allocating_connection */,
4827+ protobuf::DisplayServer& /* server */,
4828+ protobuf::BufferStream const& /* protobuf_bs */,
4829+ std::string const& /* surface_name */) override
4830+ {
4831+ return nullptr;
4832+ }
4833+
4834+ std::shared_ptr<client::ClientBufferStream> make_producer_stream(
4835+ MirConnection* /* allocating_connection */,
4836+ protobuf::DisplayServer& /* server */,
4837+ protobuf::BufferStream const& /* protobuf_bs */,
4838+ std::string const& /* surface_name */) override
4839+ {
4840+ return nullptr;
4841+ }
4842+
4843+ client::ClientBufferStream* make_producer_stream(
4844+ MirConnection* /* allocating_connection */,
4845+ protobuf::DisplayServer& /* server */,
4846+ protobuf::BufferStreamParameters const& /* params */,
4847+ mir_buffer_stream_callback /* callback */, void* /* context */) override
4848+ {
4849+ return nullptr;
4850+ }
4851+};
4852+
4853+}
4854+}
4855+}
4856+
4857+#endif // MIR_TEST_DOUBLES_STUB_CLIENT_BUFFER_STREAM_FACTORY_H_
4858
4859=== modified file 'tests/integration-tests/test_buffer_scheduling.cpp'
4860--- tests/integration-tests/test_buffer_scheduling.cpp 2017-03-13 08:12:52 +0000
4861+++ tests/integration-tests/test_buffer_scheduling.cpp 2017-03-28 00:17:49 +0000
4862@@ -27,6 +27,7 @@
4863 #include "src/client/connection_surface_map.h"
4864 #include "src/server/compositor/stream.h"
4865 #include "src/server/compositor/buffer_map.h"
4866+#include "mir/dispatch/action_queue.h"
4867 #include "mir/test/doubles/stub_client_buffer_factory.h"
4868 #include "mir/test/doubles/mock_client_buffer_factory.h"
4869 #include "mir/test/doubles/stub_buffer_allocator.h"
4870@@ -37,6 +38,7 @@
4871
4872 namespace mt = mir::test;
4873 namespace mtd = mir::test::doubles;
4874+namespace md = mir::dispatch;
4875 namespace mcl = mir::client;
4876 namespace mc = mir::compositor;
4877 namespace mg = mir::graphics;
4878@@ -290,7 +292,7 @@
4879 {
4880 ScheduledProducer(std::shared_ptr<StubIpcSystem> const& ipc_stub, int nbuffers) :
4881 ipc(ipc_stub),
4882- map(std::make_shared<mcl::ConnectionSurfaceMap>()),
4883+ map(std::make_shared<mcl::ConnectionSurfaceMap>(std::make_shared<md::ActionQueue>())),
4884 factory(std::make_shared<mcl::BufferFactory>()),
4885 vault(
4886 std::make_shared<mtd::StubClientBufferFactory>(), factory,
4887
4888=== modified file 'tests/integration-tests/test_surfaceloop.cpp'
4889--- tests/integration-tests/test_surfaceloop.cpp 2017-01-18 02:29:37 +0000
4890+++ tests/integration-tests/test_surfaceloop.cpp 2017-03-28 00:17:49 +0000
4891@@ -17,6 +17,7 @@
4892 */
4893
4894 #include "mir_toolkit/mir_client_library.h"
4895+#include "mir/graphics/buffer_ipc_message.h"
4896
4897 #include "mir/test/doubles/stub_buffer.h"
4898 #include "mir/test/doubles/stub_buffer_allocator.h"
4899@@ -33,6 +34,7 @@
4900 #include <condition_variable>
4901 #include <gmock/gmock.h>
4902 #include <gtest/gtest.h>
4903+#include <src/client/lttng/shared_library_prober_report_tp.h>
4904 #include "mir/test/gmock_fixes.h"
4905
4906 namespace mc = mir::compositor;
4907@@ -44,35 +46,6 @@
4908
4909 namespace
4910 {
4911-geom::Size const size{640, 480};
4912-MirPixelFormat const format{mir_pixel_format_abgr_8888};
4913-mg::BufferUsage const usage{mg::BufferUsage::hardware};
4914-mg::BufferProperties const buffer_properties{size, format, usage};
4915-
4916-
4917-class MockGraphicBufferAllocator : public mtd::StubBufferAllocator
4918-{
4919- public:
4920- MockGraphicBufferAllocator()
4921- {
4922- using testing::_;
4923- ON_CALL(*this, alloc_buffer(_))
4924- .WillByDefault(testing::Invoke(this, &MockGraphicBufferAllocator::on_create_swapper));
4925- }
4926-
4927- MOCK_METHOD1(
4928- alloc_buffer,
4929- std::shared_ptr<mg::Buffer> (mg::BufferProperties const&));
4930-
4931-
4932- std::shared_ptr<mg::Buffer> on_create_swapper(mg::BufferProperties const&)
4933- {
4934- return std::make_shared<mtd::StubBuffer>(::buffer_properties);
4935- }
4936-
4937- ~MockGraphicBufferAllocator() noexcept {}
4938-};
4939-
4940 class StubDisplay : public mtd::NullDisplay
4941 {
4942 public:
4943@@ -96,11 +69,13 @@
4944 {
4945 public:
4946
4947- CountingStubBuffer()
4948+ CountingStubBuffer(mg::BufferProperties const& props)
4949+ : StubBuffer(props)
4950 {
4951 std::lock_guard<std::mutex> lock{buffers_mutex};
4952 ++buffers_created;
4953 buffers_cv.notify_one();
4954+ std::cout << "Created buffer with size " << size() << std::endl;
4955 }
4956 ~CountingStubBuffer()
4957 {
4958@@ -118,11 +93,61 @@
4959 class StubGraphicBufferAllocator : public mtd::StubBufferAllocator
4960 {
4961 public:
4962- std::shared_ptr<mg::Buffer> alloc_buffer(mg::BufferProperties const&) override
4963- {
4964- return std::make_shared<CountingStubBuffer>();
4965- }
4966- };
4967+ std::shared_ptr<mg::Buffer> alloc_buffer(mg::BufferProperties const& props) override
4968+ {
4969+ return std::make_shared<CountingStubBuffer>(props);
4970+ }
4971+ };
4972+<<<<<<< TREE
4973+=======
4974+
4975+ class StubPlatform : public mtd::NullPlatform
4976+ {
4977+ public:
4978+ mir::UniqueModulePtr<mg::GraphicBufferAllocator> create_buffer_allocator() override
4979+ {
4980+ return mir::make_module_ptr<StubGraphicBufferAllocator>();
4981+ }
4982+
4983+ mir::UniqueModulePtr<mg::Display> create_display(
4984+ std::shared_ptr<mg::DisplayConfigurationPolicy> const&,
4985+ std::shared_ptr<mg::GLConfig> const&) override
4986+ {
4987+ return mir::make_module_ptr<StubDisplay>();
4988+ }
4989+
4990+ mir::UniqueModulePtr<mg::PlatformIpcOperations> make_ipc_operations() const override
4991+ {
4992+ class BufferPackingIPCOperations : public mtd::NullPlatformIpcOperations
4993+ {
4994+ public:
4995+ void pack_buffer(
4996+ mg::BufferIpcMessage& message,
4997+ mg::Buffer const& buffer,
4998+ mg::BufferIpcMsgType msg_type) const override
4999+ {
5000+ if (msg_type == mg::BufferIpcMsgType::full_msg)
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches