16
16
* Authored by: Alexandros Frantzis <alexandros.frantzis@canonical.com>
19
#include "mir_toolkit/mir_client_library.h"
20
#include "mir/compositor/renderer.h"
21
#include "mir/compositor/renderer_factory.h"
22
#include "mir/compositor/display_buffer_compositor.h"
23
#include "mir/compositor/display_buffer_compositor_factory.h"
24
#include "mir/input/composite_event_filter.h"
25
#include "mir/run_mir.h"
26
19
#include "mir/fatal.h"
28
21
#include "mir_test_framework/display_server_test_fixture.h"
29
#include "mir_test/fake_event_hub_input_configuration.h"
30
#include "mir_test/fake_event_hub.h"
31
#include "mir_test_framework/cross_process_sync.h"
32
#include "mir_test_doubles/stub_renderer.h"
34
23
#include <gtest/gtest.h>
40
namespace mc = mir::compositor;
41
namespace mg = mir::graphics;
42
namespace mi = mir::input;
43
namespace mia = mir::input::android;
44
25
namespace mtf = mir_test_framework;
45
namespace mtd = mir::test::doubles;
46
namespace ms = mir::scene;
47
namespace geom = mir::geometry;
52
char const* const mir_test_socket = mtf::test_socket_file().c_str();
54
class StubRendererFactory : public mc::RendererFactory
57
std::unique_ptr<mc::Renderer> create_renderer_for(geom::Rectangle const&, mc::DestinationAlpha)
59
return std::unique_ptr<mc::Renderer>(new mtd::StubRenderer());
63
class ExceptionThrowingDisplayBufferCompositorFactory : public mc::DisplayBufferCompositorFactory
66
std::unique_ptr<mc::DisplayBufferCompositor>
67
create_compositor_for(mg::DisplayBuffer&) override
69
struct ExceptionThrowingDisplayBufferCompositor : mc::DisplayBufferCompositor
71
void composite() override
73
throw std::runtime_error("ExceptionThrowingDisplayBufferCompositor");
77
return std::unique_ptr<mc::DisplayBufferCompositor>(
78
new ExceptionThrowingDisplayBufferCompositor{});
82
void null_surface_callback(MirSurface*, void*)
89
explicit Flag(std::string const& flag_file)
90
: flag_file{flag_file}
92
std::remove(flag_file.c_str());
97
close(open(flag_file.c_str(), O_CREAT, S_IWUSR | S_IRUSR));
103
if ((fd = open(flag_file.c_str(), O_RDONLY, S_IWUSR | S_IRUSR)) != -1)
114
std::this_thread::sleep_for(std::chrono::milliseconds(1));
118
std::string const flag_file;
121
struct FakeEventHubServerConfig : TestingServerConfiguration
123
std::shared_ptr<mi::InputConfiguration> the_input_configuration() override
125
if (!input_configuration)
127
input_configuration =
128
std::make_shared<mtd::FakeEventHubInputConfiguration>(
129
the_input_dispatcher(),
131
the_cursor_listener(),
132
the_touch_visualizer(),
136
return input_configuration;
139
std::shared_ptr<mi::InputManager> the_input_manager() override
141
return DefaultServerConfiguration::the_input_manager();
144
std::shared_ptr<mir::shell::InputTargeter> the_input_targeter() override
146
return DefaultServerConfiguration::the_input_targeter();
149
std::shared_ptr<mir::input::InputDispatcher> the_input_dispatcher() override
151
return DefaultServerConfiguration::the_input_dispatcher();
154
mia::FakeEventHub* the_fake_event_hub()
156
the_input_configuration();
157
return input_configuration->the_fake_event_hub();
160
std::shared_ptr<mtd::FakeEventHubInputConfiguration> input_configuration;
163
void null_lifecycle_callback(MirConnection*, MirLifecycleState, void*)
169
27
using ServerShutdown = BespokeDisplayServerTestFixture;
171
TEST_F(ServerShutdown, server_can_shut_down_when_clients_are_blocked)
173
Flag next_buffer_done1{"next_buffer_done1_c5d49978.tmp"};
174
Flag next_buffer_done2{"next_buffer_done2_c5d49978.tmp"};
175
Flag next_buffer_done3{"next_buffer_done3_c5d49978.tmp"};
176
Flag server_done{"server_done_c5d49978.tmp"};
178
struct ServerConfig : TestingServerConfiguration
180
std::shared_ptr<mc::RendererFactory> the_renderer_factory() override
182
return renderer_factory([] { return std::make_shared<StubRendererFactory>(); });
186
launch_server_process(server_config);
188
struct ClientConfig : TestingClientConfiguration
190
ClientConfig(Flag& next_buffer_done,
192
: next_buffer_done(next_buffer_done),
193
server_done(server_done)
199
MirConnection* connection = mir_connect_sync(mir_test_socket, __PRETTY_FUNCTION__);
201
ASSERT_TRUE(connection != NULL);
203
/* Default lifecycle handler terminates the process on disconnect, so override it */
204
mir_connection_set_lifecycle_event_callback(connection, null_lifecycle_callback, nullptr);
206
MirSurfaceParameters const request_params =
210
mir_pixel_format_abgr_8888,
211
mir_buffer_usage_hardware,
212
mir_display_output_id_invalid
215
MirSurface* surf = mir_connection_create_surface_sync(connection, &request_params);
217
/* Ask for the first buffer (should succeed) */
218
mir_surface_swap_buffers_sync(surf);
219
/* Ask for the first second buffer (should block) */
220
mir_surface_swap_buffers(surf, null_surface_callback, nullptr);
222
next_buffer_done.set();
225
mir_connection_release(connection);
229
Flag& next_buffer_done;
233
ClientConfig client_config1{next_buffer_done1, server_done};
234
ClientConfig client_config2{next_buffer_done2, server_done};
235
ClientConfig client_config3{next_buffer_done3, server_done};
237
launch_client_process(client_config1);
238
launch_client_process(client_config2);
239
launch_client_process(client_config3);
241
run_in_test_process([&]
243
/* Wait until the clients are blocked on getting the second buffer */
244
next_buffer_done1.wait();
245
next_buffer_done2.wait();
246
next_buffer_done3.wait();
248
/* Shutting down the server should not block */
249
shutdown_server_process();
251
/* Notify the clients that we are done (we only need to set the flag once) */
256
TEST_F(ServerShutdown, server_releases_resources_on_shutdown_with_connected_clients)
258
Flag surface_created1{"surface_created1_7e9c69fc.tmp"};
259
Flag surface_created2{"surface_created2_7e9c69fc.tmp"};
260
Flag surface_created3{"surface_created3_7e9c69fc.tmp"};
261
Flag server_done{"server_done_7e9c69fc.tmp"};
262
Flag resources_freed_success{"resources_free_success_7e9c69fc.tmp"};
263
Flag resources_freed_failure{"resources_free_failure_7e9c69fc.tmp"};
265
auto server_config = std::make_shared<FakeEventHubServerConfig>();
266
launch_server_process(*server_config);
268
struct ClientConfig : TestingClientConfiguration
270
ClientConfig(Flag& surface_created,
272
: surface_created(surface_created),
273
server_done(server_done)
279
MirConnection* connection = mir_connect_sync(mir_test_socket, __PRETTY_FUNCTION__);
281
ASSERT_TRUE(connection != NULL);
283
MirSurfaceParameters const request_params =
287
mir_pixel_format_abgr_8888,
288
mir_buffer_usage_hardware,
289
mir_display_output_id_invalid
292
mir_connection_create_surface_sync(connection, &request_params);
294
surface_created.set();
297
mir_connection_release(connection);
300
Flag& surface_created;
304
ClientConfig client_config1{surface_created1, server_done};
305
ClientConfig client_config2{surface_created2, server_done};
306
ClientConfig client_config3{surface_created3, server_done};
308
launch_client_process(client_config1);
309
launch_client_process(client_config2);
310
launch_client_process(client_config3);
312
run_in_test_process([&]
314
/* Wait until the clients have created a surface */
315
surface_created1.wait();
316
surface_created2.wait();
317
surface_created3.wait();
319
/* Shut down the server */
320
shutdown_server_process();
322
/* Wait until we have checked the resources in the server process */
323
while (!resources_freed_failure.is_set() && !resources_freed_success.is_set())
324
std::this_thread::sleep_for(std::chrono::milliseconds(1));
326
/* Fail if the resources have not been freed */
327
if (resources_freed_failure.is_set())
330
/* Notify the clients that we are done (we only need to set the flag once) */
333
wait_for_shutdown_client_processes();
337
* Check that all resources are freed after destroying the server config.
338
* Note that these checks are run multiple times: in the server process,
339
* in each of the client processes and in the test process. We only care about
340
* the results in the server process (in the other cases the checks will
341
* succeed anyway, since we are not using the config object).
343
std::weak_ptr<mir::graphics::Display> display = server_config->the_display();
344
std::weak_ptr<mir::compositor::Compositor> compositor = server_config->the_compositor();
345
std::weak_ptr<mir::frontend::Connector> connector = server_config->the_connector();
346
std::weak_ptr<mir::input::InputManager> input_manager = server_config->the_input_manager();
348
server_config.reset();
350
EXPECT_EQ(0, display.use_count());
351
EXPECT_EQ(0, compositor.use_count());
352
EXPECT_EQ(0, connector.use_count());
353
EXPECT_EQ(0, input_manager.use_count());
355
if (display.use_count() != 0 ||
356
compositor.use_count() != 0 ||
357
connector.use_count() != 0 ||
358
input_manager.use_count() != 0)
360
resources_freed_failure.set();
364
resources_freed_success.set();
370
31
bool file_exists(std::string const& filename)
591
252
::testing::Values(SIGQUIT, SIGABRT, SIGFPE, SIGSEGV, SIGBUS));
593
TEST(ServerShutdownWithThreadException,
594
server_releases_resources_on_abnormal_input_thread_termination)
596
auto server_config = std::make_shared<FakeEventHubServerConfig>();
597
auto fake_event_hub = server_config->the_fake_event_hub();
603
mir::run_mir(*server_config, [](mir::DisplayServer&){}),
607
fake_event_hub->throw_exception_in_next_get_events();
610
std::weak_ptr<mir::graphics::Display> display = server_config->the_display();
611
std::weak_ptr<mir::compositor::Compositor> compositor = server_config->the_compositor();
612
std::weak_ptr<mir::frontend::Connector> connector = server_config->the_connector();
613
std::weak_ptr<mir::input::InputManager> input_manager = server_config->the_input_manager();
615
server_config.reset();
617
EXPECT_EQ(0, display.use_count());
618
EXPECT_EQ(0, compositor.use_count());
619
EXPECT_EQ(0, connector.use_count());
620
EXPECT_EQ(0, input_manager.use_count());
623
TEST(ServerShutdownWithThreadException,
624
server_releases_resources_on_abnormal_compositor_thread_termination)
626
struct ServerConfig : TestingServerConfiguration
628
std::shared_ptr<mc::DisplayBufferCompositorFactory>
629
the_display_buffer_compositor_factory() override
631
return display_buffer_compositor_factory(
634
return std::make_shared<ExceptionThrowingDisplayBufferCompositorFactory>();
639
auto server_config = std::make_shared<ServerConfig>();
645
mir::run_mir(*server_config, [](mir::DisplayServer&){}),
651
std::weak_ptr<mir::graphics::Display> display = server_config->the_display();
652
std::weak_ptr<mir::compositor::Compositor> compositor = server_config->the_compositor();
653
std::weak_ptr<mir::frontend::Connector> connector = server_config->the_connector();
654
std::weak_ptr<mir::input::InputManager> input_manager = server_config->the_input_manager();
656
server_config.reset();
658
EXPECT_EQ(0, display.use_count());
659
EXPECT_EQ(0, compositor.use_count());
660
EXPECT_EQ(0, connector.use_count());
661
EXPECT_EQ(0, input_manager.use_count());