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
=== modified file 'benchmarks/benchmark_multiplexing_dispatchable.cpp'
--- benchmarks/benchmark_multiplexing_dispatchable.cpp 2015-06-17 05:20:42 +0000
+++ benchmarks/benchmark_multiplexing_dispatchable.cpp 2017-03-28 00:17:49 +0000
@@ -19,6 +19,7 @@
19#include "mir/dispatch/multiplexing_dispatchable.h"19#include "mir/dispatch/multiplexing_dispatchable.h"
2020
21#include <iostream>21#include <iostream>
22#include <thread>
22#include <vector>23#include <vector>
23#include <memory>24#include <memory>
24#include <chrono>25#include <chrono>
2526
=== modified file 'debian/control'
--- debian/control 2017-03-22 23:38:59 +0000
+++ debian/control 2017-03-28 00:17:49 +0000
@@ -288,6 +288,7 @@
288Pre-Depends: ${misc:Pre-Depends}288Pre-Depends: ${misc:Pre-Depends}
289Depends: ${misc:Depends},289Depends: ${misc:Depends},
290 ${shlibs:Depends},290 ${shlibs:Depends},
291 umockdev,
291Recommends: mir-demos,292Recommends: mir-demos,
292Description: Display Server for Ubuntu - stress tests and other test tools293Description: Display Server for Ubuntu - stress tests and other test tools
293 Mir is a display server running on linux systems, with a focus on efficiency,294 Mir is a display server running on linux systems, with a focus on efficiency,
294295
=== modified file 'examples/chain_jumping_buffers.c'
--- examples/chain_jumping_buffers.c 2017-03-10 19:47:57 +0000
+++ examples/chain_jumping_buffers.c 2017-03-28 00:17:49 +0000
@@ -268,8 +268,14 @@
268 for (unsigned int i = 0u; i < num_buffers; i++)268 for (unsigned int i = 0u; i < num_buffers; i++)
269 mir_buffer_release(buffer_available[i].buffer);269 mir_buffer_release(buffer_available[i].buffer);
270 for (unsigned int i = 0u; i < num_chains; i++)270 for (unsigned int i = 0u; i < num_chains; i++)
271<<<<<<< TREE
271 mir_render_surface_release(render_surface[i]);272 mir_render_surface_release(render_surface[i]);
272 mir_window_release_sync(window);273 mir_window_release_sync(window);
274=======
275 mir_render_surface_release_sync(render_surface[i]);
276
277 mir_surface_release_sync(surface);
278>>>>>>> MERGE-SOURCE
273 mir_connection_release(connection);279 mir_connection_release(connection);
274 return 0;280 return 0;
275}281}
276282
=== modified file 'examples/prerendered_frames.c'
--- examples/prerendered_frames.c 2017-03-10 19:47:57 +0000
+++ examples/prerendered_frames.c 2017-03-28 00:17:49 +0000
@@ -234,8 +234,13 @@
234234
235 for (i = 0u; i < num_prerendered_frames; i++)235 for (i = 0u; i < num_prerendered_frames; i++)
236 mir_buffer_release(buffer_available[i].buffer);236 mir_buffer_release(buffer_available[i].buffer);
237<<<<<<< TREE
237 mir_render_surface_release(render_surface);238 mir_render_surface_release(render_surface);
238 mir_window_release_sync(window);239 mir_window_release_sync(window);
240=======
241 mir_render_surface_release_sync(render_surface);
242 mir_surface_release_sync(surface);
243>>>>>>> MERGE-SOURCE
239 mir_connection_release(connection);244 mir_connection_release(connection);
240 return 0;245 return 0;
241}246}
242247
=== modified file 'examples/render_surface.cpp'
--- examples/render_surface.cpp 2017-03-10 19:47:57 +0000
+++ examples/render_surface.cpp 2017-03-28 00:17:49 +0000
@@ -23,6 +23,8 @@
23#include <signal.h>23#include <signal.h>
24#include <sys/signalfd.h>24#include <sys/signalfd.h>
25#include <poll.h>25#include <poll.h>
26#include <mutex>
27#include <condition_variable>
2628
27#include "mir_toolkit/mir_client_library.h"29#include "mir_toolkit/mir_client_library.h"
28#include "mir_toolkit/rs/mir_render_surface.h"30#include "mir_toolkit/rs/mir_render_surface.h"
@@ -207,14 +209,23 @@
207 if (nformats == 0)209 if (nformats == 0)
208 throw std::runtime_error("no pixel formats for buffer stream");210 throw std::runtime_error("no pixel formats for buffer stream");
209 printf("Software Driver selected pixel format %d\n", pixel_format);211 printf("Software Driver selected pixel format %d\n", pixel_format);
212<<<<<<< TREE
210 auto buffer_stream = mir_render_surface_get_buffer_stream(213 auto buffer_stream = mir_render_surface_get_buffer_stream(
211 render_surface, width, height, pixel_format);214 render_surface, width, height, pixel_format);
215=======
216
217 auto stream = mir_render_surface_get_buffer_stream_sync(
218 render_surface,
219 width, height,
220 pixel_format,
221 mir_buffer_usage_software);
222>>>>>>> MERGE-SOURCE
212223
213 auto window = mir_create_window_sync(spec);224 auto window = mir_create_window_sync(spec);
214 mir_window_spec_release(spec);225 mir_window_spec_release(spec);
215226
216 fill_stream_with(buffer_stream, 255, 0, 0, 128);227 fill_stream_with(stream, 255, 0, 0, 128);
217 mir_buffer_stream_swap_buffers_sync(buffer_stream);228 mir_buffer_stream_swap_buffers_sync(stream);
218229
219 sigset_t halt_signals;230 sigset_t halt_signals;
220 sigemptyset(&halt_signals);231 sigemptyset(&halt_signals);
@@ -235,13 +246,18 @@
235 {246 {
236 bounce_position(baseColour, dbase, 128, 255);247 bounce_position(baseColour, dbase, 128, 255);
237248
238 fill_stream_with(buffer_stream, baseColour, 0, 0, 128);249 fill_stream_with(stream, baseColour, 0, 0, 128);
239250
240 mir_buffer_stream_swap_buffers_sync(buffer_stream);251 mir_buffer_stream_swap_buffers_sync(stream);
241 }252 }
242253
254<<<<<<< TREE
243 mir_render_surface_release(render_surface);255 mir_render_surface_release(render_surface);
244 mir_window_release_sync(window);256 mir_window_release_sync(window);
257=======
258 mir_render_surface_release_sync(render_surface);
259 mir_surface_release_sync(surface);
260>>>>>>> MERGE-SOURCE
245 close(signal_watch);261 close(signal_watch);
246262
247 return 0;263 return 0;
248264
=== modified file 'include/client/mir_toolkit/mir_connection.h'
--- include/client/mir_toolkit/mir_connection.h 2017-03-13 08:12:52 +0000
+++ include/client/mir_toolkit/mir_connection.h 2017-03-28 00:17:49 +0000
@@ -63,6 +63,54 @@
63MirConnection *mir_connect_sync(char const *server, char const *app_name);63MirConnection *mir_connect_sync(char const *server, char const *app_name);
6464
65/**65/**
66 * Request a connection to the Mir server.
67 *
68 * The client is responsible for handling event consumption via
69 * mir_connection_dispatch(). Events will be available when the fd returned
70 * by mir_connection_get_event_fd() becomes readable.
71 *
72 * All callbacks for this MirConnection and any objects created on it will be
73 * called from the thread calling mir_connection_dispatch().
74 *
75 * \param [in] server A string specifying the server to connect to.
76 * Connection strings can either be path to the socket file on
77 * the filesystem, or an open file descriptor fd://
78 * \param [in] app_name A name referring to the application
79 * \param [in] callback Callback function to be invoked when request
80 * completes. mir_connection_is_valid() will return false
81 * until this callback has completed.
82 * \param [in,out] context User data passed to the callback function
83 * \returns The resulting MirConnection
84 * \todo Currently manual dispatch interacts awkwardly with *_sync() calls;
85 * Synchronous calls do *not* automatically dispatch, so unless client
86 * code has a separate thread running dispatch, any *_sync() call will
87 * deadlock. This restriction will be fixed in a later release.
88 */
89MirConnection* mir_connect_with_manual_dispatch(char const* server,
90 char const* app_name,
91 mir_connected_callback callback,
92 void* context);
93
94/**
95 * Synchronously connect to the Mir server.
96 *
97 * The client is responsible for handling event consumption via
98 * mir_connection_dispatch(). Events will be available when the fd returned
99 * by mir_connection_get_event_fd() becomes readable.
100 *
101 * All callbacks for this MirConnection and any objects created on it will be
102 * called from the thread calling mir_connection_dispatch().
103 *
104 * \param [in] server A string specifying the server to connect to.
105 * Connection strings can either be path to the socket file on
106 * the filesystem, or an open file descriptor fd://
107 * \param [in] app_name A name referring to the application
108 * \returns The resulting MirConnection
109 */
110MirConnection* mir_connect_with_manual_dispatch_sync(char const* server,
111 char const* app_name);
112
113/**
66 * Test for a valid connection114 * Test for a valid connection
67 * \param [in] connection The connection115 * \param [in] connection The connection
68 * \return True if the supplied connection is valid, or116 * \return True if the supplied connection is valid, or
@@ -87,6 +135,28 @@
87void mir_connection_release(MirConnection *connection);135void mir_connection_release(MirConnection *connection);
88136
89/**137/**
138 * \brief Get the notification fd for this connection
139 * \param [in] connection The connection. This connection must have been created by
140 * mir_connect_with_manual_dispatch().
141 * \return A file descriptor that supports select/poll/epoll and similar
142 * APIs that becomes readable when there are events to dispatch,
143 * or -1 if \ref connection was not created by
144 * mir_connect_with_manual_dispatch();
145 * \note This fd is owned by the MirConnection. Do not close the fd yourself.
146 * The fd remains valid until mir_connection_release() returns.
147 */
148int mir_connection_get_event_fd(MirConnection* connection);
149
150/**
151 * \brief Dispatch a single pending event on the connection
152 * \param [in] connection The connection. This connection must have been created by
153 * mir_connect_with_manual_dispatch().
154 * \note It is an error to call this on a \ref connection not created by
155 * mir_connect_with_manual_dispatch().
156 */
157void mir_connection_dispatch(MirConnection* connection);
158
159/**
90 * Query platform-specific data and/or file descriptors that are required to160 * Query platform-specific data and/or file descriptors that are required to
91 * initialize GL/EGL features.161 * initialize GL/EGL features.
92 * \param [in] connection The connection162 * \param [in] connection The connection
93163
=== modified file 'include/client/mir_toolkit/mir_wait.h'
--- include/client/mir_toolkit/mir_wait.h 2017-01-19 23:17:56 +0000
+++ include/client/mir_toolkit/mir_wait.h 2017-03-28 00:17:49 +0000
@@ -49,6 +49,7 @@
49void mir_wait_for_one(MirWaitHandle *wait_handle)49void mir_wait_for_one(MirWaitHandle *wait_handle)
50__attribute__ ((deprecated("No longer supported - use callbacks or wait for state changes")));50__attribute__ ((deprecated("No longer supported - use callbacks or wait for state changes")));
5151
52bool mir_wait_handle_ready(MirWaitHandle* wait_handle);
5253
53#ifdef __cplusplus54#ifdef __cplusplus
54}55}
5556
=== modified file 'include/client/mir_toolkit/rs/mir_render_surface.h'
--- include/client/mir_toolkit/rs/mir_render_surface.h 2017-03-14 04:41:33 +0000
+++ include/client/mir_toolkit/rs/mir_render_surface.h 2017-03-28 00:17:49 +0000
@@ -118,13 +118,30 @@
118/**118/**
119 * Release the specified render surface119 * Release the specified render surface
120 *120 *
121 * \param [in] render_surface The render surface to be released121 * \param [in] render_surface The render surface to be released
122 * \param [in] callback Callback to be run when the operation completes
123 * \param [in,out] ctx Context passed to callback
122 */124 */
123void mir_render_surface_release(125void mir_render_surface_release(
126<<<<<<< TREE
124 MirRenderSurface* render_surface)127 MirRenderSurface* render_surface)
125__attribute__((deprecated("This function is slated for rename due to MirRenderSurface-->MirSurface transition")));128__attribute__((deprecated("This function is slated for rename due to MirRenderSurface-->MirSurface transition")));
126129=======
127/**130 MirRenderSurface* render_surface,
131 mir_render_surface_callback callback,
132 void* ctx);
133
134/**
135 * Release the specified render surface and wait for the operation to complete
136 *
137 * \param [in] render_surface The render surface to be released
138 */
139void mir_render_surface_release_sync(
140 MirRenderSurface* render_surface);
141>>>>>>> MERGE-SOURCE
142
143/**
144<<<<<<< TREE
128 * Obtain the buffer stream backing a given render surface.145 * Obtain the buffer stream backing a given render surface.
129 * The MirBufferStream will contain buffers suitable for writing via the CPU. 146 * The MirBufferStream will contain buffers suitable for writing via the CPU.
130 *147 *
@@ -143,10 +160,57 @@
143 int width, int height,160 int width, int height,
144 MirPixelFormat format)161 MirPixelFormat format)
145__attribute__((deprecated("This function is slated for rename due to MirRenderSurface-->MirSurface transition")));162__attribute__((deprecated("This function is slated for rename due to MirRenderSurface-->MirSurface transition")));
146163=======
147/**164 * Obtain a buffer stream backing a given render surface
165 *
166 * \pre The MirRenderSurface does not have a backing object.
167 *
168 * \param [in] render_surface The render surface
169 * \param [in] width Requested width
170 * \param [in] height Requested height
171 * \param [in] format Requested pixel format
172 * \param [in] usage Requested buffer usage
173 * \param [in] callback Callback to be run when operation completes
174 * \param [in,out] context Context passed to callback
175 */
176void mir_render_surface_get_buffer_stream(
177 MirRenderSurface* render_surface,
178 int width,
179 int height,
180 MirPixelFormat format,
181 MirBufferUsage usage,
182 mir_buffer_stream_callback callback,
183 void* context);
184
185/**
186 * Back the render surface with a buffer stream and wait for the operation to complete.
187 *
188 * \pre The MirRenderSurface does not have a backing object.
189 *
190 * \param [in] render_surface The render surface
191 * \param [in] width Requested width
192 * \param [in] height Requested height
193 * \param [in] format Requested pixel format
194 * \param [in] usage Requested buffer usage
195 * \return The new MirBufferStream backing the MirRenderSurface.
196 * If a backing object for this MirRenderSurface has already been realised
197 * this returns NULL, otherwise it returns a non-null MirBufferStream
198 */
199MirBufferStream* mir_render_surface_get_buffer_stream_sync(
200 MirRenderSurface* render_surface,
201 int width,
202 int height,
203 MirPixelFormat format,
204 MirBufferUsage usage);
205>>>>>>> MERGE-SOURCE
206
207/**
208<<<<<<< TREE
148 * Obtain the presentation chain backing a given render surface.209 * Obtain the presentation chain backing a given render surface.
149 * The MirPresentationChain is created in mir_present_mode_fifo submission mode.210 * The MirPresentationChain is created in mir_present_mode_fifo submission mode.
211=======
212 * Obtain a presentation chain backing a given render surface
213>>>>>>> MERGE-SOURCE
150 *214 *
151 * \return The chain contained in the given render surface215 * \return The chain contained in the given render surface
152 * or 'nullptr' if it, or216 * or 'nullptr' if it, or
153217
=== added file 'include/common/mir/dispatch/threaded_dispatcher.h.moved'
--- include/common/mir/dispatch/threaded_dispatcher.h.moved 1970-01-01 00:00:00 +0000
+++ include/common/mir/dispatch/threaded_dispatcher.h.moved 2017-03-28 00:17:49 +0000
@@ -0,0 +1,75 @@
1/*
2 * Copyright © 2015 Canonical Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU Lesser General Public License version 3,
6 * as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authored by: Christopher James Halse Rogers <christopher.halse.rogers@canonical.com>
17 */
18
19#ifndef MIR_DISPATCH_SIMPLE_DISPATCH_THREAD_H_
20#define MIR_DISPATCH_SIMPLE_DISPATCH_THREAD_H_
21
22#include <string>
23#include <memory>
24#include <thread>
25#include <vector>
26#include <mutex>
27#include <condition_variable>
28
29#include "mir/dispatch/multiplexing_dispatchable.h"
30#include "mir/fd.h"
31
32namespace mir
33{
34namespace dispatch
35{
36class Dispatchable;
37
38class ThreadedDispatcher
39{
40public:
41 ThreadedDispatcher(std::string const& name, std::shared_ptr<Dispatchable> const& dispatchee);
42 ThreadedDispatcher(std::string const& name,
43 std::shared_ptr<Dispatchable> const& dispatchee,
44 std::function<void()> const& exception_handler);
45 ~ThreadedDispatcher() noexcept;
46
47 void add_thread();
48 void remove_thread();
49
50private:
51 class ThreadShutdownRequestHandler;
52 friend class ThreadShutdownRequestHandler;
53
54 std::string const name_base;
55
56 std::shared_ptr<ThreadShutdownRequestHandler> thread_exiter;
57 std::shared_ptr<MultiplexingDispatchable> dispatcher;
58
59 std::mutex thread_pool_mutex;
60 std::vector<std::thread> threadpool;
61
62 std::function<void()> const exception_handler;
63
64 static void dispatch_loop(std::string const& name,
65 std::shared_ptr<ThreadShutdownRequestHandler> thread_register,
66 std::shared_ptr<Dispatchable> dispatcher,
67 std::function<void()> const& exception_handler);
68
69};
70
71}
72}
73
74
75#endif // MIR_DISPATCH_SIMPLE_DISPATCH_THREAD_H_
076
=== renamed file 'tests/include/mir/test/fd_utils.h' => 'include/test/mir/test/fd_utils.h'
=== modified file 'include/test/mir/test/validity_matchers.h'
--- include/test/mir/test/validity_matchers.h 2017-01-18 02:29:37 +0000
+++ include/test/mir/test/validity_matchers.h 2017-03-28 00:17:49 +0000
@@ -23,6 +23,8 @@
2323
24#include "mir_toolkit/mir_client_library.h"24#include "mir_toolkit/mir_client_library.h"
2525
26class MirRenderSurface;
27
26using ::testing::MakePolymorphicMatcher;28using ::testing::MakePolymorphicMatcher;
27using ::testing::MatchResultListener;29using ::testing::MatchResultListener;
28using ::testing::NotNull;30using ::testing::NotNull;
@@ -54,6 +56,12 @@
54template<>56template<>
55bool IsValidMatcher::MatchAndExplain(MirWindow* surface, MatchResultListener* listener) const;57bool IsValidMatcher::MatchAndExplain(MirWindow* surface, MatchResultListener* listener) const;
5658
59template<>
60bool IsValidMatcher::MatchAndExplain(MirBufferStream* stream, MatchResultListener* listener) const;
61
62template<>
63bool IsValidMatcher::MatchAndExplain(MirRenderSurface* stream, MatchResultListener* listener) const;
64
57// To construct a polymorphic matcher, pass an instance of the class65// To construct a polymorphic matcher, pass an instance of the class
58// to MakePolymorphicMatcher(). Note the return type.66// to MakePolymorphicMatcher(). Note the return type.
59inline PolymorphicMatcher<IsValidMatcher> IsValid()67inline PolymorphicMatcher<IsValidMatcher> IsValid()
6068
=== modified file 'playground/egldiamond_render_surface.c'
--- playground/egldiamond_render_surface.c 2017-03-14 04:41:33 +0000
+++ playground/egldiamond_render_surface.c 2017-03-28 00:17:49 +0000
@@ -322,8 +322,13 @@
322 future_driver_eglTerminate(egldisplay);322 future_driver_eglTerminate(egldisplay);
323 else323 else
324 eglTerminate(egldisplay);324 eglTerminate(egldisplay);
325<<<<<<< TREE
325 mir_render_surface_release(render_surface);326 mir_render_surface_release(render_surface);
326 mir_window_release_sync(window);327 mir_window_release_sync(window);
328=======
329 mir_render_surface_release_sync(render_surface);
330 mir_surface_release_sync(surface);
331>>>>>>> MERGE-SOURCE
327 mir_connection_release(connection);332 mir_connection_release(connection);
328 return 0;333 return 0;
329}334}
330335
=== modified file 'playground/mir_egl_platform_shim.c'
--- playground/mir_egl_platform_shim.c 2017-03-10 19:47:57 +0000
+++ playground/mir_egl_platform_shim.c 2017-03-28 00:17:49 +0000
@@ -72,10 +72,19 @@
72 MirPixelFormat pixel_format = mir_connection_get_egl_pixel_format(info->connection, display, config);72 MirPixelFormat pixel_format = mir_connection_get_egl_pixel_format(info->connection, display, config);
73 //this particular [silly] driver has chosen the buffer stream as the way it wants to post73 //this particular [silly] driver has chosen the buffer stream as the way it wants to post
74 //its hardware content. I'd think most drivers would want MirPresentationChain for flexibility74 //its hardware content. I'd think most drivers would want MirPresentationChain for flexibility
75<<<<<<< TREE
75 info->stream = ext->get_hardware_buffer_stream(surface,76 info->stream = ext->get_hardware_buffer_stream(surface,
76 info->current_physical_width,77 info->current_physical_width,
77 info->current_physical_height,78 info->current_physical_height,
78 pixel_format);79 pixel_format);
80=======
81
82 info->stream = mir_render_surface_get_buffer_stream_sync(
83 surface,
84 info->current_physical_width, info->current_physical_height,
85 pixel_format,
86 mir_buffer_usage_hardware);
87>>>>>>> MERGE-SOURCE
7988
80 printf("The driver chose pixel format %d.\n", pixel_format);89 printf("The driver chose pixel format %d.\n", pixel_format);
81 return eglCreateWindowSurface(display, config, (EGLNativeWindowType) surface, attr);90 return eglCreateWindowSurface(display, config, (EGLNativeWindowType) surface, attr);
8291
=== modified file 'src/client/CMakeLists.txt'
--- src/client/CMakeLists.txt 2017-03-21 05:51:47 +0000
+++ src/client/CMakeLists.txt 2017-03-28 00:17:49 +0000
@@ -81,12 +81,15 @@
81 screencast_stream.cpp81 screencast_stream.cpp
82 buffer_vault.cpp82 buffer_vault.cpp
83 mir_buffer_stream_api.cpp83 mir_buffer_stream_api.cpp
84 synchronous_helper.cpp
84 error_stream.cpp85 error_stream.cpp
85 error_render_surface.cpp86 error_render_surface.cpp
86 buffer.cpp87 buffer.cpp
87 error_buffer.cpp88 error_buffer.cpp
88 mir_render_surface_api.cpp89 mir_render_surface_api.cpp
89 render_surface.cpp90 render_surface.cpp
91 mir_render_surface.h
92 ${CMAKE_SOURCE_DIR}/src/include/client/mir_toolkit/mir_render_surface.h
90 presentation_chain.cpp93 presentation_chain.cpp
91 mir_presentation_chain_api.cpp94 mir_presentation_chain_api.cpp
92 mir_buffer_api.cpp95 mir_buffer_api.cpp
@@ -104,7 +107,11 @@
104 ${CMAKE_SOURCE_DIR}/include/client/mir_toolkit/mir_error.h107 ${CMAKE_SOURCE_DIR}/include/client/mir_toolkit/mir_error.h
105 mir_extension_core.cpp108 mir_extension_core.cpp
106 ${CMAKE_SOURCE_DIR}/include/client/mir_toolkit/mir_extension_core.h109 ${CMAKE_SOURCE_DIR}/include/client/mir_toolkit/mir_extension_core.h
110<<<<<<< TREE
107 ${CMAKE_SOURCE_DIR}/include/client/mir_toolkit/extensions/drag_and_drop.h111 ${CMAKE_SOURCE_DIR}/include/client/mir_toolkit/extensions/drag_and_drop.h
112=======
113 no_tls_future-inl.h
114>>>>>>> MERGE-SOURCE
108)115)
109116
110# Ensure protobuf C++ headers have been produced before117# Ensure protobuf C++ headers have been produced before
@@ -160,6 +167,8 @@
160167
161add_library(mirclient-debug-extension SHARED168add_library(mirclient-debug-extension SHARED
162 mir_debug_api.cpp169 mir_debug_api.cpp
170 $<TARGET_OBJECTS:mirclientobjects>
171 $<TARGET_OBJECTS:mirsharedinput>
163)172)
164173
165target_link_libraries(mirclient-debug-extension174target_link_libraries(mirclient-debug-extension
166175
=== modified file 'src/client/buffer_factory.cpp'
--- src/client/buffer_factory.cpp 2017-03-10 19:47:57 +0000
+++ src/client/buffer_factory.cpp 2017-03-28 00:17:49 +0000
@@ -22,6 +22,7 @@
22#include <algorithm>22#include <algorithm>
23#include <boost/throw_exception.hpp>23#include <boost/throw_exception.hpp>
24#include "protobuf_to_native_buffer.h"24#include "protobuf_to_native_buffer.h"
25#include <sstream>
2526
26namespace mcl = mir::client;27namespace mcl = mir::client;
27namespace geom = mir::geometry;28namespace geom = mir::geometry;
@@ -92,7 +93,16 @@
92 });93 });
9394
94 if (request_it == allocation_requests.end())95 if (request_it == allocation_requests.end())
95 BOOST_THROW_EXCEPTION(std::logic_error("unrequested buffer received"));96 {
97 std::stringstream message;
98 message << "Unrequested buffer received. Expected a buffer with one of the following sizes:" << std::endl;
99 for (auto const& request : allocation_requests)
100 {
101 message << "\t(" << request->size.width << "×" << request->size.height << ")" << std::endl;
102 }
103 message << "Received buffer has size: (" << buffer.width() << "×" << buffer.height() << ")" << std::endl;
104 BOOST_THROW_EXCEPTION(std::logic_error{message.str()});
105 }
96106
97 std::unique_ptr<mcl::MirBuffer> b;107 std::unique_ptr<mcl::MirBuffer> b;
98 if (buffer.has_error())108 if (buffer.has_error())
99109
=== modified file 'src/client/buffer_stream.cpp'
--- src/client/buffer_stream.cpp 2017-03-20 11:24:19 +0000
+++ src/client/buffer_stream.cpp 2017-03-28 00:17:49 +0000
@@ -142,37 +142,52 @@
142//Should be merged with mcl::BufferVault142//Should be merged with mcl::BufferVault
143struct BufferDepository143struct BufferDepository
144{144{
145 BufferDepository(145 static NoTLSFuture<std::unique_ptr<BufferDepository>> create(
146 std::shared_ptr<mcl::ClientBufferFactory> const& factory,146 std::shared_ptr<mcl::ClientBufferFactory> const& factory,
147 std::shared_ptr<mcl::AsyncBufferFactory> const& mirbuffer_factory,147 std::shared_ptr<mcl::AsyncBufferFactory> const& mirbuffer_factory,
148 std::shared_ptr<mcl::ServerBufferRequests> const& requests,148 std::shared_ptr<mcl::ServerBufferRequests> const& requests,
149 std::weak_ptr<mcl::SurfaceMap> const& surface_map,149 std::weak_ptr<mcl::SurfaceMap> const& surface_map,
150 geom::Size size, MirPixelFormat format, int usage,150 geom::Size size, MirPixelFormat format, int usage,
151 unsigned int initial_nbuffers) :151 unsigned int initial_nbuffers)
152 vault(factory, mirbuffer_factory, requests, surface_map, size, format, usage, initial_nbuffers),
153 current(nullptr),
154 size_(size)
155 {152 {
156 future = vault.withdraw();153 auto vault = std::make_unique<mcl::BufferVault>(
154 factory,
155 mirbuffer_factory,
156 requests,
157 surface_map,
158 size,
159 format,
160 usage,
161 initial_nbuffers);
162
163 auto future_buffer = vault->withdraw();
164
165 // Because NoTLSFuture<>.then() internally uses a std::function<void()> for the
166 // continuation the lambda passed in has to be CopyConstructible, which means we can't
167 // move-capture a std::unique_ptr<>. Dance around it with release().
168 return future_buffer.then(
169 [raw_vault = vault.release(), size](auto&& resolved_buffer)
170 {
171 std::unique_ptr<mcl::BufferVault> vault{raw_vault};
172 return std::unique_ptr<BufferDepository>(
173 new BufferDepository{
174 resolved_buffer.get(),
175 std::move(vault),
176 size});
177 });
157 }178 }
158179
159 void deposit(mp::Buffer const&, mir::optional_value<geom::Size>, MirPixelFormat)180 void deposit(mp::Buffer const&, mir::optional_value<geom::Size>, MirPixelFormat)
160 {181 {
161 }182 }
162183
163 void advance_current_buffer(std::unique_lock<std::mutex>& lk)
164 {
165 lk.unlock();
166 auto c = future.get();
167 lk.lock();
168 current = c;
169 }
170
171 std::shared_ptr<mir::client::ClientBuffer> current_buffer()184 std::shared_ptr<mir::client::ClientBuffer> current_buffer()
172 {185 {
173 std::unique_lock<std::mutex> lk(mutex);186 std::unique_lock<std::mutex> lk(mutex);
174 if (!current)187 if (!current)
175 advance_current_buffer(lk);188 BOOST_THROW_EXCEPTION(
189 std::logic_error{
190 "Current buffer requested before waiting for buffer to arrive"});
176 return current->client_buffer();191 return current->client_buffer();
177 }192 }
178193
@@ -180,7 +195,9 @@
180 {195 {
181 std::unique_lock<std::mutex> lk(mutex);196 std::unique_lock<std::mutex> lk(mutex);
182 if (!current)197 if (!current)
183 advance_current_buffer(lk);198 BOOST_THROW_EXCEPTION(
199 std::logic_error{
200 "Current buffer requested before waiting for buffer to arrive"});
184 return current->rpc_id();201 return current->rpc_id();
185 }202 }
186203
@@ -188,16 +205,23 @@
188 {205 {
189 std::unique_lock<std::mutex> lk(mutex);206 std::unique_lock<std::mutex> lk(mutex);
190 if (!current)207 if (!current)
191 advance_current_buffer(lk);208 BOOST_THROW_EXCEPTION(
209 std::logic_error{
210 "Attempted to submit current buffer without waiting for a buffer to become current"});
192 auto c = current;211 auto c = current;
193 current = nullptr;212 current = nullptr;
194 lk.unlock();213 lk.unlock();
195214
196 vault.deposit(c);215 vault->deposit(c);
197 auto wh = vault.wire_transfer_outbound(c, done);216 auto wh = vault->wire_transfer_outbound(c, done);
198 auto f = vault.withdraw();217
199 lk.lock();218 vault->withdraw().then(
200 future = std::move(f);219 [this](auto&& new_buffer)
220 {
221 std::lock_guard<std::mutex> lk{mutex};
222
223 current = new_buffer.get();
224 }).detach();
201 return wh;225 return wh;
202 }226 }
203227
@@ -207,7 +231,7 @@
207 std::unique_lock<std::mutex> lk(mutex);231 std::unique_lock<std::mutex> lk(mutex);
208 size_ = size;232 size_ = size;
209 }233 }
210 vault.set_size(size);234 vault->set_size(size);
211 }235 }
212236
213 geom::Size size() const237 geom::Size size() const
@@ -218,14 +242,14 @@
218242
219 void lost_connection()243 void lost_connection()
220 {244 {
221 vault.disconnected();245 vault->disconnected();
222 }246 }
223247
224 MirWaitHandle* set_scale(float scale, mf::BufferStreamId)248 MirWaitHandle* set_scale(float scale, mf::BufferStreamId)
225 {249 {
226 scale_wait_handle.expect_result();250 scale_wait_handle.expect_result();
227 scale_wait_handle.result_received();251 scale_wait_handle.result_received();
228 vault.set_scale(scale);252 vault->set_scale(scale);
229 return &scale_wait_handle;253 return &scale_wait_handle;
230 }254 }
231255
@@ -233,15 +257,24 @@
233 {257 {
234 std::unique_lock<decltype(mutex)> lk(mutex);258 std::unique_lock<decltype(mutex)> lk(mutex);
235 interval = std::max(0, std::min(1, interval));259 interval = std::max(0, std::min(1, interval));
236 vault.set_interval(interval);260 vault->set_interval(interval);
237 }261 }
238262
239 // Future must be before vault, to ensure vault's destruction marks future263
240 // as ready.264private:
241 mir::client::NoTLSFuture<std::shared_ptr<mcl::MirBuffer>> future;265 BufferDepository(
242266 std::shared_ptr<mcl::MirBuffer> initial_buffer,
243 mcl::BufferVault vault;267 std::unique_ptr<mcl::BufferVault>&& vault,
268 geom::Size size) :
269 vault{std::move(vault)},
270 current{initial_buffer},
271 size_{size}
272 {
273 }
274
275 std::unique_ptr<mcl::BufferVault> vault;
244 std::mutex mutable mutex;276 std::mutex mutable mutex;
277 std::mutex current_buffer_mutex;
245 std::shared_ptr<mcl::MirBuffer> current{nullptr};278 std::shared_ptr<mcl::MirBuffer> current{nullptr};
246 MirWaitHandle scale_wait_handle;279 MirWaitHandle scale_wait_handle;
247 geom::Size size_;280 geom::Size size_;
@@ -249,12 +282,17 @@
249}282}
250}283}
251284
285<<<<<<< TREE
252#pragma GCC diagnostic push286#pragma GCC diagnostic push
253#pragma GCC diagnostic ignored "-Wdeprecated-declarations"287#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
254mcl::BufferStream::BufferStream(288mcl::BufferStream::BufferStream(
289=======
290mcl::NoTLSFuture<std::unique_ptr<mcl::BufferStream>>
291mcl::BufferStream::create(
292>>>>>>> MERGE-SOURCE
255 MirConnection* connection,293 MirConnection* connection,
256 MirRenderSurface* render_surface,294 MirRenderSurface* render_surface,
257 std::shared_ptr<MirWaitHandle> creation_wait_handle,295 std::shared_ptr<MirWaitHandle> const& creation_wait_handle,
258 mclr::DisplayServer& server,296 mclr::DisplayServer& server,
259 std::shared_ptr<mcl::ClientPlatform> const& client_platform,297 std::shared_ptr<mcl::ClientPlatform> const& client_platform,
260 std::weak_ptr<mcl::SurfaceMap> const& map,298 std::weak_ptr<mcl::SurfaceMap> const& map,
@@ -264,22 +302,87 @@
264 std::string const& surface_name,302 std::string const& surface_name,
265 geom::Size ideal_size,303 geom::Size ideal_size,
266 size_t nbuffers)304 size_t nbuffers)
305{
306 auto protobuf_bs = mcl::make_protobuf_object(a_protobuf_bs);
307
308 if (!protobuf_bs->has_id())
309 {
310 if (!protobuf_bs->has_error())
311 protobuf_bs->set_error("Error processing buffer stream create response, no ID (disconnected?)");
312 }
313
314 if (protobuf_bs->has_error())
315 {
316 if (protobuf_bs->has_buffer())
317 {
318 for (int i = 0; i < protobuf_bs->buffer().fd_size(); i++)
319 ::close(protobuf_bs->buffer().fd(i));
320 }
321
322 BOOST_THROW_EXCEPTION(std::runtime_error("Can not create buffer stream: " + std::string(protobuf_bs->error())));
323 }
324
325
326 auto future_depository = BufferDepository::create(
327 client_platform->create_buffer_factory(), factory,
328 std::make_shared<Requests>(server, protobuf_bs->id().value()), map,
329 ideal_size, static_cast<MirPixelFormat>(protobuf_bs->pixel_format()),
330 protobuf_bs->buffer_usage(), nbuffers);
331
332 return future_depository.then(
333 [=, raw_protobuf_bs = protobuf_bs.release(), raw_server = &server](auto&& depository)
334 {
335 std::unique_ptr<mp::BufferStream> protobuf_bs{raw_protobuf_bs};
336 // Can't use make_unique because the constructor is private to it.
337 return std::unique_ptr<BufferStream>{
338 new BufferStream{
339 *raw_server,
340 connection,
341 render_surface,
342 creation_wait_handle,
343 depository.get(),
344 client_platform,
345 map,
346 std::move(protobuf_bs),
347 perf_report,
348 surface_name,
349 ideal_size}};
350 }
351 );
352}
353
354mcl::BufferStream::BufferStream(
355 rpc::DisplayServer& server,
356 MirConnection* connection,
357 MirRenderSurface* render_surface,
358 std::shared_ptr<MirWaitHandle> const& creation_wait_handle,
359 std::unique_ptr<BufferDepository>&& depository,
360 std::shared_ptr<mcl::ClientPlatform> const& client_platform,
361 std::weak_ptr<mcl::SurfaceMap> const& map,
362 std::unique_ptr<mp::BufferStream>&& incoming_protobuf_bs,
363 std::shared_ptr<mcl::PerfReport> const& perf_report,
364 std::string const& surface_name,
365 geom::Size ideal_size)
267 : connection_(connection),366 : connection_(connection),
268 client_platform(client_platform),367 client_platform(client_platform),
269 protobuf_bs{mcl::make_protobuf_object<mir::protobuf::BufferStream>(a_protobuf_bs)},368 protobuf_bs{std::move(incoming_protobuf_bs)},
270 user_swap_interval(parse_env_for_swap_interval()),369 user_swap_interval(parse_env_for_swap_interval()),
370<<<<<<< TREE
271 using_client_side_vsync(false),371 using_client_side_vsync(false),
272 interval_config{server, frontend::BufferStreamId{a_protobuf_bs.id().value()}},372 interval_config{server, frontend::BufferStreamId{a_protobuf_bs.id().value()}},
373=======
374 interval_config{server, frontend::BufferStreamId{this->protobuf_bs->id().value()}},
375>>>>>>> MERGE-SOURCE
273 scale_(1.0f),376 scale_(1.0f),
274 perf_report(perf_report),377 perf_report(perf_report),
275 protobuf_void{mcl::make_protobuf_object<mir::protobuf::Void>()},378 protobuf_void{mcl::make_protobuf_object<mir::protobuf::Void>()},
379 buffer_depository{std::move(depository)},
276 ideal_buffer_size(ideal_size),380 ideal_buffer_size(ideal_size),
277 nbuffers(nbuffers),381 creation_wait_handle{creation_wait_handle},
278 creation_wait_handle(creation_wait_handle),
279 map(map),382 map(map),
280 factory(factory),
281 render_surface_(render_surface)383 render_surface_(render_surface)
282{384{
385<<<<<<< TREE
283 /*386 /*
284 * Since we try to use client-side vsync where possible, a separate387 * Since we try to use client-side vsync where possible, a separate
285 * copy of the current swap interval is required to represent that388 * copy of the current swap interval is required to represent that
@@ -306,9 +409,12 @@
306409
307 BOOST_THROW_EXCEPTION(std::runtime_error("Can not create buffer stream: " + std::string(protobuf_bs->error())));410 BOOST_THROW_EXCEPTION(std::runtime_error("Can not create buffer stream: " + std::string(protobuf_bs->error())));
308 }411 }
412=======
413>>>>>>> MERGE-SOURCE
309414
310 try415 try
311 {416 {
417<<<<<<< TREE
312 buffer_depository = std::make_unique<BufferDepository>(418 buffer_depository = std::make_unique<BufferDepository>(
313 client_platform->create_buffer_factory(), factory,419 client_platform->create_buffer_factory(), factory,
314 std::make_shared<Requests>(server, protobuf_bs->id().value(), client_platform),420 std::make_shared<Requests>(server, protobuf_bs->id().value(), client_platform),
@@ -316,6 +422,8 @@
316 ideal_buffer_size, static_cast<MirPixelFormat>(protobuf_bs->pixel_format()), 422 ideal_buffer_size, static_cast<MirPixelFormat>(protobuf_bs->pixel_format()),
317 protobuf_bs->buffer_usage(), nbuffers);423 protobuf_bs->buffer_usage(), nbuffers);
318424
425=======
426>>>>>>> MERGE-SOURCE
319 egl_native_window_ = client_platform->create_egl_native_window(this);427 egl_native_window_ = client_platform->create_egl_native_window(this);
320428
321 // This might seem like something to provide during creation but429 // This might seem like something to provide during creation but
322430
=== modified file 'src/client/buffer_stream.h'
--- src/client/buffer_stream.h 2017-03-20 11:24:19 +0000
+++ src/client/buffer_stream.h 2017-03-28 00:17:49 +0000
@@ -26,10 +26,15 @@
26#include "mir/geometry/size.h"26#include "mir/geometry/size.h"
27#include "mir/optional_value.h"27#include "mir/optional_value.h"
28#include "buffer_stream_configuration.h"28#include "buffer_stream_configuration.h"
29<<<<<<< TREE
29#include "frame_clock.h"30#include "frame_clock.h"
31=======
32#include "no_tls_future-inl.h"
33>>>>>>> MERGE-SOURCE
3034
31#include "mir_toolkit/client_types.h"35#include "mir_toolkit/client_types.h"
3236
37
33#include <EGL/eglplatform.h>38#include <EGL/eglplatform.h>
3439
35#include <unordered_set>40#include <unordered_set>
@@ -74,15 +79,19 @@
74class BufferStream : public EGLNativeSurface, public MirBufferStream79class BufferStream : public EGLNativeSurface, public MirBufferStream
75{80{
76public:81public:
82<<<<<<< TREE
77 BufferStream(83 BufferStream(
78 mir::client::rpc::DisplayServer& server,84 mir::client::rpc::DisplayServer& server,
79 std::weak_ptr<SurfaceMap> const& map);85 std::weak_ptr<SurfaceMap> const& map);
80#pragma GCC diagnostic push86#pragma GCC diagnostic push
81#pragma GCC diagnostic ignored "-Wdeprecated-declarations"87#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
82 BufferStream(88 BufferStream(
89=======
90 static NoTLSFuture<std::unique_ptr<BufferStream>> create(
91>>>>>>> MERGE-SOURCE
83 MirConnection* connection,92 MirConnection* connection,
84 MirRenderSurface* render_surface,93 MirRenderSurface* render_surface,
85 std::shared_ptr<MirWaitHandle> creation_wait_handle,94 std::shared_ptr<MirWaitHandle> const& creation_wait_handle,
86 mir::client::rpc::DisplayServer& server,95 mir::client::rpc::DisplayServer& server,
87 std::shared_ptr<ClientPlatform> const& native_window_factory,96 std::shared_ptr<ClientPlatform> const& native_window_factory,
88 std::weak_ptr<SurfaceMap> const& map,97 std::weak_ptr<SurfaceMap> const& map,
@@ -139,6 +148,19 @@
139 BufferStream& operator=(BufferStream const&) = delete;148 BufferStream& operator=(BufferStream const&) = delete;
140149
141private:150private:
151 BufferStream(
152 rpc::DisplayServer& server,
153 MirConnection* connection,
154 MirRenderSurface* render_surface,
155 std::shared_ptr<MirWaitHandle> const& creation_wait_handle,
156 std::unique_ptr<BufferDepository>&& depository,
157 std::shared_ptr<ClientPlatform> const& native_window_factory,
158 std::weak_ptr<SurfaceMap> const& map,
159 std::unique_ptr<mir::protobuf::BufferStream>&& protobuf_bs,
160 std::shared_ptr<PerfReport> const& perf_report,
161 std::string const& surface_name,
162 geometry::Size ideal_size);
163
142 void process_buffer(protobuf::Buffer const& buffer);164 void process_buffer(protobuf::Buffer const& buffer);
143 void process_buffer(protobuf::Buffer const& buffer, std::unique_lock<std::mutex>&);165 void process_buffer(protobuf::Buffer const& buffer, std::unique_lock<std::mutex>&);
144 MirWaitHandle* set_server_swap_interval(int i);166 MirWaitHandle* set_server_swap_interval(int i);
@@ -165,13 +187,15 @@
165187
166 std::unique_ptr<BufferDepository> buffer_depository;188 std::unique_ptr<BufferDepository> buffer_depository;
167 geometry::Size ideal_buffer_size;189 geometry::Size ideal_buffer_size;
168 size_t const nbuffers;
169 std::string error_message;190 std::string error_message;
170 std::shared_ptr<MirWaitHandle> creation_wait_handle;191 std::shared_ptr<MirWaitHandle> const creation_wait_handle;
171 std::weak_ptr<SurfaceMap> const map;192 std::weak_ptr<SurfaceMap> const map;
193<<<<<<< TREE
172 std::shared_ptr<AsyncBufferFactory> const factory;194 std::shared_ptr<AsyncBufferFactory> const factory;
173#pragma GCC diagnostic push195#pragma GCC diagnostic push
174#pragma GCC diagnostic ignored "-Wdeprecated-declarations"196#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
197=======
198>>>>>>> MERGE-SOURCE
175 MirRenderSurface* render_surface_;199 MirRenderSurface* render_surface_;
176#pragma GCC diagnostic pop200#pragma GCC diagnostic pop
177201
178202
=== modified file 'src/client/buffer_stream_configuration.cpp'
--- src/client/buffer_stream_configuration.cpp 2017-01-18 02:29:37 +0000
+++ src/client/buffer_stream_configuration.cpp 2017-03-28 00:17:49 +0000
@@ -29,6 +29,14 @@
29{29{
30}30}
3131
32mcl::BufferStreamConfiguration::BufferStreamConfiguration(
33 BufferStreamConfiguration&& from)
34 : server{from.server},
35 id{from.id},
36 protobuf_void{std::move(from.protobuf_void)}
37{
38}
39
32void mcl::BufferStreamConfiguration::on_swap_interval_set(int interval)40void mcl::BufferStreamConfiguration::on_swap_interval_set(int interval)
33{41{
34 std::unique_lock<decltype(mutex)> lock(mutex);42 std::unique_lock<decltype(mutex)> lock(mutex);
3543
=== modified file 'src/client/buffer_stream_configuration.h'
--- src/client/buffer_stream_configuration.h 2017-01-18 02:29:37 +0000
+++ src/client/buffer_stream_configuration.h 2017-03-28 00:17:49 +0000
@@ -33,6 +33,7 @@
33{33{
34public:34public:
35 BufferStreamConfiguration(rpc::DisplayServer& server, frontend::BufferStreamId id);35 BufferStreamConfiguration(rpc::DisplayServer& server, frontend::BufferStreamId id);
36 BufferStreamConfiguration(BufferStreamConfiguration&& from);
3637
37 void on_swap_interval_set(int interval);38 void on_swap_interval_set(int interval);
38 int swap_interval() const;39 int swap_interval() const;
3940
=== modified file 'src/client/buffer_vault.cpp'
--- src/client/buffer_vault.cpp 2017-01-30 08:13:20 +0000
+++ src/client/buffer_vault.cpp 2017-03-28 00:17:49 +0000
@@ -28,6 +28,7 @@
28#include "buffer_factory.h"28#include "buffer_factory.h"
29#include "buffer.h"29#include "buffer.h"
30#include <algorithm>30#include <algorithm>
31#include <experimental/optional>
31#include <boost/throw_exception.hpp>32#include <boost/throw_exception.hpp>
3233
33namespace mcl = mir::client;34namespace mcl = mir::client;
@@ -271,14 +272,30 @@
271 }272 }
272 }273 }
273274
275 auto cb = deferred_cb;
276 deferred_cb = {};
277 std::experimental::optional<decltype(promises)::value_type> buffer_promise;
278
274 if (!promises.empty())279 if (!promises.empty())
275 {280 {
276 buffers[buffer_id] = Owner::ContentProducer;281 buffers[buffer_id] = Owner::ContentProducer;
277 promises.front().set_value(buffer);282 // Satisfying a promise might call continuation code on this stack.
278 promises.pop_front();283 // We need to
279 }284 buffer_promise = std::move(promises.front());
280285 promises.pop_front();;
281 trigger_callback(std::move(lk));286 }
287
288 lk.unlock();
289
290 if (buffer_promise)
291 {
292 buffer_promise->set_value(buffer);
293 }
294 if (cb)
295 {
296 cb();
297 swap_buffers_wait_handle.result_received();
298 }
282}299}
283300
284void mcl::BufferVault::disconnected()301void mcl::BufferVault::disconnected()
285302
=== added file 'src/client/client_buffer_stream_factory.h.THIS'
--- src/client/client_buffer_stream_factory.h.THIS 1970-01-01 00:00:00 +0000
+++ src/client/client_buffer_stream_factory.h.THIS 2017-03-28 00:17:49 +0000
@@ -0,0 +1,66 @@
1/*
2 * Copyright © 2015 Canonical Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU Lesser General Public License version 3,
6 * as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authored by: Robert Carr <robert.carr@canonical.com>
17 */
18
19#ifndef MIR_CLIENT_CLIENT_BUFFER_STREAM_FACTORY_H_
20#define MIR_CLIENT_CLIENT_BUFFER_STREAM_FACTORY_H_
21
22#include "mir_protobuf.pb.h"
23
24#include "mir_toolkit/client_types.h"
25
26#include <memory>
27
28class MirConnection;
29
30namespace mir
31{
32namespace client
33{
34class ClientBufferStream;
35class BufferStream;
36class ClientBufferStreamFactory
37{
38public:
39 virtual std::shared_ptr<ClientBufferStream> make_consumer_stream(
40 MirConnection* allocating_connection,
41 protobuf::DisplayServer& server,
42 protobuf::BufferStream const& protobuf_bs,
43 std::string const& surface_name) = 0;
44 virtual std::shared_ptr<ClientBufferStream> make_producer_stream(
45 MirConnection* allocating_connection,
46 protobuf::DisplayServer& server,
47 protobuf::BufferStream const& protobuf_bs,
48 std::string const& surface_name) = 0;
49
50 // For creating buffer stream owned by client.
51 virtual ClientBufferStream* make_producer_stream(
52 MirConnection* allocating_connection,
53 protobuf::DisplayServer& server,
54 protobuf::BufferStreamParameters const& params,
55 mir_buffer_stream_callback callback, void* context) = 0;
56
57protected:
58 ClientBufferStreamFactory() = default;
59 virtual ~ClientBufferStreamFactory() = default;
60 ClientBufferStreamFactory(const ClientBufferStreamFactory&) = delete;
61 ClientBufferStreamFactory& operator=(const ClientBufferStreamFactory&) = delete;
62};
63}
64}
65
66#endif // MIR_CLIENT_CLIENT_BUFFER_STREAM_FACTORY_H_
067
=== modified file 'src/client/connection_configuration.h'
--- src/client/connection_configuration.h 2017-02-15 14:45:41 +0000
+++ src/client/connection_configuration.h 2017-03-28 00:17:49 +0000
@@ -37,6 +37,11 @@
37class Logger;37class Logger;
38}38}
3939
40namespace dispatch
41{
42class ActionQueue;
43}
44
40namespace client45namespace client
41{46{
42namespace rpc47namespace rpc
@@ -51,11 +56,17 @@
51class EventHandlerRegister;56class EventHandlerRegister;
52class AsyncBufferFactory;57class AsyncBufferFactory;
5358
59namespace rpc
60{
61class MirBasicRpcChannel;
62}
63
54class ConnectionConfiguration64class ConnectionConfiguration
55{65{
56public:66public:
57 virtual ~ConnectionConfiguration() = default;67 virtual ~ConnectionConfiguration() = default;
5868
69 virtual std::shared_ptr<dispatch::ActionQueue> the_delayed_queue() = 0;
59 virtual std::shared_ptr<ConnectionSurfaceMap> the_surface_map() = 0;70 virtual std::shared_ptr<ConnectionSurfaceMap> the_surface_map() = 0;
60 virtual std::shared_ptr<mir::client::rpc::MirBasicRpcChannel> the_rpc_channel() = 0;71 virtual std::shared_ptr<mir::client::rpc::MirBasicRpcChannel> the_rpc_channel() = 0;
61 virtual std::shared_ptr<mir::logging::Logger> the_logger() = 0;72 virtual std::shared_ptr<mir::logging::Logger> the_logger() = 0;
6273
=== modified file 'src/client/connection_surface_map.cpp'
--- src/client/connection_surface_map.cpp 2017-03-14 04:41:33 +0000
+++ src/client/connection_surface_map.cpp 2017-03-28 00:17:49 +0000
@@ -20,26 +20,78 @@
20#include "mir_surface.h"20#include "mir_surface.h"
21#include "presentation_chain.h"21#include "presentation_chain.h"
2222
23#include "mir/dispatch/action_queue.h"
24
23#include <boost/throw_exception.hpp>25#include <boost/throw_exception.hpp>
24#include <sstream>26#include <sstream>
2527
26namespace mcl=mir::client;28namespace mcl=mir::client;
27namespace mf=mir::frontend;29namespace mf=mir::frontend;
2830
31<<<<<<< TREE
29using mir::client::ConnectionSurfaceMap;32using mir::client::ConnectionSurfaceMap;
30using mir::frontend::SurfaceId;33using mir::frontend::SurfaceId;
31using mir::frontend::BufferStreamId;34using mir::frontend::BufferStreamId;
3235
33std::shared_ptr<MirWindow> ConnectionSurfaceMap::surface(SurfaceId id) const36std::shared_ptr<MirWindow> ConnectionSurfaceMap::surface(SurfaceId id) const
34{37=======
38mcl::ConnectionSurfaceMap::ConnectionSurfaceMap(
39 std::shared_ptr<dispatch::ActionQueue> delayed_queue)
40 : delayed_queue{delayed_queue}
41{
42}
43
44void mcl::ConnectionSurfaceMap::with_surface_do(
45 mf::SurfaceId surface_id, std::function<void(MirSurface*)> const& exec) const
46>>>>>>> MERGE-SOURCE
47{
48 {
49 std::lock_guard<decltype(reserved_guard)> lock{reserved_guard};
50 auto const it = surface_reservations.find(surface_id);
51 if (it != surface_reservations.end())
52 {
53 it->second.push_back(exec);
54 return;
55 }
56 }
57
35 std::shared_lock<decltype(guard)> lk(guard);58 std::shared_lock<decltype(guard)> lk(guard);
36 auto const found = surfaces.find(id);59 auto const found = surfaces.find(id);
37 return found != surfaces.end() ? found->second : nullptr;60 return found != surfaces.end() ? found->second : nullptr;
38}61}
3962
63<<<<<<< TREE
40void mcl::ConnectionSurfaceMap::insert(mf::SurfaceId surface_id, std::shared_ptr<MirWindow> const& surface)64void mcl::ConnectionSurfaceMap::insert(mf::SurfaceId surface_id, std::shared_ptr<MirWindow> const& surface)
65=======
66void mcl::ConnectionSurfaceMap::reserve(mf::SurfaceId surface_id)
67{
68 std::lock_guard<decltype(reserved_guard)> lock{reserved_guard};
69 surface_reservations[surface_id] = {};
70}
71
72
73
74void mcl::ConnectionSurfaceMap::insert(mf::SurfaceId surface_id, std::shared_ptr<MirSurface> const& surface)
75>>>>>>> MERGE-SOURCE
41{76{
42 std::lock_guard<decltype(guard)> lk(guard);77 std::lock_guard<decltype(guard)> lk(guard);
78 std::lock_guard<decltype(reserved_guard)> lock{reserved_guard};
79 for (auto& func : surface_reservations[surface_id])
80 {
81 delayed_queue->enqueue(
82 [this, surface_id, exec = std::move(func)]()
83 {
84 std::shared_lock<decltype(guard)> lk(guard);
85 auto const it = surfaces.find(surface_id);
86 if (it != surfaces.end())
87 {
88 auto const surface = it->second;
89 lk.unlock();
90 exec(surface.get());
91 }
92 });
93 }
94 surface_reservations.erase(surface_id);
43 surfaces[surface_id] = surface;95 surfaces[surface_id] = surface;
44}96}
4597
4698
=== modified file 'src/client/connection_surface_map.h'
--- src/client/connection_surface_map.h 2017-03-14 04:41:33 +0000
+++ src/client/connection_surface_map.h 2017-03-28 00:17:49 +0000
@@ -23,19 +23,43 @@
2323
24#include <shared_mutex>24#include <shared_mutex>
25#include <unordered_map>25#include <unordered_map>
26#include <vector>
2627
27class MirPresentationChain;28class MirPresentationChain;
28class MirRenderSurface;29class MirRenderSurface;
29namespace mir30namespace mir
30{31{
32namespace dispatch
33{
34class ActionQueue;
35}
31namespace client36namespace client
32{37{
33class MirBuffer;38class MirBuffer;
34class ConnectionSurfaceMap : public SurfaceMap39class ConnectionSurfaceMap : public SurfaceMap
35{40{
36public:41public:
42<<<<<<< TREE
37 virtual std::shared_ptr<MirWindow> surface(frontend::SurfaceId) const override;43 virtual std::shared_ptr<MirWindow> surface(frontend::SurfaceId) const override;
38 void insert(frontend::SurfaceId surface_id, std::shared_ptr<MirWindow> const& surface);44 void insert(frontend::SurfaceId surface_id, std::shared_ptr<MirWindow> const& surface);
45=======
46 ConnectionSurfaceMap(std::shared_ptr<dispatch::ActionQueue> delayed_queue);
47
48 void with_surface_do(frontend::SurfaceId surface_id, std::function<void(MirSurface*)> const& exec) const override;
49 /**
50 * Notify the surface map that a surface will be constructed.
51 *
52 * After this call, calls to with_surface_do(surface_id, functor) will succeed, but defer execution
53 * of functor until a subsequent call to insert(surface_id, surf).
54 *
55 * Any functor queued will be executed on the delayed queue, not in the stack of
56 * the insert() call.
57 *
58 * \param [in] surface_id ID of the surface about to be created.
59 */
60 void reserve(frontend::SurfaceId surface_id);
61 void insert(frontend::SurfaceId surface_id, std::shared_ptr<MirSurface> const& surface);
62>>>>>>> MERGE-SOURCE
39 void erase(frontend::SurfaceId surface_id);63 void erase(frontend::SurfaceId surface_id);
4064
41 virtual std::shared_ptr<MirBufferStream> stream(frontend::BufferStreamId) const override;65 virtual std::shared_ptr<MirBufferStream> stream(frontend::BufferStreamId) const override;
@@ -57,8 +81,16 @@
57 std::shared_ptr<MirRenderSurface> render_surface(void* render_surface_key) const;81 std::shared_ptr<MirRenderSurface> render_surface(void* render_surface_key) const;
58#pragma GCC diagnostic pop82#pragma GCC diagnostic pop
59private:83private:
84 std::shared_ptr<dispatch::ActionQueue> const delayed_queue;
85
60 std::shared_timed_mutex mutable guard;86 std::shared_timed_mutex mutable guard;
87<<<<<<< TREE
61 std::unordered_map<frontend::SurfaceId, std::shared_ptr<MirWindow>> surfaces;88 std::unordered_map<frontend::SurfaceId, std::shared_ptr<MirWindow>> surfaces;
89=======
90 std::unordered_map<frontend::SurfaceId, std::shared_ptr<MirSurface>> surfaces;
91 std::mutex mutable reserved_guard;
92 std::unordered_map<frontend::SurfaceId, std::vector<std::function<void(MirSurface*)>>> mutable surface_reservations;
93>>>>>>> MERGE-SOURCE
62 std::shared_timed_mutex mutable stream_guard;94 std::shared_timed_mutex mutable stream_guard;
63 std::unordered_map<frontend::BufferStreamId, std::shared_ptr<MirBufferStream>> streams;95 std::unordered_map<frontend::BufferStreamId, std::shared_ptr<MirBufferStream>> streams;
64 std::unordered_map<frontend::BufferStreamId, std::shared_ptr<MirPresentationChain>> chains;96 std::unordered_map<frontend::BufferStreamId, std::shared_ptr<MirPresentationChain>> chains;
6597
=== added file 'src/client/default_client_buffer_stream_factory.cpp.THIS'
--- src/client/default_client_buffer_stream_factory.cpp.THIS 1970-01-01 00:00:00 +0000
+++ src/client/default_client_buffer_stream_factory.cpp.THIS 2017-03-28 00:17:49 +0000
@@ -0,0 +1,87 @@
1/*
2 * Copyright © 2015 Canonical Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU Lesser General Public License version 3,
6 * as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authored by: Robert Carr <robert.carr@canonical.com>
17 */
18#include "default_client_buffer_stream_factory.h"
19#include "buffer_stream.h"
20#include "perf_report.h"
21#include "logging/perf_report.h"
22#include "lttng/perf_report.h"
23
24namespace mcl = mir::client;
25namespace ml = mir::logging;
26namespace mp = mir::protobuf;
27
28namespace
29{
30
31std::shared_ptr<mcl::PerfReport>
32make_perf_report(std::shared_ptr<ml::Logger> const& logger)
33{
34 // TODO: It seems strange that this directly uses getenv
35 const char* report_target = getenv("MIR_CLIENT_PERF_REPORT");
36 if (report_target && !strncmp(report_target, "log", strlen(report_target)))
37 {
38 return std::make_shared<mcl::logging::PerfReport>(logger);
39 }
40 else if (report_target && !strncmp(report_target, "lttng", strlen(report_target)))
41 {
42 return std::make_shared<mcl::lttng::PerfReport>();
43 }
44 else
45 {
46 return std::make_shared<mcl::NullPerfReport>();
47 }
48}
49
50}
51
52mcl::DefaultClientBufferStreamFactory::DefaultClientBufferStreamFactory(
53 std::shared_ptr<mcl::ClientPlatform> const& client_platform,
54 std::shared_ptr<ml::Logger> const& logger)
55 : client_platform(client_platform),
56 logger(logger)
57{
58}
59
60std::shared_ptr<mcl::ClientBufferStream> mcl::DefaultClientBufferStreamFactory::make_consumer_stream(
61 MirConnection* allocating_connection,
62 mp::DisplayServer& server,
63 mp::BufferStream const& protobuf_bs,
64 std::string const& surface_name)
65{
66 return std::make_shared<mcl::BufferStream>(allocating_connection, server, mcl::BufferStreamMode::Consumer, client_platform, protobuf_bs, make_perf_report(logger), surface_name);
67}
68
69std::shared_ptr<mcl::ClientBufferStream> mcl::DefaultClientBufferStreamFactory::make_producer_stream(
70 MirConnection* allocating_connection,
71 mp::DisplayServer& server,
72 mp::BufferStream const& protobuf_bs,
73 std::string const& surface_name)
74{
75 return std::make_shared<mcl::BufferStream>(allocating_connection, server, mcl::BufferStreamMode::Producer, client_platform, protobuf_bs, make_perf_report(logger), surface_name);
76}
77
78
79mcl::ClientBufferStream* mcl::DefaultClientBufferStreamFactory::make_producer_stream(
80 MirConnection* allocating_connection,
81 mp::DisplayServer& server,
82 mp::BufferStreamParameters const& params,
83 mir_buffer_stream_callback callback,
84 void* context)
85{
86 return new mcl::BufferStream(allocating_connection, server, client_platform, params, make_perf_report(logger), callback, context);
87}
088
=== added file 'src/client/default_client_buffer_stream_factory.h.THIS'
--- src/client/default_client_buffer_stream_factory.h.THIS 1970-01-01 00:00:00 +0000
+++ src/client/default_client_buffer_stream_factory.h.THIS 2017-03-28 00:17:49 +0000
@@ -0,0 +1,70 @@
1/*
2 * Copyright © 2015 Canonical Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU Lesser General Public License version 3,
6 * as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authored by: Robert Carr <robert.carr@canonical.com>
17 */
18
19#ifndef MIR_CLIENT_DEFAULT_CLIENT_BUFFER_STREAM_FACTORY_H_
20#define MIR_CLIENT_DEFAULT_CLIENT_BUFFER_STREAM_FACTORY_H_
21
22#include "client_buffer_stream_factory.h"
23
24class MirConnection;
25
26namespace mir
27{
28namespace logging
29{
30class Logger;
31}
32namespace client
33{
34class ClientBufferFactory;
35class ClientPlatform;
36
37class DefaultClientBufferStreamFactory : public ClientBufferStreamFactory
38{
39public:
40 DefaultClientBufferStreamFactory(
41 std::shared_ptr<ClientPlatform> const& native_window_factory,
42 std::shared_ptr<logging::Logger> const& logger);
43 virtual ~DefaultClientBufferStreamFactory() = default;
44
45 std::shared_ptr<ClientBufferStream> make_consumer_stream(
46 MirConnection* allocating_connection,
47 protobuf::DisplayServer& server,
48 protobuf::BufferStream const& protobuf_bs,
49 std::string const& surface_name) override;
50 std::shared_ptr<ClientBufferStream> make_producer_stream(
51 MirConnection* allocating_connection,
52 protobuf::DisplayServer& server,
53 protobuf::BufferStream const& protobuf_bs,
54 std::string const& surface_name) override;
55
56 ClientBufferStream* make_producer_stream(
57 MirConnection* allocating_connection,
58 protobuf::DisplayServer& server,
59 protobuf::BufferStreamParameters const& params,
60 mir_buffer_stream_callback callback, void* context) override;
61
62private:
63 std::shared_ptr<ClientPlatform> const client_platform;
64 std::shared_ptr<logging::Logger> const logger;
65
66};
67}
68}
69
70#endif // MIR_CLIENT_DEFAULT_CLIENT_BUFFER_STREAM_FACTORY_H_
071
=== modified file 'src/client/default_connection_configuration.cpp'
--- src/client/default_connection_configuration.cpp 2017-02-15 14:45:41 +0000
+++ src/client/default_connection_configuration.cpp 2017-03-28 00:17:49 +0000
@@ -37,8 +37,10 @@
37#include "probing_client_platform_factory.h"37#include "probing_client_platform_factory.h"
38#include "mir_event_distributor.h"38#include "mir_event_distributor.h"
39#include "buffer_factory.h"39#include "buffer_factory.h"
40#include "mir/dispatch/action_queue.h"
4041
41namespace mcl = mir::client;42namespace mcl = mir::client;
43namespace md = mir::dispatch;
4244
43namespace45namespace
44{46{
@@ -53,12 +55,23 @@
53{55{
54}56}
5557
58std::shared_ptr<md::ActionQueue>
59mcl::DefaultConnectionConfiguration::the_delayed_queue()
60{
61 return delayed_queue(
62 []()
63 {
64 return std::make_shared<md::ActionQueue>();
65 });
66}
67
56std::shared_ptr<mcl::ConnectionSurfaceMap>68std::shared_ptr<mcl::ConnectionSurfaceMap>
57mcl::DefaultConnectionConfiguration::the_surface_map()69mcl::DefaultConnectionConfiguration::the_surface_map()
58{70{
59 return surface_map([]71 return surface_map(
72 [this]()
60 {73 {
61 return std::make_shared<mcl::ConnectionSurfaceMap>();74 return std::make_shared<mcl::ConnectionSurfaceMap>(the_delayed_queue());
62 });75 });
63}76}
6477
6578
=== modified file 'src/client/default_connection_configuration.h'
--- src/client/default_connection_configuration.h 2017-02-15 14:45:41 +0000
+++ src/client/default_connection_configuration.h 2017-03-28 00:17:49 +0000
@@ -50,6 +50,7 @@
50public:50public:
51 DefaultConnectionConfiguration(std::string const& socket_file);51 DefaultConnectionConfiguration(std::string const& socket_file);
5252
53 std::shared_ptr<dispatch::ActionQueue> the_delayed_queue() override;
53 std::shared_ptr<ConnectionSurfaceMap> the_surface_map() override;54 std::shared_ptr<ConnectionSurfaceMap> the_surface_map() override;
54 std::shared_ptr<mir::client::rpc::MirBasicRpcChannel> the_rpc_channel() override;55 std::shared_ptr<mir::client::rpc::MirBasicRpcChannel> the_rpc_channel() override;
55 std::shared_ptr<mir::logging::Logger> the_logger() override;56 std::shared_ptr<mir::logging::Logger> the_logger() override;
@@ -69,6 +70,7 @@
69 virtual std::shared_ptr<input::receiver::InputReceiverReport> the_input_receiver_report();70 virtual std::shared_ptr<input::receiver::InputReceiverReport> the_input_receiver_report();
7071
71protected:72protected:
73 CachedPtr<dispatch::ActionQueue> delayed_queue;
72 CachedPtr<mir::client::rpc::MirBasicRpcChannel> rpc_channel;74 CachedPtr<mir::client::rpc::MirBasicRpcChannel> rpc_channel;
73 CachedPtr<mir::logging::Logger> logger;75 CachedPtr<mir::logging::Logger> logger;
74 CachedPtr<ClientPlatformFactory> client_platform_factory;76 CachedPtr<ClientPlatformFactory> client_platform_factory;
7577
=== modified file 'src/client/error_render_surface.cpp'
--- src/client/error_render_surface.cpp 2017-01-18 02:29:37 +0000
+++ src/client/error_render_surface.cpp 2017-03-28 00:17:49 +0000
@@ -54,10 +54,7 @@
54 return false;54 return false;
55}55}
5656
57MirBufferStream* mcl::ErrorRenderSurface::get_buffer_stream(57void mcl::ErrorRenderSurface::get_buffer_stream(int, int, MirPixelFormat, MirBufferUsage, mir_buffer_stream_callback, void*)
58 int /*width*/, int /*height*/,
59 MirPixelFormat /*format*/,
60 MirBufferUsage /*buffer_usage*/)
61{58{
62 BOOST_THROW_EXCEPTION(std::runtime_error(error));59 BOOST_THROW_EXCEPTION(std::runtime_error(error));
63}60}
6461
=== modified file 'src/client/error_render_surface.h'
--- src/client/error_render_surface.h 2017-03-10 19:47:57 +0000
+++ src/client/error_render_surface.h 2017-03-28 00:17:49 +0000
@@ -39,10 +39,13 @@
39 void set_size(mir::geometry::Size) override;39 void set_size(mir::geometry::Size) override;
40 bool valid() const override;40 bool valid() const override;
41 char const* get_error_message() const override;41 char const* get_error_message() const override;
42 MirBufferStream* get_buffer_stream(42 void get_buffer_stream(
43 int width, int height,43 int width,
44 int height,
44 MirPixelFormat format,45 MirPixelFormat format,
45 MirBufferUsage buffer_usage) override;46 MirBufferUsage buffer_usage,
47 mir_buffer_stream_callback callback,
48 void* context) override;
46 MirPresentationChain* get_presentation_chain() override;49 MirPresentationChain* get_presentation_chain() override;
47private:50private:
48 std::string const error;51 std::string const error;
4952
=== modified file 'src/client/mir_buffer_stream_api.cpp'
--- src/client/mir_buffer_stream_api.cpp 2017-01-24 07:37:03 +0000
+++ src/client/mir_buffer_stream_api.cpp 2017-03-28 00:17:49 +0000
@@ -30,25 +30,14 @@
30#include "mir/uncaught.h"30#include "mir/uncaught.h"
31#include "mir/require.h"31#include "mir/require.h"
3232
33#include "synchronous_helper.h"
34
33#include <stdexcept>35#include <stdexcept>
34#include <boost/throw_exception.hpp>36#include <boost/throw_exception.hpp>
3537
36namespace mcl = mir::client;38namespace mcl = mir::client;
37namespace mp = mir::protobuf;39namespace mp = mir::protobuf;
3840
39namespace
40{
41// assign_result is compatible with all 2-parameter callbacks
42void assign_result(void* result, void** context)
43{
44 if (context)
45 *context = result;
46}
47
48}
49
50
51
52MirWaitHandle* mir_connection_create_buffer_stream(MirConnection *connection,41MirWaitHandle* mir_connection_create_buffer_stream(MirConnection *connection,
53 int width, int height,42 int width, int height,
54 MirPixelFormat format,43 MirPixelFormat format,
@@ -72,9 +61,20 @@
72 MirBufferUsage buffer_usage)61 MirBufferUsage buffer_usage)
73try62try
74{63{
64<<<<<<< TREE
75 MirBufferStream *stream = nullptr;65 MirBufferStream *stream = nullptr;
76 mir_connection_create_buffer_stream(connection, width, height, format, buffer_usage,66 mir_connection_create_buffer_stream(connection, width, height, format, buffer_usage,
77 reinterpret_cast<MirBufferStreamCallback>(assign_result), &stream)->wait_for_all();67 reinterpret_cast<MirBufferStreamCallback>(assign_result), &stream)->wait_for_all();
68=======
69 MirBufferStream* stream = nullptr;
70 make_synchronous_call(
71 connection,
72 mir_connection_create_buffer_stream,
73 connection,
74 width, height, format, buffer_usage,
75 &assign_result<MirBufferStream>,
76 &stream);
77>>>>>>> MERGE-SOURCE
78 return stream;78 return stream;
79}79}
80catch (std::exception const& ex)80catch (std::exception const& ex)
@@ -94,7 +94,12 @@
9494
95void mir_buffer_stream_release_sync(MirBufferStream *buffer_stream)95void mir_buffer_stream_release_sync(MirBufferStream *buffer_stream)
96{96{
97 mir_buffer_stream_release(buffer_stream, nullptr, nullptr)->wait_for_all();97 make_synchronous_call(
98 buffer_stream->connection(),
99 &mir_buffer_stream_release,
100 buffer_stream,
101 &assign_result<MirBufferStream>,
102 static_cast<void*>(nullptr));
98}103}
99104
100void mir_buffer_stream_get_current_buffer(MirBufferStream* buffer_stream, MirNativeBuffer** buffer_package_out)105void mir_buffer_stream_get_current_buffer(MirBufferStream* buffer_stream, MirNativeBuffer** buffer_package_out)
@@ -132,6 +137,7 @@
132}137}
133138
134void mir_buffer_stream_swap_buffers_sync(MirBufferStream* buffer_stream)139void mir_buffer_stream_swap_buffers_sync(MirBufferStream* buffer_stream)
140<<<<<<< TREE
135try141try
136{142{
137 buffer_stream->swap_buffers_sync();143 buffer_stream->swap_buffers_sync();
@@ -139,6 +145,15 @@
139catch (std::exception const& ex)145catch (std::exception const& ex)
140{146{
141 MIR_LOG_UNCAUGHT_EXCEPTION(ex);147 MIR_LOG_UNCAUGHT_EXCEPTION(ex);
148=======
149{
150 make_synchronous_call(
151 buffer_stream->connection(),
152 &mir_buffer_stream_swap_buffers,
153 buffer_stream,
154 &assign_result<MirBufferStream>,
155 static_cast<void*>(nullptr));
156>>>>>>> MERGE-SOURCE
142}157}
143158
144bool mir_buffer_stream_get_graphics_region(159bool mir_buffer_stream_get_graphics_region(
145160
=== modified file 'src/client/mir_connection.cpp'
--- src/client/mir_connection.cpp 2017-03-21 05:51:47 +0000
+++ src/client/mir_connection.cpp 2017-03-28 00:17:49 +0000
@@ -27,8 +27,12 @@
27#include "mir/client_platform.h"27#include "mir/client_platform.h"
28#include "mir/client_platform_factory.h"28#include "mir/client_platform_factory.h"
29#include "rpc/mir_basic_rpc_channel.h"29#include "rpc/mir_basic_rpc_channel.h"
30#include "rpc/mir_protobuf_rpc_channel.h"
30#include "mir/dispatch/dispatchable.h"31#include "mir/dispatch/dispatchable.h"
32#include "mir/dispatch/multiplexing_dispatchable.h"
31#include "mir/dispatch/threaded_dispatcher.h"33#include "mir/dispatch/threaded_dispatcher.h"
34#include "mir/dispatch/multiplexing_dispatchable.h"
35#include "mir/dispatch/action_queue.h"
32#include "mir/input/input_devices.h"36#include "mir/input/input_devices.h"
33#include "connection_configuration.h"37#include "connection_configuration.h"
34#include "display_configuration.h"38#include "display_configuration.h"
@@ -53,6 +57,7 @@
53#include "mir/logging/logger.h"57#include "mir/logging/logger.h"
54#include "mir/platform_message.h"58#include "mir/platform_message.h"
55#include "mir_error.h"59#include "mir_error.h"
60#include "mir/require.h"
5661
57#include <algorithm>62#include <algorithm>
58#include <cstddef>63#include <cstddef>
@@ -63,6 +68,7 @@
63#include <boost/throw_exception.hpp>68#include <boost/throw_exception.hpp>
6469
65namespace mcl = mir::client;70namespace mcl = mir::client;
71namespace mclr = mir::client::rpc;
66namespace md = mir::dispatch;72namespace md = mir::dispatch;
67namespace mircv = mir::input::receiver;73namespace mircv = mir::input::receiver;
68namespace mev = mir::events;74namespace mev = mir::events;
@@ -309,8 +315,13 @@
309{315{
310}316}
311317
318MirConnection::MirConnection(mir::client::ConnectionConfiguration& conf) :
319 MirConnection(conf, DispatchType::automatic)
320{
321}
322
312MirConnection::MirConnection(323MirConnection::MirConnection(
313 mir::client::ConnectionConfiguration& conf) :324 mir::client::ConnectionConfiguration& conf, DispatchType dispatch) :
314 deregisterer{this},325 deregisterer{this},
315 surface_map(conf.the_surface_map()),326 surface_map(conf.the_surface_map()),
316 buffer_factory(conf.the_buffer_factory()),327 buffer_factory(conf.the_buffer_factory()),
@@ -330,13 +341,26 @@
330 display_configuration(conf.the_display_configuration()),341 display_configuration(conf.the_display_configuration()),
331 input_devices{conf.the_input_devices()},342 input_devices{conf.the_input_devices()},
332 lifecycle_control(conf.the_lifecycle_control()),343 lifecycle_control(conf.the_lifecycle_control()),
344 event_handler_register(conf.the_event_handler_register()),
345 dispatcher{std::make_shared<md::MultiplexingDispatchable>()},
346 eventloop{dispatch == DispatchType::automatic ?
347 std::make_unique<md::ThreadedDispatcher>("RPC Dispatch", dispatcher) :
348 nullptr
349 },
333 ping_handler{conf.the_ping_handler()},350 ping_handler{conf.the_ping_handler()},
351 pong_callback(google::protobuf::NewPermanentCallback(&google::protobuf::DoNothing)),
352 delayed_queue{conf.the_delayed_queue()},
334 error_handler{conf.the_error_handler()},353 error_handler{conf.the_error_handler()},
335 event_handler_register(conf.the_event_handler_register()),
336 pong_callback(google::protobuf::NewPermanentCallback(&google::protobuf::DoNothing)),
337 eventloop{new md::ThreadedDispatcher{"RPC Thread", std::dynamic_pointer_cast<md::Dispatchable>(channel)}},
338 nbuffers(get_nbuffers_from_env())354 nbuffers(get_nbuffers_from_env())
339{355{
356 dispatcher->add_watch(channel);
357 dispatcher->add_watch(delayed_queue);
358 if (eventloop)
359 {
360 // Need a second thread ensure RPC is not blocked if the delayed_queue blocks,
361 // as it does when waiting for surface creation.
362 eventloop->add_thread();
363 }
340 connect_result->set_error("connect not called");364 connect_result->set_error("connect not called");
341 {365 {
342 std::lock_guard<std::mutex> lock(connection_guard);366 std::lock_guard<std::mutex> lock(connection_guard);
@@ -419,38 +443,41 @@
419 if (request_it == surface_requests.end())443 if (request_it == surface_requests.end())
420 return;444 return;
421445
422 auto surface_proto = request->response; 446 auto surface_proto = request->response;
423 auto callback = request->cb;
424 auto context = request->context;
425 auto const& spec = request->spec;447 auto const& spec = request->spec;
426 std::string name{spec.surface_name.is_set() ?448 std::string name{spec.surface_name.is_set() ?
427 spec.surface_name.value() : ""};449 spec.surface_name.value() : ""};
450 surface_map->reserve(mf::SurfaceId{surface_proto->id().value()});
428451
429 std::shared_ptr<MirBufferStream> default_stream {nullptr};452 mcl::NoTLSFuture<std::unique_ptr<mcl::BufferStream>> default_stream;
430 if (surface_proto->buffer_stream().has_id())453 if (surface_proto->buffer_stream().has_id())
431 {454 {
432 try455 try
433 {456 {
434 default_stream = std::make_shared<mcl::BufferStream>(457 default_stream = mcl::BufferStream::create(
435 this, nullptr, request->wh, server, platform, surface_map, buffer_factory,458 this, nullptr, request->wh, server, platform, surface_map, buffer_factory,
436 surface_proto->buffer_stream(), make_perf_report(logger), name,459 surface_proto->buffer_stream(), make_perf_report(logger), name,
437 mir::geometry::Size{surface_proto->width(), surface_proto->height()}, nbuffers);460 mir::geometry::Size{surface_proto->width(), surface_proto->height()},
438 surface_map->insert(default_stream->rpc_id(), default_stream);461 nbuffers);
439 }462 }
440 catch (std::exception const& error)463 catch (std::exception const& error)
441 {464 {
442 if (!surface_proto->has_error())465 if (!surface_proto->has_error())
443 surface_proto->set_error(error.what());466 surface_proto->set_error(error.what());
444 // Clean up surface_proto's direct fds; BufferStream has cleaned up any owned by
445 // surface_proto->buffer_stream()
446 for (auto i = 0; i < surface_proto->fd_size(); i++)
447 ::close(surface_proto->fd(i));
448 }467 }
449 }468 }
450469
470<<<<<<< TREE
451 std::shared_ptr<MirWindow> surf {nullptr};471 std::shared_ptr<MirWindow> surf {nullptr};
472=======
473>>>>>>> MERGE-SOURCE
452 if (surface_proto->has_error() || !surface_proto->has_id())474 if (surface_proto->has_error() || !surface_proto->has_id())
453 {475 {
476 // Clean up surface_proto's direct fds; BufferStream has cleaned up any owned by
477 // surface_proto->buffer_stream()
478 for (auto i = 0; i < surface_proto->fd_size(); i++)
479 ::close(surface_proto->fd(i));
480
454 std::string reason;481 std::string reason;
455 if (surface_proto->has_error())482 if (surface_proto->has_error())
456 reason += surface_proto->error();483 reason += surface_proto->error();
@@ -459,19 +486,63 @@
459 if (!surface_proto->has_id()) 486 if (!surface_proto->has_id())
460 reason += "Server assigned surface no id";487 reason += "Server assigned surface no id";
461 auto id = next_error_id(lock);488 auto id = next_error_id(lock);
489<<<<<<< TREE
462 surf = std::make_shared<MirWindow>(reason, this, id, request->wh);490 surf = std::make_shared<MirWindow>(reason, this, id, request->wh);
491=======
492 auto surf = std::make_shared<MirSurface>(reason, this, id, request->wh);
493>>>>>>> MERGE-SOURCE
463 surface_map->insert(id, surf);494 surface_map->insert(id, surf);
495
496 request->cb(surf.get(), request->context);
497 request->wh->result_received();
498 }
499 else if (default_stream.valid())
500 {
501 default_stream.then(
502 [this, request = *request_it](auto&& resolved_stream) -> void
503 {
504 std::shared_ptr<MirSurface> surf;
505 std::shared_ptr<MirBufferStream> stream;
506 try
507 {
508 stream = resolved_stream.get();
509 surface_map->insert(stream->rpc_id(), stream);
510 }
511 catch (std::exception const& error)
512 {
513 request->response->set_error(error.what());
514 }
515
516 surf = std::make_shared<MirSurface>(
517 this,
518 server,
519 &debug,
520 stream,
521 input_platform,
522 request->spec,
523 *request->response,
524 request->wh);
525 surface_map->insert(mf::SurfaceId{request->response->id().value()}, surf);
526
527 request->cb(surf.get(), request->context);
528 request->wh->result_received();
529 }).detach();
464 }530 }
465 else531 else
466 {532 {
533<<<<<<< TREE
467 surf = std::make_shared<MirWindow>(534 surf = std::make_shared<MirWindow>(
468 this, server, &debug, default_stream, spec, *surface_proto, request->wh);535 this, server, &debug, default_stream, spec, *surface_proto, request->wh);
536=======
537 auto surf = std::make_shared<MirSurface>(
538 this, server, &debug, nullptr, input_platform, spec, *surface_proto, request->wh);
539>>>>>>> MERGE-SOURCE
469 surface_map->insert(mf::SurfaceId{surface_proto->id().value()}, surf);540 surface_map->insert(mf::SurfaceId{surface_proto->id().value()}, surf);
541
542 request->cb(surf.get(), request->context);
543 request->wh->result_received();
470 }544 }
471545
472 callback(surf.get(), context);
473 request->wh->result_received();
474
475 surface_requests.erase(request_it);546 surface_requests.erase(request_it);
476}547}
477548
@@ -515,17 +586,17 @@
515586
516void MirConnection::released(StreamRelease data)587void MirConnection::released(StreamRelease data)
517{588{
589 {
590 std::unique_lock<decltype(mutex)> lk(mutex);
591 if (data.rs)
592 surface_map->erase(data.rs);
593 surface_map->erase(mf::BufferStreamId(data.rpc_id));
594 }
595
518 if (data.callback)596 if (data.callback)
519 data.callback(data.stream, data.context);597 data.callback(data.stream, data.context);
520 if (data.handle)598 if (data.handle)
521 data.handle->result_received();599 data.handle->result_received();
522
523 {
524 std::unique_lock<decltype(mutex)> lk(mutex);
525 if (data.rs)
526 surface_map->erase(data.rs);
527 surface_map->erase(mf::BufferStreamId(data.rpc_id));
528 }
529}600}
530601
531void MirConnection::released(SurfaceRelease data)602void MirConnection::released(SurfaceRelease data)
@@ -701,6 +772,36 @@
701 return &disconnect_wait_handle;772 return &disconnect_wait_handle;
702}773}
703774
775mir::Fd MirConnection::watch_fd() const
776{
777 return eventloop ? mir::Fd{} : dispatcher->watch_fd();
778}
779
780void MirConnection::dispatch()
781{
782 mir::require(!eventloop);
783
784 dispatcher->dispatch(md::FdEvent::readable);
785}
786
787void MirConnection::add_dispatchee(std::shared_ptr<mir::dispatch::Dispatchable> const& dispatchee)
788{
789 dispatcher->add_watch(dispatchee);
790 if (eventloop)
791 {
792 eventloop->add_thread();
793 }
794}
795
796void MirConnection::remove_dispatchee(std::shared_ptr<mir::dispatch::Dispatchable> const& dispatchee)
797{
798 dispatcher->remove_watch(dispatchee);
799 if (eventloop)
800 {
801 eventloop->remove_thread();
802 }
803}
804
704void MirConnection::done_platform_operation(805void MirConnection::done_platform_operation(
705 MirPlatformOperationCallback callback, void* context)806 MirPlatformOperationCallback callback, void* context)
706{807{
@@ -880,16 +981,34 @@
880981
881 try982 try
882 {983 {
883 auto stream = std::make_shared<mcl::BufferStream>(984 auto future_stream = mcl::BufferStream::create(
884 this, request->rs, request->wh, server, platform, surface_map, buffer_factory,985 this,
885 *protobuf_bs, make_perf_report(logger), std::string{},986 request->rs,
886 mir::geometry::Size{request->parameters.width(), request->parameters.height()}, nbuffers);987 request->wh,
887 surface_map->insert(mf::BufferStreamId(protobuf_bs->id().value()), stream);988 server,
888989 platform,
889 if (request->mbs_callback)990 surface_map,
890 request->mbs_callback(stream.get(), request->context);991 buffer_factory,
891992 *protobuf_bs,
892 request->wh->result_received();993 make_perf_report(logger),
994 std::string{},
995 mir::geometry::Size{request->parameters.width(), request->parameters.height()},
996 nbuffers);
997
998 future_stream.then(
999 [this, request](auto&& resolved_stream) -> void
1000 {
1001 std::shared_ptr<mcl::BufferStream> stream{resolved_stream.get()};
1002 auto& protobuf_bs = request->response;
1003
1004 surface_map->insert(mf::BufferStreamId(protobuf_bs->id().value()), stream);
1005
1006 request->mbs_callback(
1007 static_cast<MirBufferStream*>(stream.get()),
1008 request->context);
1009
1010 request->wh->result_received();
1011 }).detach();
893 }1012 }
894 catch (std::exception const& error)1013 catch (std::exception const& error)
895 {1014 {
@@ -939,17 +1058,25 @@
939 return request->wh.get();1058 return request->wh.get();
940}1059}
9411060
942std::shared_ptr<mir::client::BufferStream> MirConnection::create_client_buffer_stream_with_id(1061mcl::NoTLSFuture<std::unique_ptr<mcl::BufferStream>>
1062MirConnection::create_client_buffer_stream_with_id(
943 int width, int height,1063 int width, int height,
944 MirRenderSurface* render_surface,1064 MirRenderSurface* render_surface,
945 mir::protobuf::BufferStream const& a_protobuf_bs)1065 mir::protobuf::BufferStream const& a_protobuf_bs)
946{1066{
947 auto stream = std::make_shared<mcl::BufferStream>(1067 return mcl::BufferStream::create(
948 this, render_surface, nullptr, server, platform, surface_map, buffer_factory,1068 this,
949 a_protobuf_bs, make_perf_report(logger), std::string{},1069 render_surface,
950 mir::geometry::Size{width, height}, nbuffers);1070 nullptr,
951 surface_map->insert(render_surface->stream_id(), stream);1071 server,
952 return stream;1072 platform,
1073 surface_map,
1074 buffer_factory,
1075 a_protobuf_bs,
1076 make_perf_report(logger),
1077 std::string{},
1078 mir::geometry::Size{width, height},
1079 nbuffers);
953}1080}
954#pragma GCC diagnostic pop1081#pragma GCC diagnostic pop
9551082
@@ -1322,8 +1449,15 @@
1322 server.release_buffers(&request, ignored.get(), gp::NewCallback(ignore));1449 server.release_buffers(&request, ignored.get(), gp::NewCallback(ignore));
1323}1450}
13241451
1452void MirConnection::process_next_request_first()
1453{
1454 channel->process_next_request_first();
1455}
1456
1325void MirConnection::release_render_surface_with_content(1457void MirConnection::release_render_surface_with_content(
1326 void* render_surface)1458 void* render_surface,
1459 mir_render_surface_callback callback,
1460 void* ctx)
1327{1461{
1328 auto rs = surface_map->render_surface(render_surface);1462 auto rs = surface_map->render_surface(render_surface);
1329 if (!rs->valid())1463 if (!rs->valid())
@@ -1332,13 +1466,23 @@
1332 return;1466 return;
1333 }1467 }
13341468
1335 StreamRelease stream_release{1469<<<<<<< TREE
1336 nullptr,1470 StreamRelease stream_release{
1337 nullptr,1471 nullptr,
1338 nullptr,1472 nullptr,
1339 nullptr,1473 nullptr,
1340 rs->stream_id().as_value(),1474 nullptr,
1341 render_surface};1475 rs->stream_id().as_value(),
1476 render_surface};
1477=======
1478 StreamRelease stream_release{
1479 reinterpret_cast<MirBufferStream*>(render_surface),
1480 nullptr,
1481 reinterpret_cast<mir_buffer_stream_callback>(callback),
1482 ctx,
1483 rs->stream_id().as_value(),
1484 render_surface};
1485>>>>>>> MERGE-SOURCE
13421486
1343 mp::BufferStreamId buffer_stream_id;1487 mp::BufferStreamId buffer_stream_id;
1344 buffer_stream_id.set_value(rs->stream_id().as_value());1488 buffer_stream_id.set_value(rs->stream_id().as_value());
13451489
=== modified file 'src/client/mir_connection.h'
--- src/client/mir_connection.h 2017-03-14 04:41:33 +0000
+++ src/client/mir_connection.h 2017-03-28 00:17:49 +0000
@@ -34,6 +34,7 @@
34#include "mir_surface.h"34#include "mir_surface.h"
35#include "display_configuration.h"35#include "display_configuration.h"
36#include "error_handler.h"36#include "error_handler.h"
37#include "no_tls_future-inl.h"
3738
38#include <atomic>39#include <atomic>
39#include <memory>40#include <memory>
@@ -42,6 +43,8 @@
42#include <unordered_set>43#include <unordered_set>
43#include <unordered_map>44#include <unordered_map>
4445
46#include "mir/fd.h"
47
45namespace mir48namespace mir
46{49{
47namespace input50namespace input
@@ -85,8 +88,17 @@
85namespace dispatch88namespace dispatch
86{89{
87class ThreadedDispatcher;90class ThreadedDispatcher;
88}91class Dispatchable;
89}92class MultiplexingDispatchable;
93class ActionQueue;
94}
95}
96
97enum class DispatchType
98{
99 automatic,
100 manual
101};
90102
91struct MirConnection : mir::client::ClientContext103struct MirConnection : mir::client::ClientContext
92{104{
@@ -94,6 +106,7 @@
94 MirConnection(std::string const& error_message);106 MirConnection(std::string const& error_message);
95107
96 MirConnection(mir::client::ConnectionConfiguration& conf);108 MirConnection(mir::client::ConnectionConfiguration& conf);
109 MirConnection(mir::client::ConnectionConfiguration &conf, DispatchType dispatch);
97 ~MirConnection() noexcept;110 ~MirConnection() noexcept;
98111
99 MirConnection(MirConnection const &) = delete;112 MirConnection(MirConnection const &) = delete;
@@ -119,6 +132,12 @@
119132
120 MirWaitHandle* disconnect();133 MirWaitHandle* disconnect();
121134
135 mir::Fd watch_fd() const;
136 void dispatch();
137
138 void add_dispatchee(std::shared_ptr<mir::dispatch::Dispatchable> const& dispatchee);
139 void remove_dispatchee(std::shared_ptr<mir::dispatch::Dispatchable> const& dispatchee);
140
122 MirWaitHandle* platform_operation(141 MirWaitHandle* platform_operation(
123 MirPlatformMessage const* request,142 MirPlatformMessage const* request,
124 MirPlatformOperationCallback callback, void* context) override;143 MirPlatformOperationCallback callback, void* context) override;
@@ -151,7 +170,7 @@
151 MirRenderSurface* render_surface,170 MirRenderSurface* render_surface,
152 MirBufferStreamCallback mbs_callback,171 MirBufferStreamCallback mbs_callback,
153 void *context);172 void *context);
154 std::shared_ptr<mir::client::BufferStream> create_client_buffer_stream_with_id(173 mir::client::NoTLSFuture<std::unique_ptr<mir::client::BufferStream>> create_client_buffer_stream_with_id(
155 int width, int height,174 int width, int height,
156 MirRenderSurface* render_surface,175 MirRenderSurface* render_surface,
157 mir::protobuf::BufferStream const& a_protobuf_bs);176 mir::protobuf::BufferStream const& a_protobuf_bs);
@@ -221,10 +240,13 @@
221 void* context) -> MirRenderSurface*;240 void* context) -> MirRenderSurface*;
222#pragma GCC diagnostic pop241#pragma GCC diagnostic pop
223 void release_render_surface_with_content(242 void release_render_surface_with_content(
224 void* render_surface);243 void* render_surface,
244 mir_render_surface_callback callback,
245 void* ctx);
225246
226 void* request_interface(char const* name, int version);247 void* request_interface(char const* name, int version);
227248
249 void process_next_request_first();
228private:250private:
229 //google cant have callbacks with more than 2 args251 //google cant have callbacks with more than 2 args
230 struct SurfaceCreationRequest252 struct SurfaceCreationRequest
@@ -242,7 +264,7 @@
242 std::shared_ptr<MirWaitHandle> wh;264 std::shared_ptr<MirWaitHandle> wh;
243 };265 };
244 std::vector<std::shared_ptr<SurfaceCreationRequest>> surface_requests;266 std::vector<std::shared_ptr<SurfaceCreationRequest>> surface_requests;
245 void surface_created(SurfaceCreationRequest*);267 void surface_created(SurfaceCreationRequest*);
246268
247 struct StreamCreationRequest269 struct StreamCreationRequest
248 {270 {
@@ -350,16 +372,20 @@
350372
351 std::shared_ptr<mir::client::LifecycleControl> const lifecycle_control;373 std::shared_ptr<mir::client::LifecycleControl> const lifecycle_control;
352374
375
376 std::shared_ptr<mir::client::EventHandlerRegister> const event_handler_register;
377
378 std::shared_ptr<mir::dispatch::MultiplexingDispatchable> const dispatcher;
379 std::unique_ptr<mir::dispatch::ThreadedDispatcher> const eventloop;
380
353 std::shared_ptr<mir::client::PingHandler> const ping_handler;381 std::shared_ptr<mir::client::PingHandler> const ping_handler;
354382
383 std::unique_ptr<google::protobuf::Closure> const pong_callback;
384
385 std::shared_ptr<mir::dispatch::ActionQueue> const delayed_queue;
386
355 std::shared_ptr<mir::client::ErrorHandler> error_handler;387 std::shared_ptr<mir::client::ErrorHandler> error_handler;
356388
357 std::shared_ptr<mir::client::EventHandlerRegister> const event_handler_register;
358
359 std::unique_ptr<google::protobuf::Closure> const pong_callback;
360
361 std::unique_ptr<mir::dispatch::ThreadedDispatcher> const eventloop;
362
363389
364 struct SurfaceRelease;390 struct SurfaceRelease;
365 struct StreamRelease;391 struct StreamRelease;
366392
=== modified file 'src/client/mir_connection_api.cpp'
--- src/client/mir_connection_api.cpp 2017-02-15 07:38:33 +0000
+++ src/client/mir_connection_api.cpp 2017-03-28 00:17:49 +0000
@@ -29,9 +29,11 @@
29#include "display_configuration.h"29#include "display_configuration.h"
30#include "error_connections.h"30#include "error_connections.h"
31#include "mir/uncaught.h"31#include "mir/uncaught.h"
32#include "synchronous_helper.h"
3233
33#include <cstddef>34#include <cstddef>
34#include <cstring>35#include <cstring>
36#include <poll.h>
3537
36namespace mcl = mir::client;38namespace mcl = mir::client;
37namespace mp = mir::protobuf;39namespace mp = mir::protobuf;
@@ -39,12 +41,105 @@
3941
40namespace42namespace
41{43{
44<<<<<<< TREE
42// assign_result is compatible with all 2-parameter callbacks45// assign_result is compatible with all 2-parameter callbacks
43void assign_result(void* result, void** context)46void assign_result(void* result, void** context)
44{47{
45 if (context)48 if (context)
46 *context = result;49 *context = result;
47}50}
51=======
52class DefaultMirConnectionAPI : public mcl::MirConnectionAPI
53{
54public:
55 MirWaitHandle* connect(
56 mcl::ConfigurationFactory configuration,
57 char const* socket_file,
58 char const* name,
59 mir_connected_callback callback,
60 void* context) override
61 {
62 try
63 {
64 std::string sock;
65 if (socket_file)
66 sock = socket_file;
67 else
68 {
69 auto socket_env = getenv("MIR_SOCKET");
70 if (socket_env && socket_env[0])
71 sock = socket_env;
72 else
73 sock = mir::default_server_socket;
74 }
75
76 auto const conf = configuration(sock);
77
78 auto connection = std::make_unique<MirConnection>(*conf);
79 auto const result = connection->connect(name, callback, context);
80 connection.release();
81 return result;
82 }
83 catch (std::exception const& x)
84 {
85 MirConnection* error_connection = new MirConnection(x.what());
86 mcl::ErrorConnections::instance().insert(error_connection);
87 callback(error_connection, context);
88 return nullptr;
89 }
90 }
91
92 void release(MirConnection* connection) override
93 {
94 if (!mcl::ErrorConnections::instance().contains(connection))
95 {
96 try
97 {
98 auto wait_handle = connection->disconnect();
99 if (connection->watch_fd() != mir::Fd::invalid)
100 {
101 pollfd fd;
102 fd.fd = connection->watch_fd();
103 fd.events = POLLIN;
104 while(wait_handle->is_pending() && (poll(&fd, 1, -1) > 0))
105 {
106 connection->dispatch();
107 }
108 }
109 else
110 {
111 wait_handle->wait_for_all();
112 }
113 }
114 catch (std::exception const& ex)
115 {
116 // We're implementing a C API so no exceptions are to be
117 // propagated. And that's OK because if disconnect() fails,
118 // we don't care why. We're finished with the connection anyway.
119
120 MIR_LOG_UNCAUGHT_EXCEPTION(ex);
121 }
122 }
123 else
124 {
125 mcl::ErrorConnections::instance().remove(connection);
126 }
127
128 delete connection;
129 }
130
131 mcl::ConfigurationFactory configuration_factory() override
132 {
133 return [](std::string const& socket) {
134 return std::unique_ptr<mcl::ConnectionConfiguration>{
135 new mcl::DefaultConnectionConfiguration{socket}
136 };
137 };
138 }
139};
140
141DefaultMirConnectionAPI default_api;
142>>>>>>> MERGE-SOURCE
48}143}
49144
50MirWaitHandle* mir_connect(145MirWaitHandle* mir_connect(
@@ -94,6 +189,7 @@
94 char const* app_name)189 char const* app_name)
95{190{
96 MirConnection* conn = nullptr;191 MirConnection* conn = nullptr;
192<<<<<<< TREE
97 auto wh = mir_connect(server, app_name,193 auto wh = mir_connect(server, app_name,
98 reinterpret_cast<MirConnectedCallback>194 reinterpret_cast<MirConnectedCallback>
99 (assign_result),195 (assign_result),
@@ -104,9 +200,62 @@
104 wh->wait_for_all();200 wh->wait_for_all();
105 }201 }
106202
203=======
204 mir_wait_for(mir_connect(server, app_name,
205 assign_result,
206 &conn));
207>>>>>>> MERGE-SOURCE
107 return conn;208 return conn;
108}209}
109210
211MirConnection* mir_connect_with_manual_dispatch(
212 char const* server,
213 char const* app_name,
214 mir_connected_callback callback,
215 void* context)
216{
217 try
218 {
219 std::string sock;
220 if (server)
221 sock = server;
222 else
223 {
224 auto socket_env = getenv("MIR_SOCKET");
225 if (socket_env)
226 sock = socket_env;
227 else
228 sock = mir::default_server_socket;
229 }
230
231 mcl::DefaultConnectionConfiguration conf{sock};
232
233 std::unique_ptr<MirConnection> connection{new MirConnection(conf, DispatchType::manual)};
234 connection->connect(app_name, callback, context);
235 return connection.release();
236 }
237 catch (std::exception const& x)
238 {
239 MirConnection* error_connection = new MirConnection(x.what());
240 mcl::ErrorConnections::instance().insert(error_connection);
241 callback(error_connection, context);
242 return error_connection;
243 }
244}
245
246MirConnection* mir_connect_with_manual_dispatch_sync(
247 char const* server,
248 char const* app_name)
249{
250 MirConnection* result = nullptr;
251
252 auto connection = mir_connect_with_manual_dispatch(server, app_name, &assign_result, &result);
253
254 dispatch_connection_until(connection, [&result]() { return result != nullptr; });
255
256 return connection;
257}
258
110bool mir_connection_is_valid(MirConnection* connection)259bool mir_connection_is_valid(MirConnection* connection)
111{260{
112 return MirConnection::is_valid(connection);261 return MirConnection::is_valid(connection);
@@ -139,6 +288,16 @@
139 MIR_LOG_UNCAUGHT_EXCEPTION(ex);288 MIR_LOG_UNCAUGHT_EXCEPTION(ex);
140}289}
141290
291int mir_connection_get_event_fd(MirConnection* connection)
292{
293 return connection->watch_fd();
294}
295
296void mir_connection_dispatch(MirConnection* connection)
297{
298 connection->dispatch();
299}
300
142void mir_connection_get_platform(301void mir_connection_get_platform(
143 MirConnection* connection,302 MirConnection* connection,
144 MirPlatformPackage* platform_package)303 MirPlatformPackage* platform_package)
145304
=== modified file 'src/client/mir_prompt_session_api.cpp'
--- src/client/mir_prompt_session_api.cpp 2017-03-10 19:47:57 +0000
+++ src/client/mir_prompt_session_api.cpp 2017-03-28 00:17:49 +0000
@@ -25,6 +25,8 @@
25#include "mir/require.h"25#include "mir/require.h"
26#include "mir/uncaught.h"26#include "mir/uncaught.h"
2727
28#include "synchronous_helper.h"
29
28#include <stdexcept>30#include <stdexcept>
29#include <boost/throw_exception.hpp>31#include <boost/throw_exception.hpp>
3032
@@ -46,6 +48,17 @@
46 prompt_session->register_prompt_session_state_change_callback(state_change_callback, context);48 prompt_session->register_prompt_session_state_change_callback(state_change_callback, context);
47 prompt_session->start(application_pid, null_callback, nullptr)->wait_for_all();49 prompt_session->start(application_pid, null_callback, nullptr)->wait_for_all();
4850
51<<<<<<< TREE
52=======
53 make_synchronous_call(
54 connection,
55 std::mem_fn(&MirPromptSession::start),
56 prompt_session,
57 application_pid,
58 &assign_result<MirPromptSession>,
59 static_cast<void*>(nullptr));
60
61>>>>>>> MERGE-SOURCE
49 return prompt_session;62 return prompt_session;
50 }63 }
51 catch (std::exception const& ex)64 catch (std::exception const& ex)
5265
=== modified file 'src/client/mir_render_surface_api.cpp'
--- src/client/mir_render_surface_api.cpp 2017-03-14 04:41:33 +0000
+++ src/client/mir_render_surface_api.cpp 2017-03-28 00:17:49 +0000
@@ -163,10 +163,13 @@
163}163}
164164
165void mir_render_surface_release(165void mir_render_surface_release(
166 MirRenderSurface* render_surface)166 MirRenderSurface* render_surface,
167 mir_render_surface_callback callback,
168 void* ctx)
167try169try
168{170{
169 mir::require(render_surface);171 mir::require(render_surface);
172<<<<<<< TREE
170 auto connection = connection_map.connection(render_surface);173 auto connection = connection_map.connection(render_surface);
171 connection_map.erase(render_surface);174 connection_map.erase(render_surface);
172 connection->release_render_surface_with_content(render_surface);175 connection->release_render_surface_with_content(render_surface);
@@ -180,17 +183,114 @@
180 MirRenderSurface* render_surface,183 MirRenderSurface* render_surface,
181 int width, int height,184 int width, int height,
182 MirPixelFormat format)185 MirPixelFormat format)
183try186=======
184{187 auto connection = connection_map.connection(static_cast<void*>(render_surface));
188 connection_map.erase(static_cast<void*>(render_surface));
189 connection->release_render_surface_with_content(render_surface, callback, ctx);
190}
191catch (std::exception const& ex)
192{
193 callback(render_surface, ctx);
194 MIR_LOG_UNCAUGHT_EXCEPTION(ex);
195}
196
197void mir_render_surface_get_buffer_stream(
198 MirRenderSurface* render_surface,
199 int width,
200 int height,
201 MirPixelFormat format,
202 MirBufferUsage usage,
203 mir_buffer_stream_callback callback,
204 void* context)
205try
206{
207 mir::require(render_surface);
208 auto connection = connection_map.connection(static_cast<void*>(render_surface));
209 auto rs = connection->connection_surface_map()->render_surface(render_surface);
210 rs->get_buffer_stream(width, height, format, usage, callback, context);
211}
212catch (std::exception const& ex)
213{
214 MIR_LOG_UNCAUGHT_EXCEPTION(ex);
215}
216
217MirBufferStream* mir_render_surface_get_buffer_stream_sync(
218 MirRenderSurface* render_surface,
219 int width,
220 int height,
221 MirPixelFormat format,
222 MirBufferUsage usage)
223>>>>>>> MERGE-SOURCE
224try
225{
226<<<<<<< TREE
185 mir::require(render_surface);227 mir::require(render_surface);
186 auto connection = connection_map.connection(render_surface);228 auto connection = connection_map.connection(render_surface);
187 auto rs = connection->connection_surface_map()->render_surface(render_surface);229 auto rs = connection->connection_surface_map()->render_surface(render_surface);
188 return rs->get_buffer_stream(width, height, format, mir_buffer_usage_software);230 return rs->get_buffer_stream(width, height, format, mir_buffer_usage_software);
231=======
232 struct BufferStreamResult
233 {
234 std::mutex lock;
235 std::condition_variable notify;
236 bool done{false};
237 MirBufferStream* result;
238 } ready;
239
240 mir_render_surface_get_buffer_stream(
241 render_surface,
242 width, height,
243 format,
244 usage,
245 [](MirBufferStream* stream, void* context)
246 {
247 auto result = reinterpret_cast<BufferStreamResult*>(context);
248
249 {
250 std::lock_guard<std::mutex> lock{result->lock};
251 result->result = stream;
252 result->done = true;
253 }
254 result->notify.notify_all();
255 },
256 &ready);
257
258 std::unique_lock<std::mutex> lock{ready.lock};
259 ready.notify.wait(lock, [&ready]() { return ready.done; });
260
261 return ready.result;
262>>>>>>> MERGE-SOURCE
189}263}
190catch (std::exception const& ex)264catch (std::exception const& ex)
191{265{
192 MIR_LOG_UNCAUGHT_EXCEPTION(ex);266 MIR_LOG_UNCAUGHT_EXCEPTION(ex);
193 return nullptr;267 std::terminate();
268}
269
270void mir_render_surface_release_sync(MirRenderSurface* render_surface)
271{
272 struct Waiter
273 {
274 std::condition_variable notifier;
275 std::mutex lock;
276 bool done{false};
277 } waiter;
278
279 mir_render_surface_release(
280 render_surface,
281 [](MirRenderSurface*, void* ctx)
282 {
283 auto waiter = reinterpret_cast<Waiter*>(ctx);
284 {
285 std::lock_guard<std::mutex> lock{waiter->lock};
286 waiter->done = true;
287 }
288 waiter->notifier.notify_all();
289 },
290 &waiter);
291
292 std::unique_lock<std::mutex> lock(waiter.lock);
293 waiter.notifier.wait(lock, [&waiter]() { return waiter.done; });
194}294}
195295
196MirPresentationChain* mir_render_surface_get_presentation_chain(296MirPresentationChain* mir_render_surface_get_presentation_chain(
197297
=== modified file 'src/client/mir_screencast.cpp'
--- src/client/mir_screencast.cpp 2017-03-10 19:47:57 +0000
+++ src/client/mir_screencast.cpp 2017-03-28 00:17:49 +0000
@@ -104,8 +104,9 @@
104{104{
105}105}
106106
107MirScreencast::MirScreencast(std::string const& error)107MirScreencast::MirScreencast(MirConnection* connection, std::string const& error)
108 : protobuf_screencast{mcl::make_protobuf_object<mir::protobuf::Screencast>()}108 : connection{connection},
109 protobuf_screencast{mcl::make_protobuf_object<mir::protobuf::Screencast>()}
109{110{
110 protobuf_screencast->set_error(error);111 protobuf_screencast->set_error(error);
111}112}
@@ -178,7 +179,12 @@
178}179}
179180
180void MirScreencast::screencast_created(181void MirScreencast::screencast_created(
182<<<<<<< TREE
181 MirScreencastCallback callback, void* context)183 MirScreencastCallback callback, void* context)
184=======
185 mir_screencast_callback callback,
186 void* context)
187>>>>>>> MERGE-SOURCE
182{188{
183 if (!protobuf_screencast->has_error() && connection)189 if (!protobuf_screencast->has_error() && connection)
184 {190 {
@@ -219,3 +225,8 @@
219 std::lock_guard<decltype(mutex)> lock(mutex);225 std::lock_guard<decltype(mutex)> lock(mutex);
220 return buffer_stream.get();226 return buffer_stream.get();
221}227}
228
229MirConnection* MirScreencast::get_connection()
230{
231 return connection;
232}
222233
=== modified file 'src/client/mir_screencast.h'
--- src/client/mir_screencast.h 2017-01-24 07:37:03 +0000
+++ src/client/mir_screencast.h 2017-03-28 00:17:49 +0000
@@ -68,7 +68,7 @@
68struct MirScreencast68struct MirScreencast
69{69{
70public:70public:
71 MirScreencast(std::string const& error);71 MirScreencast(MirConnection* connection, std::string const& error);
72 MirScreencast(72 MirScreencast(
73 MirScreencastSpec const& spec,73 MirScreencastSpec const& spec,
74 mir::client::rpc::DisplayServer& server,74 mir::client::rpc::DisplayServer& server,
@@ -85,6 +85,7 @@
8585
86 MirBufferStream* get_buffer_stream();86 MirBufferStream* get_buffer_stream();
8787
88 MirConnection* get_connection();
88private:89private:
89 void screencast_created(90 void screencast_created(
90 MirScreencastCallback callback, void* context);91 MirScreencastCallback callback, void* context);
9192
=== modified file 'src/client/mir_screencast_api.cpp'
--- src/client/mir_screencast_api.cpp 2017-01-18 02:29:37 +0000
+++ src/client/mir_screencast_api.cpp 2017-03-28 00:17:49 +0000
@@ -25,6 +25,8 @@
25#include "mir/require.h"25#include "mir/require.h"
26#include "mir/uncaught.h"26#include "mir/uncaught.h"
2727
28#include "synchronous_helper.h"
29
28#include <stdexcept>30#include <stdexcept>
29#include <boost/throw_exception.hpp>31#include <boost/throw_exception.hpp>
3032
@@ -35,7 +37,18 @@
35{37{
36 auto& server = spec->connection->display_server();38 auto& server = spec->connection->display_server();
37 auto screencast = std::make_unique<MirScreencast>(*spec, server, null_callback, nullptr);39 auto screencast = std::make_unique<MirScreencast>(*spec, server, null_callback, nullptr);
38 screencast->creation_wait_handle()->wait_for_all();40
41 if (spec->connection->watch_fd() != mir::Fd::invalid)
42 {
43 dispatch_connection_until(spec->connection, [&screencast]()
44 {
45 return !screencast->creation_wait_handle()->is_pending();
46 });
47 }
48 else
49 {
50 screencast->creation_wait_handle()->wait_for_all();
51 }
3952
40 auto raw_screencast = screencast.get();53 auto raw_screencast = screencast.get();
41 screencast.release();54 screencast.release();
@@ -92,7 +105,7 @@
92catch (std::exception const& ex)105catch (std::exception const& ex)
93{106{
94 MIR_LOG_UNCAUGHT_EXCEPTION(ex);107 MIR_LOG_UNCAUGHT_EXCEPTION(ex);
95 return new MirScreencast(ex.what());108 return new MirScreencast(spec->connection, ex.what());
96}109}
97110
98bool mir_screencast_is_valid(MirScreencast *screencast)111bool mir_screencast_is_valid(MirScreencast *screencast)
@@ -117,7 +130,11 @@
117130
118void mir_screencast_release_sync(MirScreencast* screencast)131void mir_screencast_release_sync(MirScreencast* screencast)
119{132{
120 screencast->release(null_callback, nullptr)->wait_for_all();133 make_synchronous_call(screencast->get_connection(),
134 std::mem_fn(&MirScreencast::release),
135 screencast,
136 &assign_result<MirScreencast>,
137 static_cast<void*>(nullptr));
121 delete screencast;138 delete screencast;
122}139}
123140
124141
=== modified file 'src/client/mir_surface.cpp'
--- src/client/mir_surface.cpp 2017-03-23 17:23:58 +0000
+++ src/client/mir_surface.cpp 2017-03-28 00:17:49 +0000
@@ -194,6 +194,15 @@
194 spec.event_handler.value().context);194 spec.event_handler.value().context);
195 }195 }
196196
197<<<<<<< TREE
198=======
199 if (surface_proto.fd_size() > 0 && handle_event_callback)
200 {
201 input_dispatcher = input_platform->create_input_receiver(surface_proto.fd(0), keymapper, handle_event_callback);
202 connection()->add_dispatchee(input_dispatcher);
203 }
204
205>>>>>>> MERGE-SOURCE
197 std::lock_guard<decltype(handle_mutex)> lock(handle_mutex);206 std::lock_guard<decltype(handle_mutex)> lock(handle_mutex);
198 valid_surfaces.insert(this);207 valid_surfaces.insert(this);
199208
@@ -220,7 +229,10 @@
220229
221 std::lock_guard<decltype(mutex)> lock(mutex);230 std::lock_guard<decltype(mutex)> lock(mutex);
222231
223 input_thread.reset();232 if (input_dispatcher)
233 {
234 connection()->remove_dispatchee(input_dispatcher);
235 }
224236
225 for (auto i = 0, end = surface->fd_size(); i != end; ++i)237 for (auto i = 0, end = surface->fd_size(); i != end; ++i)
226 close(surface->fd(i));238 close(surface->fd(i));
@@ -466,7 +478,12 @@
466{478{
467 std::lock_guard<decltype(mutex)> lock(mutex);479 std::lock_guard<decltype(mutex)> lock(mutex);
468480
469 input_thread.reset();481 if (input_dispatcher)
482 {
483 connection()->remove_dispatchee(input_dispatcher);
484 input_dispatcher.reset();
485 }
486
470 handle_event_callback = [](auto){};487 handle_event_callback = [](auto){};
471488
472 if (callback)489 if (callback)
@@ -474,6 +491,17 @@
474 handle_event_callback = std::bind(callback, this,491 handle_event_callback = std::bind(callback, this,
475 std::placeholders::_1,492 std::placeholders::_1,
476 context);493 context);
494<<<<<<< TREE
495=======
496
497 if (surface->fd_size() > 0 && handle_event_callback)
498 {
499 input_dispatcher = input_platform->create_input_receiver(surface->fd(0),
500 keymapper,
501 handle_event_callback);
502 connection()->add_dispatchee(input_dispatcher);
503 }
504>>>>>>> MERGE-SOURCE
477 }505 }
478}506}
479507
480508
=== modified file 'src/client/mir_surface.h'
--- src/client/mir_surface.h 2017-03-23 17:23:58 +0000
+++ src/client/mir_surface.h 2017-03-28 00:17:49 +0000
@@ -44,7 +44,7 @@
44{44{
45namespace dispatch45namespace dispatch
46{46{
47class ThreadedDispatcher;47class Dispatchable;
48}48}
49namespace input49namespace input
50{50{
@@ -263,9 +263,13 @@
263 std::shared_ptr<mir::client::FrameClock> const frame_clock;263 std::shared_ptr<mir::client::FrameClock> const frame_clock;
264264
265 std::function<void(MirEvent const*)> handle_event_callback;265 std::function<void(MirEvent const*)> handle_event_callback;
266<<<<<<< TREE
266 std::function<void(MirWindowEvent const*)> handle_drag_and_drop_start_callback = [](auto){};267 std::function<void(MirWindowEvent const*)> handle_drag_and_drop_start_callback = [](auto){};
267268
268 std::shared_ptr<mir::dispatch::ThreadedDispatcher> input_thread;269 std::shared_ptr<mir::dispatch::ThreadedDispatcher> input_thread;
270=======
271 std::shared_ptr<mir::dispatch::Dispatchable> input_dispatcher;
272>>>>>>> MERGE-SOURCE
269273
270 //a bit batty, but the creation handle has to exist for as long as the MirSurface does,274 //a bit batty, but the creation handle has to exist for as long as the MirSurface does,
271 //as we don't really manage the lifetime of MirWaitHandle sensibly.275 //as we don't really manage the lifetime of MirWaitHandle sensibly.
@@ -274,7 +278,6 @@
274 MirPixelFormat format;278 MirPixelFormat format;
275 MirBufferUsage usage;279 MirBufferUsage usage;
276 uint32_t output_id;280 uint32_t output_id;
277
278};281};
279282
280#pragma GCC diagnostic pop283#pragma GCC diagnostic pop
281284
=== modified file 'src/client/mir_surface_api.cpp'
--- src/client/mir_surface_api.cpp 2017-03-14 04:41:33 +0000
+++ src/client/mir_surface_api.cpp 2017-03-28 00:17:49 +0000
@@ -30,6 +30,7 @@
30#include "error_connections.h"30#include "error_connections.h"
31#include "connection_surface_map.h"31#include "connection_surface_map.h"
32#include "mir/uncaught.h"32#include "mir/uncaught.h"
33#include "synchronous_helper.h"
3334
34#include <boost/exception/diagnostic_information.hpp>35#include <boost/exception/diagnostic_information.hpp>
35#include <functional>36#include <functional>
@@ -37,6 +38,7 @@
3738
38namespace mcl = mir::client;39namespace mcl = mir::client;
3940
41<<<<<<< TREE
40namespace42namespace
41{43{
42MirWaitHandle* mir_configure_cursor_helper(MirWindow* window, MirCursorConfiguration const* cursor)44MirWaitHandle* mir_configure_cursor_helper(MirWindow* window, MirCursorConfiguration const* cursor)
@@ -895,6 +897,8 @@
895 MIR_LOG_UNCAUGHT_EXCEPTION(ex);897 MIR_LOG_UNCAUGHT_EXCEPTION(ex);
896}898}
897899
900=======
901>>>>>>> MERGE-SOURCE
898MirSurfaceSpec* mir_connection_create_spec_for_normal_surface(MirConnection* connection,902MirSurfaceSpec* mir_connection_create_spec_for_normal_surface(MirConnection* connection,
899 int width, int height,903 int width, int height,
900 MirPixelFormat format)904 MirPixelFormat format)
@@ -969,7 +973,20 @@
969973
970MirSurface* mir_surface_create_sync(MirSurfaceSpec* requested_specification)974MirSurface* mir_surface_create_sync(MirSurfaceSpec* requested_specification)
971{975{
976<<<<<<< TREE
972 return mir_create_window_sync(requested_specification);977 return mir_create_window_sync(requested_specification);
978=======
979 MirSurface* surface = nullptr;
980
981 make_synchronous_call(
982 requested_specification->connection,
983 &mir_surface_create,
984 requested_specification,
985 &assign_result<MirSurface>,
986 &surface);
987
988 return surface;
989>>>>>>> MERGE-SOURCE
973}990}
974991
975MirWaitHandle* mir_surface_create(MirSurfaceSpec* requested_specification,992MirWaitHandle* mir_surface_create(MirSurfaceSpec* requested_specification,
@@ -1172,7 +1189,15 @@
11721189
1173void mir_surface_release_sync(MirSurface* surface)1190void mir_surface_release_sync(MirSurface* surface)
1174{1191{
1192<<<<<<< TREE
1175 mir_window_release_sync(surface);1193 mir_window_release_sync(surface);
1194=======
1195 make_synchronous_call(surface->connection(),
1196 mir_surface_release,
1197 surface,
1198 &assign_result<MirSurface>,
1199 static_cast<void*>(nullptr));
1200>>>>>>> MERGE-SOURCE
1176}1201}
11771202
1178MirSurfaceType mir_surface_get_type(MirSurface* surf)1203MirSurfaceType mir_surface_get_type(MirSurface* surf)
11791204
=== modified file 'src/client/mir_wait_api.cpp'
--- src/client/mir_wait_api.cpp 2014-03-31 14:36:08 +0000
+++ src/client/mir_wait_api.cpp 2017-03-28 00:17:49 +0000
@@ -30,3 +30,12 @@
30 if (wait_handle)30 if (wait_handle)
31 wait_handle->wait_for_one();31 wait_handle->wait_for_one();
32}32}
33
34bool mir_wait_handle_ready(MirWaitHandle* wait_handle)
35{
36 if (wait_handle)
37 {
38 return !wait_handle->is_pending();
39 }
40 return true;
41}
3342
=== modified file 'src/client/no_tls_future-inl.h'
--- src/client/no_tls_future-inl.h 2017-01-18 02:29:37 +0000
+++ src/client/no_tls_future-inl.h 2017-03-28 00:17:49 +0000
@@ -395,6 +395,7 @@
395 NoTLSPromiseBase& operator=(NoTLSPromiseBase&& other)395 NoTLSPromiseBase& operator=(NoTLSPromiseBase&& other)
396 {396 {
397 state = std::move(other.state);397 state = std::move(other.state);
398 return *this;
398 }399 }
399400
400 NoTLSPromiseBase(NoTLSPromiseBase const&) = delete;401 NoTLSPromiseBase(NoTLSPromiseBase const&) = delete;
401402
=== modified file 'src/client/render_surface.cpp'
--- src/client/render_surface.cpp 2017-03-14 02:26:28 +0000
+++ src/client/render_surface.cpp 2017-03-28 00:17:49 +0000
@@ -25,6 +25,7 @@
25#include "mir/client_platform.h"25#include "mir/client_platform.h"
2626
27#include <boost/throw_exception.hpp>27#include <boost/throw_exception.hpp>
28#include <mir/require.h>
2829
29namespace mcl = mir::client;30namespace mcl = mir::client;
30namespace geom = mir::geometry;31namespace geom = mir::geometry;
@@ -55,27 +56,46 @@
55 return mf::BufferStreamId(protobuf_bs->id().value());56 return mf::BufferStreamId(protobuf_bs->id().value());
56}57}
5758
58MirBufferStream* mcl::RenderSurface::get_buffer_stream(59void mcl::RenderSurface::get_buffer_stream(
59 int width, int height,60 int width,
61 int height,
60 MirPixelFormat format,62 MirPixelFormat format,
61 MirBufferUsage buffer_usage)63 MirBufferUsage buffer_usage,
64 mir_buffer_stream_callback callback,
65 void* context)
62{66{
63 if (chain_from_id || stream_from_id)67 if (chain_from_id || stream_from_id)
68 {
69 callback(nullptr, context);
64 BOOST_THROW_EXCEPTION(std::logic_error("Content already handed out"));70 BOOST_THROW_EXCEPTION(std::logic_error("Content already handed out"));
71 }
6572
66 protobuf_bs->set_pixel_format(format);73 protobuf_bs->set_pixel_format(format);
67 protobuf_bs->set_buffer_usage(buffer_usage);74 protobuf_bs->set_buffer_usage(buffer_usage);
68 stream_from_id = connection_->create_client_buffer_stream_with_id(width,75
69 height,76 connection_->create_client_buffer_stream_with_id(
70 this,77 width,
71 *protobuf_bs);78 height,
72 if (buffer_usage == mir_buffer_usage_hardware)79 this,
73 {80 *protobuf_bs).then(
74 platform->use_egl_native_window(81 [
75 wrapped_native_window, dynamic_cast<EGLNativeSurface*>(stream_from_id.get()));82 this,
76 }83 buffer_usage,
7784 callback,
78 return stream_from_id.get();85 context
86 ](auto&& resolved_future)
87 {
88 auto bs = resolved_future.get();
89
90 if (buffer_usage == mir_buffer_usage_hardware)
91 {
92 platform->use_egl_native_window(
93 wrapped_native_window, dynamic_cast<EGLNativeSurface*>(bs.get()));
94 }
95
96 stream_from_id = std::move(bs);
97 callback(static_cast<MirBufferStream*>(stream_from_id.get()), context);
98 }).detach();
79}99}
80100
81MirPresentationChain* mcl::RenderSurface::get_presentation_chain()101MirPresentationChain* mcl::RenderSurface::get_presentation_chain()
82102
=== modified file 'src/client/render_surface.h'
--- src/client/render_surface.h 2017-03-10 19:47:57 +0000
+++ src/client/render_surface.h 2017-03-28 00:17:49 +0000
@@ -56,10 +56,13 @@
56 mir::frontend::BufferStreamId stream_id() const override;56 mir::frontend::BufferStreamId stream_id() const override;
57 char const* get_error_message() const override;57 char const* get_error_message() const override;
58 bool valid() const override;58 bool valid() const override;
59 MirBufferStream* get_buffer_stream(59 void get_buffer_stream(
60 int width, int height,60 int width,
61 int height,
61 MirPixelFormat format,62 MirPixelFormat format,
62 MirBufferUsage buffer_usage) override;63 MirBufferUsage buffer_usage,
64 mir_buffer_stream_callback callback,
65 void* context) override;
63 MirPresentationChain* get_presentation_chain() override;66 MirPresentationChain* get_presentation_chain() override;
6467
65private:68private:
6669
=== modified file 'src/client/rpc/make_rpc_channel.h'
--- src/client/rpc/make_rpc_channel.h 2017-01-18 02:29:37 +0000
+++ src/client/rpc/make_rpc_channel.h 2017-03-28 00:17:49 +0000
@@ -41,6 +41,7 @@
41{41{
42class MirBasicRpcChannel;42class MirBasicRpcChannel;
43class RpcReport;43class RpcReport;
44class MirBasicRpcChannel;
4445
45std::shared_ptr<mir::client::rpc::MirBasicRpcChannel>46std::shared_ptr<mir::client::rpc::MirBasicRpcChannel>
46make_rpc_channel(47make_rpc_channel(
4748
=== modified file 'src/client/rpc/mir_basic_rpc_channel.h'
--- src/client/rpc/mir_basic_rpc_channel.h 2017-01-30 05:18:36 +0000
+++ src/client/rpc/mir_basic_rpc_channel.h 2017-03-28 00:17:49 +0000
@@ -19,6 +19,8 @@
19#ifndef MIR_CLIENT_RPC_MIR_BASIC_RPC_CHANNEL_H_19#ifndef MIR_CLIENT_RPC_MIR_BASIC_RPC_CHANNEL_H_
20#define MIR_CLIENT_RPC_MIR_BASIC_RPC_CHANNEL_H_20#define MIR_CLIENT_RPC_MIR_BASIC_RPC_CHANNEL_H_
2121
22#include "mir/dispatch/dispatchable.h"
23
22#include <memory>24#include <memory>
23#include <map>25#include <map>
24#include <mutex>26#include <mutex>
@@ -105,6 +107,7 @@
105}107}
106108
107class MirBasicRpcChannel109class MirBasicRpcChannel
110 : public mir::dispatch::Dispatchable
108{111{
109public:112public:
110 virtual ~MirBasicRpcChannel();113 virtual ~MirBasicRpcChannel();
@@ -115,11 +118,16 @@
115 google::protobuf::MessageLite* response,118 google::protobuf::MessageLite* response,
116 google::protobuf::Closure* complete) = 0;119 google::protobuf::Closure* complete) = 0;
117120
121<<<<<<< TREE
118 virtual void discard_future_calls() = 0;122 virtual void discard_future_calls() = 0;
119 virtual void wait_for_outstanding_calls() = 0;123 virtual void wait_for_outstanding_calls() = 0;
120124
125=======
126 virtual void process_next_request_first() = 0;
127>>>>>>> MERGE-SOURCE
121protected:128protected:
122 MirBasicRpcChannel();129 MirBasicRpcChannel();
130
123 mir::protobuf::wire::Invocation invocation_for(131 mir::protobuf::wire::Invocation invocation_for(
124 std::string const& method_name,132 std::string const& method_name,
125 google::protobuf::MessageLite const* request,133 google::protobuf::MessageLite const* request,
126134
=== modified file 'src/client/rpc/mir_protobuf_rpc_channel.cpp'
--- src/client/rpc/mir_protobuf_rpc_channel.cpp 2017-03-17 17:20:09 +0000
+++ src/client/rpc/mir_protobuf_rpc_channel.cpp 2017-03-28 00:17:49 +0000
@@ -374,7 +374,7 @@
374 {374 {
375 for(auto i = 0; i < seq.buffer_request().buffer().fd_size(); i++)375 for(auto i = 0; i < seq.buffer_request().buffer().fd_size(); i++)
376 close(seq.buffer_request().buffer().fd(i));376 close(seq.buffer_request().buffer().fd(i));
377 throw e;377 throw;
378 }378 }
379 }379 }
380 else380 else
@@ -395,13 +395,22 @@
395 // But that's a job for later...395 // But that's a job for later...
396 try396 try
397 {397 {
398<<<<<<< TREE
398 auto e = MirEvent::deserialize(event.raw());399 auto e = MirEvent::deserialize(event.raw());
400=======
401 std::shared_ptr<MirEvent> e = mev::deserialize_event(event.raw());
402>>>>>>> MERGE-SOURCE
399 if (e)403 if (e)
400 {404 {
401 rpc_report->event_parsing_succeeded(*e);405 rpc_report->event_parsing_succeeded(*e);
402406
407<<<<<<< TREE
403 int window_id = 0;408 int window_id = 0;
404 bool is_window_event = true;409 bool is_window_event = true;
410=======
411 auto const send_e = [e](MirSurface* surface)
412 { surface->handle_event(*e); };
413>>>>>>> MERGE-SOURCE
405414
406 switch (e->type())415 switch (e->type())
407 {416 {
408417
=== modified file 'src/client/rpc/mir_protobuf_rpc_channel.h'
--- src/client/rpc/mir_protobuf_rpc_channel.h 2017-01-30 05:18:36 +0000
+++ src/client/rpc/mir_protobuf_rpc_channel.h 2017-03-28 00:17:49 +0000
@@ -53,8 +53,7 @@
5353
54class MirProtobufRpcChannel :54class MirProtobufRpcChannel :
55 public MirBasicRpcChannel,55 public MirBasicRpcChannel,
56 public StreamTransport::Observer,56 public StreamTransport::Observer
57 public dispatch::Dispatchable
58{57{
59public:58public:
60 MirProtobufRpcChannel(std::unique_ptr<StreamTransport> transport,59 MirProtobufRpcChannel(std::unique_ptr<StreamTransport> transport,
@@ -91,7 +90,7 @@
91 *90 *
92 * No messages are discarded, only delayed.91 * No messages are discarded, only delayed.
93 */92 */
94 void process_next_request_first();93 void process_next_request_first() override;
9594
96 void call_method(95 void call_method(
97 std::string const& method_name,96 std::string const& method_name,
@@ -112,6 +111,7 @@
112 detail::SendBuffer header_bytes;111 detail::SendBuffer header_bytes;
113 detail::SendBuffer body_bytes;112 detail::SendBuffer body_bytes;
114113
114
115 void receive_file_descriptors(google::protobuf::MessageLite* response);115 void receive_file_descriptors(google::protobuf::MessageLite* response);
116 template<class MessageType>116 template<class MessageType>
117 void receive_any_file_descriptors_for(MessageType* response);117 void receive_any_file_descriptors_for(MessageType* response);
118118
=== modified file 'src/client/symbols.map'
--- src/client/symbols.map 2017-03-21 05:51:47 +0000
+++ src/client/symbols.map 2017-03-28 00:17:49 +0000
@@ -346,17 +346,23 @@
346 mir_connection_create_render_surface;346 mir_connection_create_render_surface;
347 mir_connection_create_render_surface_sync;347 mir_connection_create_render_surface_sync;
348 mir_render_surface_get_buffer_stream;348 mir_render_surface_get_buffer_stream;
349 mir_render_surface_get_buffer_stream_sync;
349 mir_render_surface_get_presentation_chain;350 mir_render_surface_get_presentation_chain;
350 mir_render_surface_is_valid;351 mir_render_surface_is_valid;
351 mir_render_surface_get_error_message;352 mir_render_surface_get_error_message;
352 mir_render_surface_get_size;353 mir_render_surface_get_size;
353 mir_render_surface_set_size;354 mir_render_surface_set_size;
354 mir_render_surface_release;355 mir_render_surface_release;
356<<<<<<< TREE
355 mir_connection_present_mode_supported;357 mir_connection_present_mode_supported;
356 mir_presentation_chain_set_mode;358 mir_presentation_chain_set_mode;
357 mir_window_spec_add_render_surface;359 mir_window_spec_add_render_surface;
358 mir_window_spec_set_cursor_render_surface;360 mir_window_spec_set_cursor_render_surface;
359 mir_cursor_configuration_from_render_surface;361 mir_cursor_configuration_from_render_surface;
362=======
363 mir_render_surface_release_sync;
364 mir_surface_spec_add_render_surface;
365>>>>>>> MERGE-SOURCE
360366
361 #private functions needed temporarily by nested passthrough367 #private functions needed temporarily by nested passthrough
362 #should not be published along with the rest of the NBS symbols368 #should not be published along with the rest of the NBS symbols
@@ -395,6 +401,11 @@
395 mir_input_device_state_event_time;401 mir_input_device_state_event_time;
396 mir_input_device_state_event_device_pointer_buttons;402 mir_input_device_state_event_device_pointer_buttons;
397 mir_surface_spec_set_pointer_confinement;403 mir_surface_spec_set_pointer_confinement;
404 mir_connect_with_manual_dispatch;
405 mir_connect_with_manual_dispatch_sync;
406 mir_connection_get_event_fd;
407 mir_connection_dispatch;
408 mir_wait_handle_ready;
398} MIR_CLIENT_0.22;409} MIR_CLIENT_0.22;
399410
400MIR_CLIENT_0.25 { # New functions in Mir 0.25411MIR_CLIENT_0.25 { # New functions in Mir 0.25
@@ -552,6 +563,7 @@
552 mir_window_request_persistent_id;563 mir_window_request_persistent_id;
553 mir_window_request_persistent_id_sync;564 mir_window_request_persistent_id_sync;
554} MIR_CLIENT_0.25;565} MIR_CLIENT_0.25;
566<<<<<<< TREE
555567
556MIR_CLIENT_0.26.1 { # New functions in Mir 0.26.1568MIR_CLIENT_0.26.1 { # New functions in Mir 0.26.1
557 global:569 global:
@@ -616,3 +628,12 @@
616 mir_touchscreen_config_set_mapping_mode;628 mir_touchscreen_config_set_mapping_mode;
617 mir_touchscreen_config_set_output_id;629 mir_touchscreen_config_set_output_id;
618} MIR_CLIENT_0.26.1;630} MIR_CLIENT_0.26.1;
631=======
632
633MIR_CLIENT_DETAIL_0.26 {
634 global:
635 extern "C++" {
636 mir::client::DefaultConnectionConfiguration::the_delayed_queue*;
637 };
638} MIR_CLIENT_DETAIL_0.25;
639>>>>>>> MERGE-SOURCE
619640
=== added file 'src/client/synchronous_helper.cpp'
--- src/client/synchronous_helper.cpp 1970-01-01 00:00:00 +0000
+++ src/client/synchronous_helper.cpp 2017-03-28 00:17:49 +0000
@@ -0,0 +1,33 @@
1/*
2 * Copyright © 2015 Canonical Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU Lesser General Public License version 3,
6 * as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authored by: Christopher James Halse Rogers <christopher.halse.rogers@canonical.com>
17 */
18
19#include "synchronous_helper.h"
20
21#include <poll.h>
22
23void dispatch_connection_until(MirConnection* connection, std::function<bool()> predicate)
24{
25 pollfd fd;
26 fd.fd = connection->watch_fd();
27 fd.events = POLLIN;
28 while(!predicate() && (poll(&fd, 1, -1) > 0))
29 {
30 connection->dispatch();
31 }
32}
33
034
=== added file 'src/client/synchronous_helper.h'
--- src/client/synchronous_helper.h 1970-01-01 00:00:00 +0000
+++ src/client/synchronous_helper.h 2017-03-28 00:17:49 +0000
@@ -0,0 +1,160 @@
1/*
2 * Copyright © 2015 Canonical Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU Lesser General Public License version 3,
6 * as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authored by: Christopher James Halse Rogers <christopher.halse.rogers@canonical.com>
17 */
18
19#ifndef MIR_CLIENT_SYNCHRONOUS_H_
20#define MIR_CLIENT_SYNCHRONOUS_H_
21
22#include "mir_connection.h"
23#include "mir_wait_handle.h"
24
25#include <functional>
26#include <type_traits>
27
28template<typename Result>
29void assign_result(Result* result, void* ctx)
30{
31 auto assignee = reinterpret_cast<Result**>(ctx);
32 if (assignee)
33 {
34 *assignee = result;
35 }
36}
37
38template<typename Callback>
39struct SynchronousContext
40{
41 Callback real_callback;
42 bool complete;
43 void* userdata;
44};
45
46template<typename Callable, class Tuple, std::size_t...I>
47void apply_substituting_last_arg(
48 Callable&& function,
49 Tuple&& args,
50 std::index_sequence<I...>,
51 void* context)
52{
53 return std::forward<Callable>(function)(
54 std::get<I>(std::forward<Tuple>(args))...,
55 context);
56}
57
58
59template<typename... Args>
60void synchronous_wrapper(Args... args)
61{
62 std::tuple<Args...> arguments{args...};
63 constexpr std::size_t arg_count = sizeof...(Args);
64
65 auto wrapped_context = reinterpret_cast<SynchronousContext<void(*)(Args...)>*>(std::get<arg_count - 1>(arguments));
66 if (wrapped_context->real_callback)
67 {
68 apply_substituting_last_arg(
69 wrapped_context->real_callback,
70 std::forward_as_tuple(args...),
71 std::make_index_sequence<arg_count - 1>(),
72 wrapped_context->userdata);
73 }
74 wrapped_context->complete = true;
75}
76
77
78template<typename Callable, typename Tuple, std::size_t...I>
79constexpr decltype(auto) call_impl(Callable&& function, Tuple&& args, std::index_sequence<I...>)
80{
81 return std::forward<Callable>(function)(std::get<I>(std::forward<Tuple>((args)))...);
82}
83
84template<typename Callable, typename Tuple>
85constexpr decltype(auto) apply(Callable&& function, Tuple&& args)
86{
87 return call_impl(
88 std::forward<Callable>(function),
89 std::forward<Tuple>(args),
90 std::make_index_sequence<std::tuple_size<std::decay_t<Tuple>>{}>{});
91}
92
93void dispatch_connection_until(MirConnection* connection, std::function<bool()> predicate);
94
95
96/**
97 * \brief Make a synchronous RPC call
98 *
99 * This wrapper takes care of manually dispatching the MirConnection if it is in
100 * manual dispatch mode, or waiting for the operation to complete if in automatic
101 * dispatch mode.
102 *
103 * Given a function mir_foo_do_thing(MirFoo* target, int arg, foo_callback callback, void* context)
104 * the correct way to call this function is
105 * make_synchronous_call(connection,
106 * &mir_foo_do_thing,
107 * target,
108 * arg,
109 * callback,
110 * static_cast<void*>(context));
111 *
112 * The last two parameters must be the callback function and the void* to pass to that callback.
113 * The last argument must have a pointer type; NULL or nullptr must be explicitly cast to
114 * void*.
115 */
116template<typename Callable, typename... Args>
117void make_synchronous_call(MirConnection* connection,
118 Callable&& function,
119 Args&&... args)
120{
121 static_assert(
122 std::is_same<typename std::result_of<Callable(Args...)>::type, MirWaitHandle*>::value,
123 "Second parameter must be a function that returns a MirWaitHandle*");
124
125 if (connection->watch_fd() != mir::Fd::invalid)
126 {
127 std::tuple<Args...> arguments{args...};
128 constexpr int arg_count = sizeof...(Args);
129 auto callback = std::get<arg_count - 2>(arguments);
130 auto context = std::get<arg_count - 1>(arguments);
131
132 static_assert(
133 std::is_pointer<typename std::tuple_element<arg_count - 1, std::tuple<Args...>>::type>::value,
134 "The final argument must be a pointer type");
135 static_assert(
136 std::is_pointer<typename std::tuple_element<arg_count - 2, std::tuple<Args...>>::type>::value,
137 "The second last argument must be a function pointer");
138
139 SynchronousContext<decltype(callback)> wrapper_context {
140 callback,
141 false,
142 context
143 };
144
145 std::get<arg_count - 2>(arguments) = &synchronous_wrapper;
146 std::get<arg_count - 1>(arguments) =
147 reinterpret_cast<typename std::tuple_element<arg_count - 1, std::tuple<Args...>>::type>(&wrapper_context);
148
149 connection->process_next_request_first();
150 apply(std::forward<Callable>(function), arguments);
151
152 dispatch_connection_until(connection, [&wrapper_context](){ return wrapper_context.complete; });
153 }
154 else
155 {
156 mir_wait_for(std::forward<Callable>(function)(std::forward<Args>(args)...));
157 }
158}
159
160#endif // MIR_CLIENT_SYNCHRONOUS_H_
0161
=== added file 'src/common/dispatch/threaded_dispatcher.cpp.moved'
--- src/common/dispatch/threaded_dispatcher.cpp.moved 1970-01-01 00:00:00 +0000
+++ src/common/dispatch/threaded_dispatcher.cpp.moved 2017-03-28 00:17:49 +0000
@@ -0,0 +1,294 @@
1/*
2 * Copyright © 2015 Canonical Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU Lesser General Public License version 3,
6 * as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authored by: Christopher James Halse Rogers <christopher.halse.rogers@canonical.com>
17 */
18
19#include "mir/dispatch/threaded_dispatcher.h"
20#include "mir/dispatch/dispatchable.h"
21#include "mir/thread_name.h"
22
23#include "mir/raii.h"
24#include "mir/logging/logger.h"
25
26#include <fcntl.h>
27#include <poll.h>
28#include <unistd.h>
29#include <system_error>
30#include <signal.h>
31#include <boost/exception/all.hpp>
32#include <algorithm>
33#include <unordered_map>
34#include <sys/eventfd.h>
35
36namespace md = mir::dispatch;
37
38class md::ThreadedDispatcher::ThreadShutdownRequestHandler : public md::Dispatchable
39{
40public:
41 ThreadShutdownRequestHandler()
42 : event_semaphore{eventfd(0, EFD_CLOEXEC | EFD_SEMAPHORE)},
43 shutting_down{false}
44 {
45 if (event_semaphore == mir::Fd::invalid)
46 {
47 BOOST_THROW_EXCEPTION((std::system_error{errno,
48 std::system_category(),
49 "Failed to create shutdown eventfd"}));
50 }
51 }
52
53 mir::Fd watch_fd() const override
54 {
55 return event_semaphore;
56 }
57
58 bool dispatch(md::FdEvents events) override
59 {
60 if (events & md::FdEvent::error)
61 {
62 return false;
63 }
64
65 eventfd_t dummy;
66 if (eventfd_read(event_semaphore, &dummy) < 0)
67 {
68 BOOST_THROW_EXCEPTION((std::system_error{errno,
69 std::system_category(),
70 "Failed to clear shutdown notification"}));
71 }
72 std::lock_guard<decltype(running_flag_guard)> lock{running_flag_guard};
73 *running_flags.at(std::this_thread::get_id()) = false;
74
75 return true;
76 }
77
78 md::FdEvents relevant_events() const override
79 {
80 return md::FdEvent::readable;
81 }
82
83 std::thread::id terminate_one_thread()
84 {
85 // First we tell a thread to die, any thread...
86 if (eventfd_write(event_semaphore, 1) < 0)
87 {
88 BOOST_THROW_EXCEPTION((std::system_error{errno,
89 std::system_category(),
90 "Failed to trigger thread shutdown"}));
91 }
92
93 // ...now we wait for a thread to die and tell us its ID...
94 // We wait for a surprisingly long time because our threads are potentially blocked
95 // in client code that we don't control.
96 //
97 // If the client is entirely unresponsive for a whole minute, it deserves to die.
98 std::unique_lock<decltype(terminating_thread_mutex)> lock{terminating_thread_mutex};
99 if (!thread_terminating.wait_for (lock,
100 std::chrono::seconds{60},
101 [this]() { return !terminating_threads.empty(); }))
102 {
103 BOOST_THROW_EXCEPTION((std::runtime_error{"Thread failed to shutdown"}));
104 }
105
106 auto killed_thread_id = terminating_threads.back();
107 terminating_threads.pop_back();
108 return killed_thread_id;
109 }
110
111 void terminate_all_threads_async()
112 {
113 eventfd_t thread_count;
114 {
115 std::lock_guard<std::mutex> lock(running_flag_guard);
116 thread_count = running_flags.size();
117 shutting_down = true;
118 }
119 if (eventfd_write(event_semaphore, thread_count) < 0)
120 {
121 BOOST_THROW_EXCEPTION((std::system_error{errno,
122 std::system_category(),
123 "Failed to trigger thread shutdown"}));
124 }
125 }
126
127 void register_thread(bool& run_flag)
128 {
129 std::lock_guard<decltype(running_flag_guard)> lock{running_flag_guard};
130
131 running_flags[std::this_thread::get_id()] = &run_flag;
132 if (shutting_down)
133 {
134 if (eventfd_write(event_semaphore, 1) < 0)
135 {
136 BOOST_THROW_EXCEPTION((std::system_error{errno,
137 std::system_category(),
138 "Failed to trigger thread shutdown"}));
139 }
140 }
141 }
142
143 void unregister_thread()
144 {
145 {
146 std::lock_guard<decltype(terminating_thread_mutex)> lock{terminating_thread_mutex};
147 terminating_threads.push_back(std::this_thread::get_id());
148 }
149 thread_terminating.notify_one();
150 {
151 std::lock_guard<decltype(running_flag_guard)> lock{running_flag_guard};
152
153 if (running_flags.erase(std::this_thread::get_id()) != 1)
154 {
155 BOOST_THROW_EXCEPTION((std::logic_error{"Attempted to unregister a not-registered thread"}));
156 }
157 }
158 }
159
160private:
161 mir::Fd event_semaphore;
162
163 std::mutex terminating_thread_mutex;
164 std::condition_variable thread_terminating;
165 std::vector<std::thread::id> terminating_threads;
166
167 std::mutex running_flag_guard;
168 std::unordered_map<std::thread::id, bool*> running_flags;
169 bool shutting_down;
170};
171
172md::ThreadedDispatcher::ThreadedDispatcher(std::string const& name, std::shared_ptr<Dispatchable> const& dispatchee)
173 : ThreadedDispatcher(name, dispatchee, [](){ throw; })
174{
175}
176
177md::ThreadedDispatcher::ThreadedDispatcher(std::string const& name,
178 std::shared_ptr<md::Dispatchable> const& dispatchee,
179 std::function<void()> const& exception_handler)
180 : name_base{name},
181 thread_exiter{std::make_shared<ThreadShutdownRequestHandler>()},
182 dispatcher{std::make_shared<MultiplexingDispatchable>()},
183 exception_handler{exception_handler}
184{
185
186 // We rely on exactly one thread at a time getting a shutdown message
187 dispatcher->add_watch(thread_exiter, md::DispatchReentrancy::sequential);
188
189 // But our target dispatchable is welcome to be dispatched on as many threads
190 // as desired.
191 dispatcher->add_watch(dispatchee, md::DispatchReentrancy::reentrant);
192
193 threadpool.emplace_back(&dispatch_loop, name_base, thread_exiter, dispatcher, exception_handler);
194}
195
196md::ThreadedDispatcher::~ThreadedDispatcher() noexcept
197{
198 std::lock_guard<decltype(thread_pool_mutex)> lock{thread_pool_mutex};
199
200 thread_exiter->terminate_all_threads_async();
201
202 for (auto& thread : threadpool)
203 {
204 if (thread.get_id() == std::this_thread::get_id())
205 {
206 // We're being destroyed from within the dispatch callback
207 // Attempting to join the eventloop will result in a trivial deadlock.
208 //
209 // The std::thread destructor will call std::terminate() for us, let's
210 // leave a useful message.
211 mir::logging::log(mir::logging::Severity::critical,
212 "Destroying ThreadedDispatcher from within a dispatch callback. This is a programming error.",
213 "Dispatch");
214 }
215 else
216 {
217 thread.join();
218 }
219 }
220}
221
222void md::ThreadedDispatcher::add_thread()
223{
224 std::lock_guard<decltype(thread_pool_mutex)> lock{thread_pool_mutex};
225 threadpool.emplace_back(&dispatch_loop, name_base, thread_exiter, dispatcher, exception_handler);
226}
227
228void md::ThreadedDispatcher::remove_thread()
229{
230 auto terminated_thread_id = thread_exiter->terminate_one_thread();
231
232 // Find that thread in our vector, join() it, then remove it.
233 std::lock_guard<decltype(thread_pool_mutex)> threadpool_lock{thread_pool_mutex};
234
235 auto dying_thread = std::find_if(threadpool.begin(),
236 threadpool.end(),
237 [this, &terminated_thread_id](std::thread const& candidate)
238 {
239 return candidate.get_id() == terminated_thread_id;
240 });
241 dying_thread->join();
242 threadpool.erase(dying_thread);
243}
244
245void md::ThreadedDispatcher::dispatch_loop(std::string const& name,
246 std::shared_ptr<ThreadShutdownRequestHandler> thread_register,
247 std::shared_ptr<Dispatchable> dispatcher,
248 std::function<void()> const& exception_handler)
249{
250 sigset_t all_signals;
251 sigfillset(&all_signals);
252
253 if (auto error = pthread_sigmask(SIG_BLOCK, &all_signals, NULL))
254 BOOST_THROW_EXCEPTION((std::system_error{error,
255 std::system_category(),
256 "Failed to block signals on IO thread"}));
257
258 mir::set_thread_name(name);
259
260 // This does not have to be std::atomic<bool> because thread_register is guaranteed to
261 // only ever be dispatch()ed from one thread at a time.
262 bool running{true};
263
264 auto thread_registrar = mir::raii::paired_calls(
265 [&running, thread_register]()
266 {
267 thread_register->register_thread(running);
268 },
269 [thread_register]()
270 {
271 thread_register->unregister_thread();
272 });
273
274 try
275 {
276 struct pollfd waiter;
277 waiter.fd = dispatcher->watch_fd();
278 waiter.events = POLL_IN;
279 while (running)
280 {
281 if (poll(&waiter, 1, -1) < 0)
282 {
283 BOOST_THROW_EXCEPTION((std::system_error{errno,
284 std::system_category(),
285 "Failed to wait for event"}));
286 }
287 dispatcher->dispatch(md::FdEvent::readable);
288 }
289 }
290 catch(...)
291 {
292 exception_handler();
293 }
294}
0295
=== modified file 'src/include/client/mir/mir_render_surface.h'
--- src/include/client/mir/mir_render_surface.h 2017-03-10 19:47:57 +0000
+++ src/include/client/mir/mir_render_surface.h 2017-03-28 00:17:49 +0000
@@ -32,10 +32,13 @@
32 virtual mir::geometry::Size size() const = 0;32 virtual mir::geometry::Size size() const = 0;
33 virtual void set_size(mir::geometry::Size) = 0;33 virtual void set_size(mir::geometry::Size) = 0;
34 virtual bool valid() const = 0;34 virtual bool valid() const = 0;
35 virtual MirBufferStream* get_buffer_stream(35 virtual void get_buffer_stream(
36 int width, int height,36 int width,
37 int height,
37 MirPixelFormat format,38 MirPixelFormat format,
38 MirBufferUsage buffer_usage) = 0;39 MirBufferUsage buffer_usage,
40 mir_buffer_stream_callback callback,
41 void* context) = 0;
39 virtual MirPresentationChain* get_presentation_chain() = 0;42 virtual MirPresentationChain* get_presentation_chain() = 0;
40 virtual char const* get_error_message() const = 0;43 virtual char const* get_error_message() const = 0;
41 virtual ~MirRenderSurface() = default;44 virtual ~MirRenderSurface() = default;
4245
=== modified file 'src/server/scene/mediating_display_changer.cpp'
--- src/server/scene/mediating_display_changer.cpp 2017-03-13 08:12:52 +0000
+++ src/server/scene/mediating_display_changer.cpp 2017-03-28 00:17:49 +0000
@@ -336,7 +336,7 @@
336 */336 */
337 previously_set_alarm = std::move(preview_configuration_timeout);337 previously_set_alarm = std::move(preview_configuration_timeout);
338 preview_configuration_timeout = nullptr;338 preview_configuration_timeout = nullptr;
339 currently_previewing_session = std::weak_ptr<frontend::Session>{};339 currently_previewing_session = std::weak_ptr<frontend::Session>{} ;
340 }340 }
341341
342 if (previously_set_alarm->cancel())342 if (previously_set_alarm->cancel())
343343
=== modified file 'tests/acceptance-tests/CMakeLists.txt'
--- tests/acceptance-tests/CMakeLists.txt 2017-03-15 09:30:18 +0000
+++ tests/acceptance-tests/CMakeLists.txt 2017-03-28 00:17:49 +0000
@@ -1,5 +1,13 @@
1include(CMakeDependentOption)1include(CMakeDependentOption)
22
3<<<<<<< TREE
4=======
5include_directories(
6 ${CMAKE_SOURCE_DIR}
7 ${UMOCKDEV_INCLUDE_DIRS}
8)
9
10>>>>>>> MERGE-SOURCE
3set(11set(
4 SOURCES12 SOURCES
513
614
=== modified file 'tests/acceptance-tests/test_client_library.cpp'
--- tests/acceptance-tests/test_client_library.cpp 2017-03-10 19:47:57 +0000
+++ tests/acceptance-tests/test_client_library.cpp 2017-03-28 00:17:49 +0000
@@ -20,9 +20,19 @@
2020
21#include "mir_test_framework/headless_in_process_server.h"21#include "mir_test_framework/headless_in_process_server.h"
22#include "mir_test_framework/stub_platform_helpers.h"22#include "mir_test_framework/stub_platform_helpers.h"
23<<<<<<< TREE
24=======
25#include "mir_test_framework/using_stub_client_platform.h"
26#include "mir_test_framework/fake_input_device.h"
27#include "mir_test_framework/stub_server_platform_factory.h"
28>>>>>>> MERGE-SOURCE
23#include "mir_test_framework/any_surface.h"29#include "mir_test_framework/any_surface.h"
30#include "mir/test/fd_utils.h"
31#include "mir/test/signal.h"
24#include "mir/test/validity_matchers.h"32#include "mir/test/validity_matchers.h"
33#include "mir/test/signal.h"
25#include "src/include/common/mir/protobuf/protocol_version.h"34#include "src/include/common/mir/protobuf/protocol_version.h"
35#include "mir/test/signal.h"
2636
27#include "mir_protobuf.pb.h"37#include "mir_protobuf.pb.h"
2838
@@ -38,10 +48,16 @@
38#include <fcntl.h>48#include <fcntl.h>
3949
40#include <errno.h>50#include <errno.h>
51#include <mir/input/input_device_info.h>
52#include <mir/input/device_capability.h>
4153
42namespace mf = mir::frontend;54namespace mf = mir::frontend;
43namespace mc = mir::compositor;55namespace mc = mir::compositor;
44namespace mtf = mir_test_framework;56namespace mtf = mir_test_framework;
57namespace mt = mir::test;
58namespace mi = mir::input;
59namespace mis = mir::input::synthesis;
60
45namespace61namespace
46{62{
47#pragma GCC diagnostic push63#pragma GCC diagnostic push
@@ -1120,8 +1136,371 @@
1120 mir_connection_release(connection);1136 mir_connection_release(connection);
1121}1137}
11221138
1139<<<<<<< TREE
1123#pragma GCC diagnostic push1140#pragma GCC diagnostic push
1124#pragma GCC diagnostic ignored "-Wdeprecated-declarations"1141#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
1142=======
1143namespace
1144{
1145struct ThreadTrackingCallbacks
1146{
1147 ThreadTrackingCallbacks()
1148 : client_thread{pthread_self()}
1149 {
1150 }
1151
1152 static void connection_ready(MirConnection* /*connection*/, void* ctx)
1153 {
1154 auto data = reinterpret_cast<ThreadTrackingCallbacks*>(ctx);
1155 EXPECT_EQ(pthread_self(), data->client_thread);
1156 data->connection_ready_called.raise();
1157 }
1158
1159 static void event_delegate(MirSurface* /*surf*/, MirEvent const* event, void* ctx)
1160 {
1161 auto data = reinterpret_cast<ThreadTrackingCallbacks*>(ctx);
1162
1163 EXPECT_THAT(pthread_self(), Eq(data->client_thread));
1164 data->event_received.raise();
1165 if (mir_event_get_type(event) == mir_event_type_input)
1166 {
1167 data->input_event_received.raise();
1168 }
1169 }
1170
1171 static void surface_created(MirSurface* surf, void* ctx)
1172 {
1173 auto data = reinterpret_cast<ThreadTrackingCallbacks*>(ctx);
1174 EXPECT_THAT(pthread_self(), Eq(data->client_thread));
1175 data->surf = surf;
1176
1177 mir_surface_set_event_handler(data->surf, &ThreadTrackingCallbacks::event_delegate, data);
1178 }
1179
1180 static void swap_buffers_complete(MirBufferStream* /*stream*/, void* ctx)
1181 {
1182 auto data = reinterpret_cast<ThreadTrackingCallbacks*>(ctx);
1183 EXPECT_EQ(pthread_self(), data->client_thread);
1184 data->buffers_swapped.raise();
1185 }
1186
1187 pthread_t const client_thread;
1188 MirSurface* surf{nullptr};
1189 mt::Signal buffers_swapped;
1190 mt::Signal connection_ready_called;
1191 mt::Signal event_received;
1192 mt::Signal input_event_received;
1193};
1194
1195void pump_eventloop_until(MirConnection* connection, std::function<bool()> predicate, std::chrono::steady_clock::time_point timeout)
1196{
1197 using namespace std::literals::chrono_literals;
1198
1199 auto fd = mir::Fd{mir::IntOwnedFd{mir_connection_get_event_fd(connection)}};
1200
1201 while (!predicate() && (std::chrono::steady_clock::now() < timeout))
1202 {
1203 if (mt::fd_becomes_readable(fd, 10ms))
1204 {
1205 mir_connection_dispatch(connection);
1206 }
1207 }
1208 if (!predicate())
1209 {
1210 BOOST_THROW_EXCEPTION((std::runtime_error{"Timeout waiting for state change"}));
1211 }
1212}
1213}
1214
1215TEST_F(ClientLibrary, manual_dispatch_handles_callbacks_in_parent_thread)
1216{
1217 using namespace std::literals::chrono_literals;
1218
1219 auto const test_timeout = std::chrono::steady_clock::now() + 10min;
1220
1221 ThreadTrackingCallbacks data;
1222
1223 auto connection = mir_connect_with_manual_dispatch(new_connection().c_str(), __PRETTY_FUNCTION__, &ThreadTrackingCallbacks::connection_ready, &data);
1224
1225 ASSERT_THAT(connection, Ne(nullptr));
1226
1227 pump_eventloop_until(
1228 connection,
1229 [&data]()
1230 {
1231 return data.connection_ready_called.raised();
1232 },
1233 test_timeout);
1234
1235 ASSERT_THAT(connection, IsValid());
1236
1237 auto surface_spec = mir_connection_create_spec_for_normal_surface(connection,
1238 233, 355,
1239 mir_pixel_format_argb_8888);
1240 auto surf_wh = mir_surface_create(surface_spec,
1241 &ThreadTrackingCallbacks::surface_created,
1242 &data);
1243 mir_surface_spec_release(surface_spec);
1244
1245 pump_eventloop_until(
1246 connection,
1247 [surf_wh]()
1248 {
1249 return mir_wait_handle_ready(surf_wh);
1250 },
1251 test_timeout);
1252
1253 EXPECT_THAT(data.surf, IsValid());
1254
1255 auto buffer_stream = mir_surface_get_buffer_stream(data.surf);
1256 auto swap_wh = mir_buffer_stream_swap_buffers(buffer_stream, ThreadTrackingCallbacks::swap_buffers_complete, &data);
1257
1258 pump_eventloop_until(
1259 connection,
1260 [swap_wh]()
1261 {
1262 return mir_wait_handle_ready(swap_wh);
1263 },
1264 test_timeout);
1265 EXPECT_TRUE(data.buffers_swapped.raised());
1266
1267 mir_surface_release_sync(data.surf);
1268 mir_connection_release(connection);
1269}
1270
1271TEST_F(ClientLibrary, manual_dispatch_handles_events_in_parent_thread)
1272{
1273 using namespace testing;
1274 using namespace std::literals::chrono_literals;
1275
1276 auto const test_timeout = std::chrono::steady_clock::now() + 10min;
1277
1278 auto fake_keyboard = mtf::add_fake_input_device(
1279 mi::InputDeviceInfo{"keyboard", "keyboard-unique-id", mi::DeviceCapability::keyboard});
1280
1281 ThreadTrackingCallbacks data;
1282
1283 connection = mir_connect_with_manual_dispatch(new_connection().c_str(), __PRETTY_FUNCTION__, &ThreadTrackingCallbacks::connection_ready, &data);
1284
1285 ASSERT_THAT(connection, Ne(nullptr));
1286
1287 pump_eventloop_until(
1288 connection,
1289 [&data]()
1290 {
1291 return data.connection_ready_called.raised();
1292 },
1293 test_timeout);
1294
1295 ASSERT_THAT(connection, IsValid());
1296
1297 auto surface_spec = mir_connection_create_spec_for_normal_surface(connection,
1298 233, 355,
1299 mir_pixel_format_argb_8888);
1300 auto surf_wh = mir_surface_create(surface_spec,
1301 &ThreadTrackingCallbacks::surface_created,
1302 &data);
1303 mir_surface_spec_release(surface_spec);
1304
1305
1306 pump_eventloop_until(
1307 connection,
1308 [surf_wh]()
1309 {
1310 return mir_wait_handle_ready(surf_wh);
1311 },
1312 test_timeout);
1313
1314 EXPECT_THAT(data.surf, IsValid());
1315
1316 // We need to swap buffers so that the surface is fully realised and
1317 // will be a valid focus target.
1318 //
1319 // The shell will not focus a surface with no content.
1320 auto buffer_stream = mir_surface_get_buffer_stream(data.surf);
1321 mir_buffer_stream_swap_buffers_sync(buffer_stream);
1322
1323 pump_eventloop_until(
1324 connection,
1325 [&data]()
1326 {
1327 return mir_surface_get_focus(data.surf) == mir_surface_focused;
1328 },
1329 test_timeout);
1330
1331 ASSERT_THAT(mir_surface_get_focus(data.surf), Eq(mir_surface_focused));
1332
1333 fake_keyboard->emit_event(mis::a_key_down_event());
1334
1335 pump_eventloop_until(
1336 connection,
1337 [&data]()
1338 {
1339 return data.input_event_received.raised();
1340 },
1341 test_timeout);
1342
1343 mir_surface_release_sync(data.surf);
1344 mir_connection_release(connection);
1345}
1346
1347namespace
1348{
1349struct SignalData
1350{
1351 mir::test::Signal focus_received;
1352 mir::test::Signal now_blocking;
1353 mir::test::Signal event_received;
1354 mir::test::Signal buffer_stream_destroyed;
1355};
1356
1357void notifying_event_handler(MirSurface*, MirEvent const* ev, void* ctx)
1358{
1359 auto signals = *reinterpret_cast<std::shared_ptr<SignalData>*>(ctx);
1360 // We trigger an input event once we've noticed the surface callback is blocking
1361 // so we need to only raise the flag on an input event; otherwise we may spuriously
1362 // fail if we receive a surface event (like the focus event) before we hit
1363 // the wait in blocking_surface_callback()
1364 if (mir_event_get_type(ev) == mir_event_type_input)
1365 {
1366 signals->event_received.raise();
1367 }
1368 if (mir_event_get_type(ev) == mir_event_type_surface)
1369 {
1370 auto surface_event = mir_event_get_surface_event(ev);
1371 if (mir_surface_event_get_attribute(surface_event) == mir_surface_attrib_focus &&
1372 mir_surface_event_get_attribute_value(surface_event) == mir_surface_focused)
1373 {
1374 signals->focus_received.raise();
1375 }
1376 }
1377}
1378
1379void notify_buffer_stream_destroyed(MirBufferStream*, void* ctx)
1380{
1381 auto& signal = *reinterpret_cast<mt::Signal*>(ctx);
1382 signal.raise();
1383}
1384
1385void blocking_buffer_stream_callback(MirBufferStream* stream, void* ctx)
1386{
1387 auto signals = *reinterpret_cast<std::shared_ptr<SignalData>*>(ctx);
1388 signals->now_blocking.raise();
1389 EXPECT_TRUE(signals->event_received.wait_for(std::chrono::seconds{5}));
1390 mir_buffer_stream_release(stream, &notify_buffer_stream_destroyed, &signals->buffer_stream_destroyed);
1391}
1392}
1393
1394TEST_F(ClientLibrary, rpc_blocking_doesnt_block_event_delivery_with_auto_dispatch)
1395{
1396 using namespace testing;
1397
1398 connection = mir_connect_sync(new_connection().c_str(), __PRETTY_FUNCTION__);
1399
1400 auto fake_keyboard = mtf::add_fake_input_device(
1401 mi::InputDeviceInfo{"keyboard", "keyboard-unique-id", mi::DeviceCapability::keyboard});
1402
1403
1404 ASSERT_THAT(connection, IsValid());
1405 auto signals = std::make_shared<SignalData>();
1406
1407 auto surface_spec = mir_connection_create_spec_for_normal_surface(connection,
1408 233, 355,
1409 mir_pixel_format_argb_8888);
1410 mir_surface_spec_set_event_handler(surface_spec, &notifying_event_handler, &signals);
1411
1412 auto surf = mir_surface_create_sync(surface_spec);
1413 mir_surface_spec_release(surface_spec);
1414
1415 ASSERT_THAT(surf, IsValid());
1416
1417 auto buffer_stream = mir_surface_get_buffer_stream(surf);
1418
1419 // Ensure that the surface is focused.
1420 mir_buffer_stream_swap_buffers_sync(buffer_stream);
1421 ASSERT_TRUE(signals->focus_received.wait_for(std::chrono::seconds{5}));
1422
1423 auto wh = mir_connection_create_buffer_stream(
1424 connection,
1425 800, 600,
1426 mir_pixel_format_abgr_8888,
1427 mir_buffer_usage_software,
1428 &blocking_buffer_stream_callback, &signals);
1429
1430 EXPECT_TRUE(signals->now_blocking.wait_for(std::chrono::seconds{5}));
1431 EXPECT_FALSE(signals->event_received.raised());
1432
1433 fake_keyboard->emit_event(mis::a_key_down_event());
1434
1435 EXPECT_TRUE(signals->event_received.wait_for(std::chrono::seconds{5}));
1436 EXPECT_TRUE(signals->buffer_stream_destroyed.wait_for(std::chrono::seconds{5}));
1437
1438 mir_wait_for(wh);
1439 mir_surface_release_sync(surf);
1440 mir_connection_release(connection);
1441}
1442
1443namespace
1444{
1445void async_release_completed(MirSurface*, void* ctx)
1446{
1447 auto called = reinterpret_cast<bool*>(ctx);
1448 *called = true;
1449}
1450
1451void async_creation_completed(MirSurface* surf, void* ctx)
1452{
1453 mir_surface_release(surf, &async_release_completed, ctx);
1454}
1455}
1456
1457TEST_F(ClientLibrary, sync_call_completes_before_previous_undispatched_call)
1458{
1459 using namespace std::literals::chrono_literals;
1460 using namespace testing;
1461
1462 auto timeout = std::chrono::steady_clock::now() + 60s;
1463
1464 ThreadTrackingCallbacks data;
1465
1466 auto connection = mir_connect_with_manual_dispatch(new_connection().c_str(), __PRETTY_FUNCTION__, &ThreadTrackingCallbacks::connection_ready, &data);
1467 ASSERT_THAT(connection, Ne(nullptr));
1468
1469 pump_eventloop_until(connection, [connection]() { return mir_connection_is_valid(connection); }, timeout);
1470
1471 bool async_call_completed{false};
1472
1473 auto surface_spec = mir_connection_create_spec_for_normal_surface(connection,
1474 233, 355,
1475 mir_pixel_format_argb_8888);
1476 mir_surface_create(surface_spec, &async_creation_completed, &async_call_completed);
1477
1478 EXPECT_FALSE(async_call_completed);
1479 auto surf = mir_surface_create_sync(surface_spec);
1480 mir_surface_spec_release(surface_spec);
1481
1482 EXPECT_THAT(surf, IsValid());
1483 EXPECT_FALSE(async_call_completed);
1484
1485 mir_surface_release_sync(surf);
1486 EXPECT_FALSE(async_call_completed);
1487
1488 pump_eventloop_until(connection, [&async_call_completed]() { return async_call_completed;}, timeout);
1489
1490}
1491
1492TEST_F(ClientLibrary, can_connect_synchronously_with_manual_dispatch)
1493{
1494 using namespace testing;
1495
1496 auto connection = mir_connect_with_manual_dispatch_sync(new_connection().c_str(), __PRETTY_FUNCTION__);
1497
1498 EXPECT_THAT(connection, IsValid());
1499
1500 mir_connection_release(connection);
1501}
1502
1503>>>>>>> MERGE-SOURCE
1125TEST_F(ClientLibrary, can_get_persistent_surface_id)1504TEST_F(ClientLibrary, can_get_persistent_surface_id)
1126{1505{
1127 auto connection = mir_connect_sync(new_connection().c_str(), __PRETTY_FUNCTION__);1506 auto connection = mir_connect_sync(new_connection().c_str(), __PRETTY_FUNCTION__);
@@ -1225,6 +1604,7 @@
1225 mir_buffer_stream_release_sync(stream);1604 mir_buffer_stream_release_sync(stream);
1226 mir_connection_release(connection);1605 mir_connection_release(connection);
1227}1606}
1607<<<<<<< TREE
12281608
1229TEST_F(ClientLibrary, client_api_version)1609TEST_F(ClientLibrary, client_api_version)
1230{1610{
@@ -1232,3 +1612,117 @@
1232 MIR_CLIENT_API_VERSION_MINOR,1612 MIR_CLIENT_API_VERSION_MINOR,
1233 MIR_CLIENT_API_VERSION_PATCH) == mir_get_client_api_version());1613 MIR_CLIENT_API_VERSION_PATCH) == mir_get_client_api_version());
1234}1614}
1615=======
1616
1617TEST_F(ClientLibrary, synchronously_creating_buffer_stream_results_in_valid_buffer_stream)
1618{
1619 using namespace testing;
1620
1621 auto connection = mir_connect_with_manual_dispatch_sync(new_connection().c_str(), __PRETTY_FUNCTION__);
1622
1623 ASSERT_THAT(connection, IsValid());
1624
1625 int const width{640}, height{480};
1626 auto stream = mir_connection_create_buffer_stream_sync(
1627 connection,
1628 width, height,
1629 mir_pixel_format_abgr_8888,
1630 mir_buffer_usage_software);
1631
1632 EXPECT_THAT(stream, IsValid());
1633
1634 MirGraphicsRegion region;
1635 mir_buffer_stream_get_graphics_region(stream, &region);
1636
1637 EXPECT_THAT(region.vaddr, NotNull());
1638 EXPECT_THAT(region.width, Eq(width));
1639 EXPECT_THAT(region.height, Eq(height));
1640 EXPECT_THAT(region.stride, Ge(width));
1641 EXPECT_THAT(region.pixel_format, Eq(mir_pixel_format_abgr_8888));
1642
1643 mir_buffer_stream_release_sync(stream);
1644 mir_connection_release(connection);
1645}
1646
1647TEST_F(ClientLibrary, default_surface_stream_is_valid_in_created_callback)
1648{
1649 connection = mir_connect_sync(new_connection().c_str(), __PRETTY_FUNCTION__);
1650 ASSERT_TRUE(mir_connection_is_valid(connection));
1651
1652 auto surface_spec = mir_connection_create_spec_for_normal_surface(
1653 connection,
1654 800, 600,
1655 mir_pixel_format_argb_8888);
1656
1657 mt::Signal done;
1658
1659 mir_surface_create(
1660 surface_spec,
1661 [](MirSurface* surf, void* ctx)
1662 {
1663 auto stream = mir_surface_get_buffer_stream(surf);
1664 EXPECT_THAT(stream, NotNull());
1665 EXPECT_TRUE(mir_buffer_stream_is_valid(stream));
1666
1667 MirNativeBuffer* package;
1668 mir_buffer_stream_get_current_buffer(stream, &package);
1669
1670 EXPECT_THAT(package, NotNull());
1671
1672 mir_surface_release(
1673 surf,
1674 [](MirSurface*, void* ctx)
1675 {
1676 auto done = reinterpret_cast<mt::Signal*>(ctx);
1677
1678 done->raise();
1679 },
1680 ctx);
1681 },
1682 &done);
1683 mir_surface_spec_release(surface_spec);
1684
1685 // ASSERT_TRUE rather than EXPECT_TRUE so that the test dies on client deadlock.
1686 ASSERT_TRUE(done.wait_for(std::chrono::seconds{20}));
1687
1688 mir_connection_release(connection);
1689}
1690
1691TEST_F(ClientLibrary, buffer_stream_is_valid_in_created_callback)
1692{
1693 connection = mir_connect_sync(new_connection().c_str(), __PRETTY_FUNCTION__);
1694 ASSERT_TRUE(mir_connection_is_valid(connection));
1695
1696 mt::Signal done;
1697
1698 mir_connection_create_buffer_stream(
1699 connection,
1700 800, 600,
1701 mir_pixel_format_argb_8888,
1702 mir_buffer_usage_software,
1703 [](MirBufferStream* stream, void* ctx)
1704 {
1705 EXPECT_THAT(stream, IsValid());
1706
1707 MirNativeBuffer* package;
1708 mir_buffer_stream_get_current_buffer(stream, &package);
1709
1710 EXPECT_THAT(package, NotNull());
1711
1712 mir_buffer_stream_release(
1713 stream,
1714 [](MirBufferStream*, void* ctx)
1715 {
1716 auto done = reinterpret_cast<mt::Signal*>(ctx);
1717
1718 done->raise();
1719 },
1720 ctx);
1721 },
1722 &done);
1723
1724 ASSERT_TRUE(done.wait_for(std::chrono::seconds{20}));
1725
1726 mir_connection_release(connection);
1727}
1728>>>>>>> MERGE-SOURCE
12351729
=== modified file 'tests/acceptance-tests/test_client_surfaces.cpp'
--- tests/acceptance-tests/test_client_surfaces.cpp 2017-03-14 04:41:33 +0000
+++ tests/acceptance-tests/test_client_surfaces.cpp 2017-03-28 00:17:49 +0000
@@ -28,6 +28,7 @@
28#include "mir_test_framework/any_surface.h"28#include "mir_test_framework/any_surface.h"
29#include "mir/test/validity_matchers.h"29#include "mir/test/validity_matchers.h"
30#include "mir/test/fake_shared.h"30#include "mir/test/fake_shared.h"
31#include "mir/test/signal.h"
3132
32#include <gmock/gmock.h>33#include <gmock/gmock.h>
33#include <gtest/gtest.h>34#include <gtest/gtest.h>
@@ -391,4 +392,43 @@
391392
392 mir_connection_release(im_connection);393 mir_connection_release(im_connection);
393}394}
395<<<<<<< TREE
394#pragma GCC diagnostic pop396#pragma GCC diagnostic pop
397=======
398
399TEST_F(ClientSurfaces, default_buffer_stream_is_fully_constructed_in_surface_created_callback)
400{
401 using namespace testing;
402 using namespace std::chrono_literals;
403
404 auto surface_spec = mir_connection_create_spec_for_normal_surface(
405 connection,
406 800, 600,
407 mir_pixel_format_argb_8888);
408
409 mt::Signal surface_released;
410 mir_surface_create(
411 surface_spec,
412 [](MirSurface* surf, void* ctx)
413 {
414 EXPECT_THAT(surf, IsValid());
415 auto buffer_stream = mir_surface_get_buffer_stream(surf);
416 MirGraphicsRegion region;
417 mir_buffer_stream_get_graphics_region(buffer_stream, &region);
418 EXPECT_THAT(region.vaddr, NotNull());
419
420 mir_surface_release(
421 surf,
422 [](MirSurface*, void* ctx)
423 {
424 auto& done = *reinterpret_cast<mt::Signal*>(ctx);
425 done.raise();
426 },
427 ctx);
428 },
429 &surface_released);
430 mir_surface_spec_release(surface_spec);
431
432 EXPECT_TRUE(surface_released.wait_for(10s));
433}
434>>>>>>> MERGE-SOURCE
395435
=== modified file 'tests/acceptance-tests/test_render_surface.cpp'
--- tests/acceptance-tests/test_render_surface.cpp 2017-03-10 19:47:57 +0000
+++ tests/acceptance-tests/test_render_surface.cpp 2017-03-28 00:17:49 +0000
@@ -23,11 +23,14 @@
23#include "mir/geometry/size.h"23#include "mir/geometry/size.h"
24#include "mir_test_framework/headless_in_process_server.h"24#include "mir_test_framework/headless_in_process_server.h"
25#include "mir/test/validity_matchers.h"25#include "mir/test/validity_matchers.h"
26#include "mir/test/signal.h"
2627
27#include <gtest/gtest.h>28#include <gtest/gtest.h>
28#include <gmock/gmock.h>29#include <gmock/gmock.h>
30#include "mir/test/signal.h"
2931
30namespace mtf = mir_test_framework;32namespace mtf = mir_test_framework;
33namespace mt = mir::test;
31namespace geom = mir::geometry;34namespace geom = mir::geometry;
3235
33namespace36namespace
@@ -54,7 +57,7 @@
54 EXPECT_TRUE(mir_render_surface_is_valid(rs));57 EXPECT_TRUE(mir_render_surface_is_valid(rs));
55 EXPECT_THAT(mir_render_surface_get_error_message(rs), StrEq(""));58 EXPECT_THAT(mir_render_surface_get_error_message(rs), StrEq(""));
5659
57 mir_render_surface_release(rs);60 mir_render_surface_release_sync(rs);
58 mir_connection_release(connection);61 mir_connection_release(connection);
59}62}
6063
@@ -73,9 +76,13 @@
73 return {width, height};76 return {width, height};
74 };77 };
75 auto physical_size = determine_physical_size(rs);78 auto physical_size = determine_physical_size(rs);
76 auto bs = mir_render_surface_get_buffer_stream(79
80 mt::Signal done;
81
82 mir_render_surface_get_buffer_stream(
77 rs,83 rs,
78 physical_size.width.as_int(), physical_size.height.as_int(),84 physical_size.width.as_int(), physical_size.height.as_int(),
85<<<<<<< TREE
79 mir_pixel_format_abgr_8888);86 mir_pixel_format_abgr_8888);
8087
81 ASSERT_THAT(bs, NotNull());88 ASSERT_THAT(bs, NotNull());
@@ -83,6 +90,22 @@
83 EXPECT_THAT(mir_buffer_stream_get_error_message(bs), StrEq(""));90 EXPECT_THAT(mir_buffer_stream_get_error_message(bs), StrEq(""));
8491
85 mir_render_surface_release(rs);92 mir_render_surface_release(rs);
93=======
94 mir_pixel_format_abgr_8888,
95 mir_buffer_usage_hardware,
96 [](MirBufferStream* bs, void* ctx)
97 {
98 ASSERT_THAT(bs, NotNull());
99 EXPECT_THAT(bs, IsValid());
100
101 reinterpret_cast<mt::Signal*>(ctx)->raise();
102 },
103 &done);
104
105 ASSERT_TRUE(done.wait_for(std::chrono::seconds{20}));
106
107 mir_render_surface_release_sync(rs);
108>>>>>>> MERGE-SOURCE
86 mir_connection_release(connection);109 mir_connection_release(connection);
87}110}
88111
@@ -94,23 +117,21 @@
94 auto rs = mir_connection_create_render_surface_sync(117 auto rs = mir_connection_create_render_surface_sync(
95 connection, logical_size.width.as_int(), logical_size.height.as_int());118 connection, logical_size.width.as_int(), logical_size.height.as_int());
96119
97 auto bs = mir_render_surface_get_buffer_stream(120 auto bs = mir_render_surface_get_buffer_stream_sync(
98 rs,121 rs,
99 physical_size.width.as_int(), physical_size.height.as_int(),122 physical_size.width.as_int(), physical_size.height.as_int(),
100 mir_pixel_format_abgr_8888);123 mir_pixel_format_abgr_8888);
101124
102 ASSERT_THAT(bs, NotNull());125 EXPECT_THAT(bs, IsValid());
103 EXPECT_TRUE(mir_buffer_stream_is_valid(bs));
104 EXPECT_THAT(mir_buffer_stream_get_error_message(bs), StrEq(""));
105126
106 auto bs2 = mir_render_surface_get_buffer_stream(127 auto bs2 = mir_render_surface_get_buffer_stream_sync(
107 rs,128 rs,
108 physical_size.width.as_int(), physical_size.height.as_int(),129 physical_size.width.as_int(), physical_size.height.as_int(),
109 mir_pixel_format_abgr_8888);130 mir_pixel_format_abgr_8888);
110131
111 EXPECT_THAT(bs2, Eq(nullptr));132 EXPECT_THAT(bs2, Eq(nullptr));
112133
113 mir_render_surface_release(rs);134 mir_render_surface_release_sync(rs);
114 mir_connection_release(connection);135 mir_connection_release(connection);
115}136}
116137
@@ -121,9 +142,13 @@
121142
122 auto rs = mir_connection_create_render_surface_sync(143 auto rs = mir_connection_create_render_surface_sync(
123 connection, logical_size.width.as_int(), logical_size.height.as_int());144 connection, logical_size.width.as_int(), logical_size.height.as_int());
124 auto bs = mir_render_surface_get_buffer_stream(145
146 mt::Signal done;
147
148 mir_render_surface_get_buffer_stream(
125 rs,149 rs,
126 physical_size.width.as_int(), physical_size.height.as_int(),150 physical_size.width.as_int(), physical_size.height.as_int(),
151<<<<<<< TREE
127 mir_pixel_format_abgr_8888);152 mir_pixel_format_abgr_8888);
128153
129 ASSERT_THAT(bs, NotNull());154 ASSERT_THAT(bs, NotNull());
@@ -131,6 +156,22 @@
131 EXPECT_THAT(mir_buffer_stream_get_error_message(bs), StrEq(""));156 EXPECT_THAT(mir_buffer_stream_get_error_message(bs), StrEq(""));
132157
133 mir_render_surface_release(rs);158 mir_render_surface_release(rs);
159=======
160 mir_pixel_format_abgr_8888,
161 mir_buffer_usage_hardware,
162 [](MirBufferStream* bs, void* ctx)
163 {
164 ASSERT_THAT(bs, NotNull());
165 EXPECT_THAT(bs, IsValid());
166
167 reinterpret_cast<mt::Signal*>(ctx)->raise();
168 },
169 &done);
170
171 ASSERT_TRUE(done.wait_for(std::chrono::seconds{20}));
172
173 mir_render_surface_release_sync(rs);
174>>>>>>> MERGE-SOURCE
134 mir_connection_release(connection);175 mir_connection_release(connection);
135}176}
136177
@@ -152,8 +193,13 @@
152 EXPECT_THAT(window, IsValid());193 EXPECT_THAT(window, IsValid());
153 EXPECT_THAT(mir_window_get_buffer_stream(window), Eq(nullptr));194 EXPECT_THAT(mir_window_get_buffer_stream(window), Eq(nullptr));
154195
196<<<<<<< TREE
155 mir_render_surface_release(rs);197 mir_render_surface_release(rs);
156 mir_window_release_sync(window);198 mir_window_release_sync(window);
199=======
200 mir_render_surface_release_sync(rs);
201 mir_surface_release_sync(surface);
202>>>>>>> MERGE-SOURCE
157 mir_connection_release(connection);203 mir_connection_release(connection);
158}204}
159205
@@ -166,19 +212,55 @@
166212
167 auto rs = mir_connection_create_render_surface_sync(213 auto rs = mir_connection_create_render_surface_sync(
168 connection, logical_size.width.as_int(), logical_size.height.as_int());214 connection, logical_size.width.as_int(), logical_size.height.as_int());
215<<<<<<< TREE
169 auto spec = mir_create_normal_window_spec(connection, width, height);216 auto spec = mir_create_normal_window_spec(connection, width, height);
170 mir_window_spec_set_pixel_format(spec, format);217 mir_window_spec_set_pixel_format(spec, format);
171 mir_window_spec_add_render_surface(spec, rs, width, height, 0, 0);218 mir_window_spec_add_render_surface(spec, rs, width, height, 0, 0);
172 auto window = mir_create_window_sync(spec);219 auto window = mir_create_window_sync(spec);
173 mir_window_spec_release(spec);220 mir_window_spec_release(spec);
174 auto bs = mir_render_surface_get_buffer_stream(rs, 640, 480, format);221 auto bs = mir_render_surface_get_buffer_stream(rs, 640, 480, format);
175222=======
223 auto spec = mir_connection_create_spec_for_normal_surface(connection,
224 width, height,
225 format);
226 mir_surface_spec_add_render_surface(spec, rs, width, height, 0, 0);
227 auto surface = mir_surface_create_sync(spec);
228 mir_surface_spec_release(spec);
229 mt::Signal done;
230
231 mir_render_surface_get_buffer_stream(
232 rs,
233 640, 480,
234 format,
235 usage,
236 [](MirBufferStream* bs, void* ctx)
237 {
238 ASSERT_THAT(bs, NotNull());
239 EXPECT_THAT(bs, IsValid());
240
241 reinterpret_cast<mt::Signal*>(ctx)->raise();
242 },
243 &done);
244
245>>>>>>> MERGE-SOURCE
246
247<<<<<<< TREE
176 EXPECT_THAT(window, IsValid());248 EXPECT_THAT(window, IsValid());
177 EXPECT_THAT(mir_window_get_buffer_stream(window), Eq(nullptr));249 EXPECT_THAT(mir_window_get_buffer_stream(window), Eq(nullptr));
178 EXPECT_TRUE(mir_buffer_stream_is_valid(bs));250 EXPECT_TRUE(mir_buffer_stream_is_valid(bs));
179251
180 mir_render_surface_release(rs);252 mir_render_surface_release(rs);
181 mir_window_release_sync(window);253 mir_window_release_sync(window);
254=======
255 EXPECT_THAT(surface, IsValid());
256
257 EXPECT_THAT(mir_surface_get_buffer_stream(surface), Eq(nullptr));
258
259 ASSERT_TRUE(done.wait_for(std::chrono::seconds{20}));
260
261 mir_render_surface_release_sync(rs);
262 mir_surface_release_sync(surface);
263>>>>>>> MERGE-SOURCE
182 mir_connection_release(connection);264 mir_connection_release(connection);
183}265}
184266
@@ -194,7 +276,7 @@
194 ASSERT_THAT(pc, NotNull());276 ASSERT_THAT(pc, NotNull());
195 EXPECT_TRUE(mir_presentation_chain_is_valid(pc));277 EXPECT_TRUE(mir_presentation_chain_is_valid(pc));
196278
197 mir_render_surface_release(rs);279 mir_render_surface_release_sync(rs);
198 mir_connection_release(connection);280 mir_connection_release(connection);
199}281}
200282
@@ -214,7 +296,7 @@
214296
215 EXPECT_THAT(pc2, Eq(nullptr));297 EXPECT_THAT(pc2, Eq(nullptr));
216298
217 mir_render_surface_release(rs);299 mir_render_surface_release_sync(rs);
218 mir_connection_release(connection);300 mir_connection_release(connection);
219}301}
220302
@@ -238,8 +320,13 @@
238 EXPECT_THAT(mir_window_get_buffer_stream(window), Eq(nullptr));320 EXPECT_THAT(mir_window_get_buffer_stream(window), Eq(nullptr));
239 EXPECT_TRUE(mir_presentation_chain_is_valid(pc));321 EXPECT_TRUE(mir_presentation_chain_is_valid(pc));
240322
323<<<<<<< TREE
241 mir_render_surface_release(rs);324 mir_render_surface_release(rs);
242 mir_window_release_sync(window);325 mir_window_release_sync(window);
326=======
327 mir_render_surface_release_sync(rs);
328 mir_surface_release_sync(surface);
329>>>>>>> MERGE-SOURCE
243 mir_connection_release(connection);330 mir_connection_release(connection);
244}331}
245332
@@ -254,7 +341,7 @@
254 ASSERT_THAT(pc, NotNull());341 ASSERT_THAT(pc, NotNull());
255 EXPECT_TRUE(mir_presentation_chain_is_valid(pc));342 EXPECT_TRUE(mir_presentation_chain_is_valid(pc));
256343
257 mir_render_surface_release(rs);344 mir_render_surface_release_sync(rs);
258 mir_connection_release(connection);345 mir_connection_release(connection);
259}346}
260347
@@ -270,14 +357,14 @@
270 ASSERT_THAT(pc, NotNull());357 ASSERT_THAT(pc, NotNull());
271 EXPECT_TRUE(mir_presentation_chain_is_valid(pc));358 EXPECT_TRUE(mir_presentation_chain_is_valid(pc));
272359
273 auto bs = mir_render_surface_get_buffer_stream(360 auto bs = mir_render_surface_get_buffer_stream_sync(
274 rs,361 rs,
275 physical_size.width.as_int(), physical_size.height.as_int(),362 physical_size.width.as_int(), physical_size.height.as_int(),
276 mir_pixel_format_abgr_8888);363 mir_pixel_format_abgr_8888);
277364
278 EXPECT_THAT(bs, Eq(nullptr));365 EXPECT_THAT(bs, Eq(nullptr));
279366
280 mir_render_surface_release(rs);367 mir_render_surface_release_sync(rs);
281 mir_connection_release(connection);368 mir_connection_release(connection);
282}369}
283370
@@ -288,20 +375,148 @@
288375
289 auto rs = mir_connection_create_render_surface_sync(376 auto rs = mir_connection_create_render_surface_sync(
290 connection, logical_size.width.as_int(), logical_size.height.as_int());377 connection, logical_size.width.as_int(), logical_size.height.as_int());
291 auto bs = mir_render_surface_get_buffer_stream(378 auto bs = mir_render_surface_get_buffer_stream_sync(
292 rs,379 rs,
293 physical_size.width.as_int(), physical_size.height.as_int(),380 physical_size.width.as_int(), physical_size.height.as_int(),
294 mir_pixel_format_abgr_8888);381 mir_pixel_format_abgr_8888);
295382
296 ASSERT_THAT(bs, NotNull());383 EXPECT_THAT(bs, IsValid());
297 EXPECT_TRUE(mir_buffer_stream_is_valid(bs));
298384
299 auto pc = mir_render_surface_get_presentation_chain(rs);385 auto pc = mir_render_surface_get_presentation_chain(rs);
300386
301 EXPECT_THAT(pc, Eq(nullptr));387 EXPECT_THAT(pc, Eq(nullptr));
302388
303 mir_render_surface_release(rs);389 mir_render_surface_release_sync(rs);
304 mir_connection_release(connection);390 mir_connection_release(connection);
391}
392
393TEST_F(RenderSurfaceTest, asynchronous_render_surface_destruction_works_with_realised_buffer_stream)
394{
395 auto physical_size = logical_size;
396 auto connection = mir_connect_sync(new_connection().c_str(), __PRETTY_FUNCTION__);
397
398 auto rs = mir_connection_create_render_surface_sync(
399 connection, logical_size.width.as_int(), logical_size.height.as_int());
400 mir_render_surface_get_buffer_stream_sync(
401 rs,
402 physical_size.width.as_int(), physical_size.height.as_int(),
403 mir_pixel_format_abgr_8888,
404 mir_buffer_usage_hardware);
405
406 struct Context
407 {
408 MirRenderSurface* rs;
409 mt::Signal done;
410 } context;
411
412 context.rs = rs;
413
414 mir_render_surface_release(
415 rs,
416 [](MirRenderSurface* rs, void* ctx)
417 {
418 auto& context = *reinterpret_cast<Context*>(ctx);
419 EXPECT_THAT(rs, Eq(context.rs));
420 /*
421 * Should really test that the render surface isn't valid here, but that fails.
422 *
423 EXPECT_THAT(rs, Not(IsValid()));
424 */
425 context.done.raise();
426 },
427 &context);
428
429 ASSERT_TRUE(context.done.wait_for(std::chrono::seconds{20}));
430
431 mir_connection_release(connection);
432}
433
434TEST_F(RenderSurfaceTest, asynchronous_render_surface_destruction_works_with_realised_presentation_chain)
435{
436 auto connection = mir_connect_sync(new_connection().c_str(), __PRETTY_FUNCTION__);
437
438 auto rs = mir_connection_create_render_surface_sync(
439 connection, logical_size.width.as_int(), logical_size.height.as_int());
440 mir_render_surface_get_presentation_chain(rs);
441
442 struct Context
443 {
444 MirRenderSurface* rs;
445 mt::Signal done;
446 } context;
447
448 context.rs = rs;
449
450 mir_render_surface_release(
451 rs,
452 [](MirRenderSurface* rs, void* ctx)
453 {
454 auto& context = *reinterpret_cast<Context*>(ctx);
455 EXPECT_THAT(rs, Eq(context.rs));
456 /*
457 * Should really test that the render surface isn't valid here, but that fails.
458 *
459 EXPECT_THAT(rs, Not(IsValid()));
460 */
461 context.done.raise();
462 },
463 &context);
464
465 ASSERT_TRUE(context.done.wait_for(std::chrono::seconds{20}));
466
467 mir_connection_release(connection);
468}
469
470TEST_F(RenderSurfaceTest, asynchronous_render_surface_destruction_works_with_no_backing_object)
471{
472 auto connection = mir_connect_sync(new_connection().c_str(), __PRETTY_FUNCTION__);
473
474 auto rs = mir_connection_create_render_surface_sync(
475 connection, logical_size.width.as_int(), logical_size.height.as_int());
476
477 struct Context
478 {
479 MirRenderSurface* rs;
480 mt::Signal done;
481 } context;
482
483 context.rs = rs;
484
485 mir_render_surface_release(
486 rs,
487 [](MirRenderSurface* rs, void* ctx)
488 {
489 auto& context = *reinterpret_cast<Context*>(ctx);
490 EXPECT_THAT(rs, Eq(context.rs));
491 /*
492 * Should really test that the render surface isn't valid here, but that fails.
493 *
494 EXPECT_THAT(rs, Not(IsValid()));
495 */
496 context.done.raise();
497 },
498 &context);
499
500 ASSERT_TRUE(context.done.wait_for(std::chrono::seconds{20}));
501
502 mir_connection_release(connection);
503}
504
505TEST_F(RenderSurfaceTest, asynchronous_destruction_calls_callback_on_failure)
506{
507 auto not_a_valid_client_side_rs = reinterpret_cast<MirRenderSurface*>(0x0ff01bb1);
508
509 mt::Signal callback_called;
510
511 mir_render_surface_release(
512 not_a_valid_client_side_rs,
513 [](MirRenderSurface*, void* ctx)
514 {
515 reinterpret_cast<mt::Signal*>(ctx)->raise();
516 },
517 &callback_called);
518
519 EXPECT_TRUE(callback_called.wait_for(std::chrono::seconds{20}));
305}520}
306521
307TEST_F(RenderSurfaceTest, stores_user_set_size_for_driver_to_access)522TEST_F(RenderSurfaceTest, stores_user_set_size_for_driver_to_access)
308523
=== modified file 'tests/acceptance-tests/test_server_shutdown.cpp'
--- tests/acceptance-tests/test_server_shutdown.cpp 2017-03-09 12:52:48 +0000
+++ tests/acceptance-tests/test_server_shutdown.cpp 2017-03-28 00:17:49 +0000
@@ -25,7 +25,7 @@
25#include "mir_test_framework/executable_path.h"25#include "mir_test_framework/executable_path.h"
26#include "mir/test/doubles/null_logger.h"26#include "mir/test/doubles/null_logger.h"
2727
28#include <gtest/gtest.h>28#include </usr/include/gtest/gtest.h>
2929
30namespace mt = mir::test;30namespace mt = mir::test;
31namespace mtf = mir_test_framework;31namespace mtf = mir_test_framework;
3232
=== added file 'tests/include/mir/test/doubles/mock_client_buffer_stream_factory.h.THIS'
--- tests/include/mir/test/doubles/mock_client_buffer_stream_factory.h.THIS 1970-01-01 00:00:00 +0000
+++ tests/include/mir/test/doubles/mock_client_buffer_stream_factory.h.THIS 2017-03-28 00:17:49 +0000
@@ -0,0 +1,59 @@
1/*
2 * Copyright © 2015 Canonical Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 3,
6 * as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authored by: Robert Carr <robert.carr@canonical.com>
17 */
18
19#ifndef MIR_TEST_DOUBLES_MOCK_CLIENT_BUFFER_STREAM_FACTORY_H_
20#define MIR_TEST_DOUBLES_MOCK_CLIENT_BUFFER_STREAM_FACTORY_H_
21
22#include "src/client/client_buffer_stream_factory.h"
23#include "src/client/buffer_stream.h"
24
25#include <gtest/gtest.h>
26#include <gmock/gmock.h>
27
28namespace mir
29{
30namespace test
31{
32namespace doubles
33{
34
35struct MockClientBufferStreamFactory : public client::ClientBufferStreamFactory
36{
37 MOCK_METHOD4(make_consumer_stream, std::shared_ptr<client::ClientBufferStream>(
38 MirConnection*,
39 protobuf::DisplayServer&,
40 protobuf::BufferStream const&,
41 std::string const&));
42 MOCK_METHOD4(make_producer_stream, std::shared_ptr<client::ClientBufferStream>(
43 MirConnection*,
44 protobuf::DisplayServer&,
45 protobuf::BufferStream const&,
46 std::string const&));
47 MOCK_METHOD5(make_producer_stream, client::ClientBufferStream*(
48 MirConnection*,
49 protobuf::DisplayServer&,
50 protobuf::BufferStreamParameters const&,
51 mir_buffer_stream_callback callback,
52 void* context));
53};
54
55}
56}
57}
58
59#endif // MIR_TEST_DOUBLES_MOCK_CLIENT_BUFFER_STREAM_FACTORY_H_
060
=== modified file 'tests/include/mir/test/doubles/mock_mir_buffer_stream.h'
--- tests/include/mir/test/doubles/mock_mir_buffer_stream.h 2017-03-10 19:47:57 +0000
+++ tests/include/mir/test/doubles/mock_mir_buffer_stream.h 2017-03-28 00:17:49 +0000
@@ -50,6 +50,7 @@
50 MOCK_METHOD0(get_create_wait_handle, MirWaitHandle*(void));50 MOCK_METHOD0(get_create_wait_handle, MirWaitHandle*(void));
51 MOCK_CONST_METHOD0(rpc_id, frontend::BufferStreamId(void));51 MOCK_CONST_METHOD0(rpc_id, frontend::BufferStreamId(void));
52 MOCK_CONST_METHOD0(valid, bool(void));52 MOCK_CONST_METHOD0(valid, bool(void));
53 MOCK_CONST_METHOD0(has_buffer, bool(void));
53 MOCK_METHOD1(buffer_available, void(mir::protobuf::Buffer const&));54 MOCK_METHOD1(buffer_available, void(mir::protobuf::Buffer const&));
54 MOCK_METHOD0(buffer_unavailable, void());55 MOCK_METHOD0(buffer_unavailable, void());
55 MOCK_METHOD1(set_size, void(geometry::Size));56 MOCK_METHOD1(set_size, void(geometry::Size));
5657
=== modified file 'tests/include/mir/test/doubles/stub_buffer_stream_factory.h'
--- tests/include/mir/test/doubles/stub_buffer_stream_factory.h 2017-03-13 08:12:52 +0000
+++ tests/include/mir/test/doubles/stub_buffer_stream_factory.h 2017-03-28 00:17:49 +0000
@@ -21,7 +21,10 @@
2121
22#include "mir/frontend/client_buffers.h"22#include "mir/frontend/client_buffers.h"
23#include "mir/scene/buffer_stream_factory.h"23#include "mir/scene/buffer_stream_factory.h"
24#include "mir/frontend/buffer_sink.h"
24#include "stub_buffer_stream.h"25#include "stub_buffer_stream.h"
26#include "stub_buffer.h"
27#include "mir_test_framework/stub_platform_native_buffer.h"
2528
26namespace mir29namespace mir
27{30{
@@ -32,8 +35,20 @@
3235
33struct StubClientBuffers : frontend::ClientBuffers36struct StubClientBuffers : frontend::ClientBuffers
34{37{
38<<<<<<< TREE
35 graphics::BufferID add_buffer(std::shared_ptr<graphics::Buffer> const&) override39 graphics::BufferID add_buffer(std::shared_ptr<graphics::Buffer> const&) override
36 {40 {
41=======
42 StubClientBuffers(std::shared_ptr<frontend::BufferSink> const& sink)
43 : sink{sink}
44 {
45 }
46
47 graphics::BufferID add_buffer(graphics::BufferProperties const& props) override
48 {
49 StubBuffer buf{std::make_shared<mir_test_framework::NativeBuffer>(props), props.size};
50 sink->add_buffer(buf);
51>>>>>>> MERGE-SOURCE
37 return {};52 return {};
38 }53 }
39 void remove_buffer(graphics::BufferID) override54 void remove_buffer(graphics::BufferID) override
@@ -50,6 +65,7 @@
50 {65 {
51 }66 }
52 std::shared_ptr<graphics::Buffer> buffer;67 std::shared_ptr<graphics::Buffer> buffer;
68 std::shared_ptr<frontend::BufferSink> const sink;
53};69};
5470
55struct StubBufferStreamFactory : public scene::BufferStreamFactory71struct StubBufferStreamFactory : public scene::BufferStreamFactory
@@ -61,9 +77,9 @@
61 frontend::BufferStreamId, std::shared_ptr<frontend::ClientBuffers> const&,77 frontend::BufferStreamId, std::shared_ptr<frontend::ClientBuffers> const&,
62 graphics::BufferProperties const&) { return std::make_shared<StubBufferStream>(); }78 graphics::BufferProperties const&) { return std::make_shared<StubBufferStream>(); }
63 std::shared_ptr<frontend::ClientBuffers> create_buffer_map(79 std::shared_ptr<frontend::ClientBuffers> create_buffer_map(
64 std::shared_ptr<frontend::BufferSink> const&)80 std::shared_ptr<frontend::BufferSink> const& sink)
65 {81 {
66 return std::make_shared<StubClientBuffers>();82 return std::make_shared<StubClientBuffers>(sink);
67 }83 }
68};84};
69}85}
7086
=== added file 'tests/include/mir/test/doubles/stub_client_buffer_stream_factory.h.THIS'
--- tests/include/mir/test/doubles/stub_client_buffer_stream_factory.h.THIS 1970-01-01 00:00:00 +0000
+++ tests/include/mir/test/doubles/stub_client_buffer_stream_factory.h.THIS 2017-03-28 00:17:49 +0000
@@ -0,0 +1,66 @@
1/*
2 * Copyright © 2015 Canonical Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 3,
6 * as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authored by: Robert Carr <robert.carr@canonical.com>
17 */
18
19#ifndef MIR_TEST_DOUBLES_STUB_CLIENT_BUFFER_STREAM_FACTORY_H_
20#define MIR_TEST_DOUBLES_STUB_CLIENT_BUFFER_STREAM_FACTORY_H_
21
22#include "src/client/client_buffer_stream_factory.h"
23#include "src/client/buffer_stream.h"
24
25namespace mir
26{
27namespace test
28{
29namespace doubles
30{
31
32struct StubClientBufferStreamFactory : public client::ClientBufferStreamFactory
33{
34 std::shared_ptr<client::ClientBufferStream> make_consumer_stream(
35 MirConnection* /* allocating_connection */,
36 protobuf::DisplayServer& /* server */,
37 protobuf::BufferStream const& /* protobuf_bs */,
38 std::string const& /* surface_name */) override
39 {
40 return nullptr;
41 }
42
43 std::shared_ptr<client::ClientBufferStream> make_producer_stream(
44 MirConnection* /* allocating_connection */,
45 protobuf::DisplayServer& /* server */,
46 protobuf::BufferStream const& /* protobuf_bs */,
47 std::string const& /* surface_name */) override
48 {
49 return nullptr;
50 }
51
52 client::ClientBufferStream* make_producer_stream(
53 MirConnection* /* allocating_connection */,
54 protobuf::DisplayServer& /* server */,
55 protobuf::BufferStreamParameters const& /* params */,
56 mir_buffer_stream_callback /* callback */, void* /* context */) override
57 {
58 return nullptr;
59 }
60};
61
62}
63}
64}
65
66#endif // MIR_TEST_DOUBLES_STUB_CLIENT_BUFFER_STREAM_FACTORY_H_
067
=== modified file 'tests/integration-tests/test_buffer_scheduling.cpp'
--- tests/integration-tests/test_buffer_scheduling.cpp 2017-03-13 08:12:52 +0000
+++ tests/integration-tests/test_buffer_scheduling.cpp 2017-03-28 00:17:49 +0000
@@ -27,6 +27,7 @@
27#include "src/client/connection_surface_map.h"27#include "src/client/connection_surface_map.h"
28#include "src/server/compositor/stream.h"28#include "src/server/compositor/stream.h"
29#include "src/server/compositor/buffer_map.h"29#include "src/server/compositor/buffer_map.h"
30#include "mir/dispatch/action_queue.h"
30#include "mir/test/doubles/stub_client_buffer_factory.h"31#include "mir/test/doubles/stub_client_buffer_factory.h"
31#include "mir/test/doubles/mock_client_buffer_factory.h"32#include "mir/test/doubles/mock_client_buffer_factory.h"
32#include "mir/test/doubles/stub_buffer_allocator.h"33#include "mir/test/doubles/stub_buffer_allocator.h"
@@ -37,6 +38,7 @@
3738
38namespace mt = mir::test;39namespace mt = mir::test;
39namespace mtd = mir::test::doubles;40namespace mtd = mir::test::doubles;
41namespace md = mir::dispatch;
40namespace mcl = mir::client;42namespace mcl = mir::client;
41namespace mc = mir::compositor;43namespace mc = mir::compositor;
42namespace mg = mir::graphics;44namespace mg = mir::graphics;
@@ -290,7 +292,7 @@
290{292{
291 ScheduledProducer(std::shared_ptr<StubIpcSystem> const& ipc_stub, int nbuffers) :293 ScheduledProducer(std::shared_ptr<StubIpcSystem> const& ipc_stub, int nbuffers) :
292 ipc(ipc_stub),294 ipc(ipc_stub),
293 map(std::make_shared<mcl::ConnectionSurfaceMap>()),295 map(std::make_shared<mcl::ConnectionSurfaceMap>(std::make_shared<md::ActionQueue>())),
294 factory(std::make_shared<mcl::BufferFactory>()),296 factory(std::make_shared<mcl::BufferFactory>()),
295 vault(297 vault(
296 std::make_shared<mtd::StubClientBufferFactory>(), factory,298 std::make_shared<mtd::StubClientBufferFactory>(), factory,
297299
=== modified file 'tests/integration-tests/test_surfaceloop.cpp'
--- tests/integration-tests/test_surfaceloop.cpp 2017-01-18 02:29:37 +0000
+++ tests/integration-tests/test_surfaceloop.cpp 2017-03-28 00:17:49 +0000
@@ -17,6 +17,7 @@
17 */17 */
1818
19#include "mir_toolkit/mir_client_library.h"19#include "mir_toolkit/mir_client_library.h"
20#include "mir/graphics/buffer_ipc_message.h"
2021
21#include "mir/test/doubles/stub_buffer.h"22#include "mir/test/doubles/stub_buffer.h"
22#include "mir/test/doubles/stub_buffer_allocator.h"23#include "mir/test/doubles/stub_buffer_allocator.h"
@@ -33,6 +34,7 @@
33#include <condition_variable>34#include <condition_variable>
34#include <gmock/gmock.h>35#include <gmock/gmock.h>
35#include <gtest/gtest.h>36#include <gtest/gtest.h>
37#include <src/client/lttng/shared_library_prober_report_tp.h>
36#include "mir/test/gmock_fixes.h"38#include "mir/test/gmock_fixes.h"
3739
38namespace mc = mir::compositor;40namespace mc = mir::compositor;
@@ -44,35 +46,6 @@
4446
45namespace47namespace
46{48{
47geom::Size const size{640, 480};
48MirPixelFormat const format{mir_pixel_format_abgr_8888};
49mg::BufferUsage const usage{mg::BufferUsage::hardware};
50mg::BufferProperties const buffer_properties{size, format, usage};
51
52
53class MockGraphicBufferAllocator : public mtd::StubBufferAllocator
54{
55 public:
56 MockGraphicBufferAllocator()
57 {
58 using testing::_;
59 ON_CALL(*this, alloc_buffer(_))
60 .WillByDefault(testing::Invoke(this, &MockGraphicBufferAllocator::on_create_swapper));
61 }
62
63 MOCK_METHOD1(
64 alloc_buffer,
65 std::shared_ptr<mg::Buffer> (mg::BufferProperties const&));
66
67
68 std::shared_ptr<mg::Buffer> on_create_swapper(mg::BufferProperties const&)
69 {
70 return std::make_shared<mtd::StubBuffer>(::buffer_properties);
71 }
72
73 ~MockGraphicBufferAllocator() noexcept {}
74};
75
76class StubDisplay : public mtd::NullDisplay49class StubDisplay : public mtd::NullDisplay
77{50{
78public:51public:
@@ -96,11 +69,13 @@
96 {69 {
97 public:70 public:
9871
99 CountingStubBuffer()72 CountingStubBuffer(mg::BufferProperties const& props)
73 : StubBuffer(props)
100 {74 {
101 std::lock_guard<std::mutex> lock{buffers_mutex};75 std::lock_guard<std::mutex> lock{buffers_mutex};
102 ++buffers_created;76 ++buffers_created;
103 buffers_cv.notify_one();77 buffers_cv.notify_one();
78 std::cout << "Created buffer with size " << size() << std::endl;
104 }79 }
105 ~CountingStubBuffer()80 ~CountingStubBuffer()
106 {81 {
@@ -118,11 +93,61 @@
118 class StubGraphicBufferAllocator : public mtd::StubBufferAllocator93 class StubGraphicBufferAllocator : public mtd::StubBufferAllocator
119 {94 {
120 public:95 public:
121 std::shared_ptr<mg::Buffer> alloc_buffer(mg::BufferProperties const&) override96 std::shared_ptr<mg::Buffer> alloc_buffer(mg::BufferProperties const& props) override
122 {97 {
123 return std::make_shared<CountingStubBuffer>();98 return std::make_shared<CountingStubBuffer>(props);
124 }99 }
125 };100 };
101<<<<<<< TREE
102=======
103
104 class StubPlatform : public mtd::NullPlatform
105 {
106 public:
107 mir::UniqueModulePtr<mg::GraphicBufferAllocator> create_buffer_allocator() override
108 {
109 return mir::make_module_ptr<StubGraphicBufferAllocator>();
110 }
111
112 mir::UniqueModulePtr<mg::Display> create_display(
113 std::shared_ptr<mg::DisplayConfigurationPolicy> const&,
114 std::shared_ptr<mg::GLConfig> const&) override
115 {
116 return mir::make_module_ptr<StubDisplay>();
117 }
118
119 mir::UniqueModulePtr<mg::PlatformIpcOperations> make_ipc_operations() const override
120 {
121 class BufferPackingIPCOperations : public mtd::NullPlatformIpcOperations
122 {
123 public:
124 void pack_buffer(
125 mg::BufferIpcMessage& message,
126 mg::Buffer const& buffer,
127 mg::BufferIpcMsgType msg_type) const override
128 {
129 if (msg_type == mg::BufferIpcMsgType::full_msg)
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches