Merge lp:~thomas-voss/location-service/factor-out-runtime into lp:location-service/15.04

Proposed by Thomas Voß
Status: Merged
Approved by: Alberto Mardegan
Approved revision: 138
Merged at revision: 205
Proposed branch: lp:~thomas-voss/location-service/factor-out-runtime
Merge into: lp:location-service/15.04
Diff against target: 613 lines (+351/-72)
9 files modified
src/location_service/com/ubuntu/location/CMakeLists.txt (+1/-0)
src/location_service/com/ubuntu/location/service/daemon.cpp (+10/-43)
src/location_service/com/ubuntu/location/service/provider_daemon.cpp (+11/-16)
src/location_service/com/ubuntu/location/service/runtime.cpp (+109/-0)
src/location_service/com/ubuntu/location/service/runtime.h (+90/-0)
tests/CMakeLists.txt (+1/-0)
tests/acceptance_tests.cpp (+10/-12)
tests/position_test.cpp (+1/-1)
tests/runtime_test.cpp (+118/-0)
To merge this branch: bzr merge lp:~thomas-voss/location-service/factor-out-runtime
Reviewer Review Type Date Requested Status
Alberto Mardegan (community) Approve
Review via email: mp+278674@code.launchpad.net

This proposal supersedes a proposal from 2015-11-19.

Commit message

- Factor out service::Runtime from daemon.cpp into its own .h/.cpp pair of files.
- Add test cases around correct operation of service::Runtime.

Description of the change

- Factor out service::Runtime from daemon.cpp into its own .h/.cpp pair of files.
- Add test cases around correct operation of service::Runtime.

To post a comment you must log in.
138. By Thomas Voß

Remove dependency on robustify-...

Revision history for this message
Alberto Mardegan (mardy) wrote :

LGTM!

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'src/location_service/com/ubuntu/location/CMakeLists.txt'
--- src/location_service/com/ubuntu/location/CMakeLists.txt 2015-04-23 14:48:44 +0000
+++ src/location_service/com/ubuntu/location/CMakeLists.txt 2015-11-26 08:30:38 +0000
@@ -38,6 +38,7 @@
38 service/harvester.cpp38 service/harvester.cpp
39 service/demultiplexing_reporter.h39 service/demultiplexing_reporter.h
40 service/demultiplexing_reporter.cpp40 service/demultiplexing_reporter.cpp
41 service/runtime.cpp
41 service/runtime_tests.h42 service/runtime_tests.h
42 service/runtime_tests.cpp43 service/runtime_tests.cpp
43 service/trust_store_permission_manager.cpp44 service/trust_store_permission_manager.cpp
4445
=== modified file 'src/location_service/com/ubuntu/location/service/daemon.cpp'
--- src/location_service/com/ubuntu/location/service/daemon.cpp 2015-10-23 13:43:32 +0000
+++ src/location_service/com/ubuntu/location/service/daemon.cpp 2015-11-26 08:30:38 +0000
@@ -20,6 +20,7 @@
20#include <com/ubuntu/location/boost_ptree_settings.h>20#include <com/ubuntu/location/boost_ptree_settings.h>
21#include <com/ubuntu/location/provider_factory.h>21#include <com/ubuntu/location/provider_factory.h>
2222
23#include <com/ubuntu/location/logging.h>
23#include <com/ubuntu/location/connectivity/dummy_connectivity_manager.h>24#include <com/ubuntu/location/connectivity/dummy_connectivity_manager.h>
2425
25#include <com/ubuntu/location/service/default_configuration.h>26#include <com/ubuntu/location/service/default_configuration.h>
@@ -32,6 +33,7 @@
3233
33#include "program_options.h"34#include "program_options.h"
34#include "daemon.h"35#include "daemon.h"
36#include "runtime.h"
3537
36#include <core/dbus/announcer.h>38#include <core/dbus/announcer.h>
37#include <core/dbus/resolver.h>39#include <core/dbus/resolver.h>
@@ -39,6 +41,8 @@
3941
40#include <core/posix/signal.h>42#include <core/posix/signal.h>
4143
44#include <boost/asio.hpp>
45
42#include <system_error>46#include <system_error>
43#include <thread>47#include <thread>
4448
@@ -177,6 +181,8 @@
177 trap->stop();181 trap->stop();
178 });182 });
179183
184 auto runtime = location::service::Runtime::create();
185
180 const location::Configuration empty_provider_configuration;186 const location::Configuration empty_provider_configuration;
181187
182 std::set<location::Provider::Ptr> instantiated_providers;188 std::set<location::Provider::Ptr> instantiated_providers;
@@ -203,8 +209,10 @@
203 }209 }
204 }210 }
205211
206 config.incoming->install_executor(dbus::asio::make_executor(config.incoming));212 config.incoming->install_executor(dbus::asio::make_executor(config.incoming, runtime->service()));
207 config.outgoing->install_executor(dbus::asio::make_executor(config.outgoing));213 config.outgoing->install_executor(dbus::asio::make_executor(config.outgoing, runtime->service()));
214
215 runtime->start();
208216
209 location::service::DefaultConfiguration dc;217 location::service::DefaultConfiguration dc;
210218
@@ -222,50 +230,9 @@
222 };230 };
223231
224 auto location_service = std::make_shared<location::service::Implementation>(configuration);232 auto location_service = std::make_shared<location::service::Implementation>(configuration);
225 // We need to ensure that any exception raised by the executor does not crash the app
226 // and also gets logged.
227 auto execute = [] (std::shared_ptr<core::dbus::Bus> bus) {
228 while(true)
229 {
230 try
231 {
232 VLOG(10) << "Starting a bus executor";
233 bus->run();
234 break; // run() exited normally
235 }
236 catch (const std::exception& e)
237 {
238 LOG(WARNING) << e.what();
239 }
240 catch (...)
241 {
242 LOG(WARNING) << "Unexpected exception was raised by the bus executor";
243 }
244 }
245 };
246
247 std::thread t1{execute, config.incoming};
248 std::thread t2{execute, config.incoming};
249 std::thread t3{execute, config.incoming};
250 std::thread t4{execute, config.outgoing};
251233
252 trap->run();234 trap->run();
253235
254 config.incoming->stop();
255 config.outgoing->stop();
256
257 if (t1.joinable())
258 t1.join();
259
260 if (t2.joinable())
261 t2.join();
262
263 if (t3.joinable())
264 t3.join();
265
266 if (t4.joinable())
267 t4.join();
268
269 return EXIT_SUCCESS;236 return EXIT_SUCCESS;
270}237}
271238
272239
=== modified file 'src/location_service/com/ubuntu/location/service/provider_daemon.cpp'
--- src/location_service/com/ubuntu/location/service/provider_daemon.cpp 2014-10-27 21:58:16 +0000
+++ src/location_service/com/ubuntu/location/service/provider_daemon.cpp 2015-11-26 08:30:38 +0000
@@ -25,6 +25,7 @@
2525
26#include <com/ubuntu/location/service/configuration.h>26#include <com/ubuntu/location/service/configuration.h>
27#include <com/ubuntu/location/service/program_options.h>27#include <com/ubuntu/location/service/program_options.h>
28#include <com/ubuntu/location/service/runtime.h>
2829
29#include <core/dbus/asio/executor.h>30#include <core/dbus/asio/executor.h>
3031
@@ -65,7 +66,6 @@
65 location::service::ProviderDaemon::Configuration result;66 location::service::ProviderDaemon::Configuration result;
6667
67 result.connection = factory(mutable_daemon_options().bus());68 result.connection = factory(mutable_daemon_options().bus());
68 result.connection->install_executor(core::dbus::asio::make_executor(result.connection));
6969
70 auto service = core::dbus::Service::add_service(70 auto service = core::dbus::Service::add_service(
71 result.connection,71 result.connection,
@@ -108,7 +108,7 @@
108 return result;108 return result;
109}109}
110110
111int location::service::ProviderDaemon::main(const location::service::ProviderDaemon::Configuration& configuration)111int location::service::ProviderDaemon::main(const location::service::ProviderDaemon::Configuration& config)
112{112{
113 auto trap = core::posix::trap_signals_for_all_subsequent_threads(113 auto trap = core::posix::trap_signals_for_all_subsequent_threads(
114 {114 {
@@ -121,27 +121,22 @@
121 trap->stop();121 trap->stop();
122 });122 });
123123
124 std::thread worker124 auto runtime = location::service::Runtime::create(1);
125 {125
126 [configuration]()126 config.connection->install_executor(core::dbus::asio::make_executor(config.connection, runtime->service()));
127 {
128 configuration.connection->run();
129 }
130 };
131127
132 auto skeleton = location::providers::remote::skeleton::create_with_configuration(location::providers::remote::skeleton::Configuration128 auto skeleton = location::providers::remote::skeleton::create_with_configuration(location::providers::remote::skeleton::Configuration
133 {129 {
134 configuration.object,130 config.object,
135 configuration.connection,131 config.connection,
136 configuration.provider132 config.provider
137 });133 });
138134
135 runtime->start();
136
139 trap->run();137 trap->run();
140138
141 configuration.connection->stop();139 config.connection->stop();
142
143 if (worker.joinable())
144 worker.join();
145140
146 return EXIT_SUCCESS;141 return EXIT_SUCCESS;
147}142}
148143
=== added file 'src/location_service/com/ubuntu/location/service/runtime.cpp'
--- src/location_service/com/ubuntu/location/service/runtime.cpp 1970-01-01 00:00:00 +0000
+++ src/location_service/com/ubuntu/location/service/runtime.cpp 2015-11-26 08:30:38 +0000
@@ -0,0 +1,109 @@
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 PARTIlocationAR 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: Thomas Voß <thomas.voss@canonical.com>
17 */
18#include <com/ubuntu/location/service/runtime.h>
19
20#include <com/ubuntu/location/logging.h>
21
22namespace culs = com::ubuntu::location::service;
23
24namespace
25{
26// exception_safe_run runs service, catching all exceptions and
27// restarting operation until an explicit shutdown has been requested.
28//
29// TODO(tvoss): Catching all exceptions is risky as they might signal unrecoverable
30// errors. We should enable calling code to decide whether an exception should be considered
31// fatal or not.
32void exception_safe_run(boost::asio::io_service& service)
33{
34 while (true)
35 {
36 try
37 {
38 service.run();
39 // a clean return from run only happens in case of
40 // stop() being called (we are keeping the service alive with
41 // a service::work instance).
42 break;
43 }
44 catch (const std::exception& e)
45 {
46 LOG(WARNING) << e.what();
47 }
48 catch (...)
49 {
50 LOG(WARNING) << "Unknown exception caught while executing boost::asio::io_service";
51 }
52 }
53}
54}
55
56std::shared_ptr<culs::Runtime> culs::Runtime::create(std::uint32_t pool_size)
57{
58 return std::shared_ptr<culs::Runtime>(new culs::Runtime(pool_size));
59}
60
61culs::Runtime::Runtime(std::uint32_t pool_size)
62 : pool_size_{pool_size},
63 service_{pool_size_},
64 strand_{service_},
65 keep_alive_{service_}
66{
67}
68
69culs::Runtime::~Runtime()
70{
71 try
72 {
73 stop();
74 } catch(...)
75 {
76 // Dropping all exceptions to satisfy the nothrow guarantee.
77 }
78}
79
80void culs::Runtime::start()
81{
82 for (unsigned int i = 0; i < pool_size_; i++)
83 workers_.push_back(std::thread{exception_safe_run, std::ref(service_)});
84}
85
86void culs::Runtime::stop()
87{
88 service_.stop();
89
90 for (auto& worker : workers_)
91 if (worker.joinable())
92 worker.join();
93}
94
95std::function<void(std::function<void()>)> culs::Runtime::to_dispatcher_functional()
96{
97 // We have to make sure that we stay alive for as long as
98 // calling code requires the dispatcher to work.
99 auto sp = shared_from_this();
100 return [sp](std::function<void()> task)
101 {
102 sp->strand_.post(task);
103 };
104}
105
106boost::asio::io_service& culs::Runtime::service()
107{
108 return service_;
109}
0110
=== added file 'src/location_service/com/ubuntu/location/service/runtime.h'
--- src/location_service/com/ubuntu/location/service/runtime.h 1970-01-01 00:00:00 +0000
+++ src/location_service/com/ubuntu/location/service/runtime.h 2015-11-26 08:30:38 +0000
@@ -0,0 +1,90 @@
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 PARTIlocationAR 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: Thomas Voß <thomas.voss@canonical.com>
17 */
18#ifndef COM_UBUNTU_LOCATION_SERVICE_RUNTIME_H_
19#define COM_UBUNTU_LOCATION_SERVICE_RUNTIME_H_
20
21#include <boost/asio.hpp>
22
23#include <functional>
24#include <memory>
25#include <thread>
26#include <vector>
27
28#include <cstdint>
29
30namespace com
31{
32namespace ubuntu
33{
34namespace location
35{
36namespace service
37{
38// We bundle our "global" runtime dependencies here, specifically
39// a dispatcher to decouple multiple in-process providers from one
40// another , forcing execution to a well known set of threads.
41class Runtime : public std::enable_shared_from_this<Runtime>
42{
43public:
44 // Our default concurrency setup.
45 static constexpr const std::uint32_t worker_threads = 2;
46
47 // create returns a Runtime instance with pool_size worker threads
48 // executing the underlying service.
49 static std::shared_ptr<Runtime> create(std::uint32_t pool_size = worker_threads);
50
51 Runtime(const Runtime&) = delete;
52 Runtime(Runtime&&) = delete;
53 // Tears down the runtime, stopping all worker threads.
54 ~Runtime() noexcept(true);
55 Runtime& operator=(const Runtime&) = delete;
56 Runtime& operator=(Runtime&&) = delete;
57
58 // start executes the underlying io_service on a thread pool with
59 // the size configured at creation time.
60 void start();
61
62 // stop cleanly shuts down a Runtime instance,
63 // joining all worker threads.
64 void stop();
65
66 // to_dispatcher_functional returns a function for integration
67 // with components that expect a dispatcher for operation.
68 std::function<void(std::function<void()>)> to_dispatcher_functional();
69
70 // service returns the underlying boost::asio::io_service that is executed
71 // by the Runtime.
72 boost::asio::io_service& service();
73
74private:
75 // Runtime constructs a new instance, firing up pool_size
76 // worker threads.
77 Runtime(std::uint32_t pool_size);
78
79 std::uint32_t pool_size_;
80 boost::asio::io_service service_;
81 boost::asio::io_service::strand strand_;
82 boost::asio::io_service::work keep_alive_;
83 std::vector<std::thread> workers_;
84};
85}
86}
87}
88}
89
90#endif // COM_UBUNTU_LOCATION_SERVICE_RUNTIME_H_
091
=== modified file 'tests/CMakeLists.txt'
--- tests/CMakeLists.txt 2015-04-23 17:04:09 +0000
+++ tests/CMakeLists.txt 2015-11-26 08:30:38 +0000
@@ -92,6 +92,7 @@
92LOCATION_SERVICE_ADD_TEST(provider_test provider_test.cpp)92LOCATION_SERVICE_ADD_TEST(provider_test provider_test.cpp)
93LOCATION_SERVICE_ADD_TEST(wgs84_test wgs84_test.cpp)93LOCATION_SERVICE_ADD_TEST(wgs84_test wgs84_test.cpp)
94LOCATION_SERVICE_ADD_TEST(trust_store_permission_manager_test trust_store_permission_manager_test.cpp)94LOCATION_SERVICE_ADD_TEST(trust_store_permission_manager_test trust_store_permission_manager_test.cpp)
95LOCATION_SERVICE_ADD_TEST(runtime_test runtime_test.cpp)
9596
96# Provider-specific test-cases go here.97# Provider-specific test-cases go here.
97if (LOCATION_SERVICE_ENABLE_GPS_PROVIDER)98if (LOCATION_SERVICE_ENABLE_GPS_PROVIDER)
9899
=== modified file 'tests/acceptance_tests.cpp'
--- tests/acceptance_tests.cpp 2015-02-13 13:19:18 +0000
+++ tests/acceptance_tests.cpp 2015-11-26 08:30:38 +0000
@@ -38,12 +38,14 @@
38#include <com/ubuntu/location/service/stub.h>38#include <com/ubuntu/location/service/stub.h>
3939
40#include <core/dbus/announcer.h>40#include <core/dbus/announcer.h>
41#include <core/dbus/bus.h>
41#include <core/dbus/fixture.h>42#include <core/dbus/fixture.h>
42#include <core/dbus/resolver.h>43#include <core/dbus/resolver.h>
4344
44#include <core/dbus/asio/executor.h>45#include <core/dbus/asio/executor.h>
4546
46#include <core/posix/signal.h>47#include <core/posix/signal.h>
48#include <core/posix/this_process.h>
4749
48#include <core/testing/cross_process_sync.h>50#include <core/testing/cross_process_sync.h>
49#include <core/testing/fork_and_run.h>51#include <core/testing/fork_and_run.h>
@@ -708,7 +710,7 @@
708710
709 options.add(Keys::update_period,711 options.add(Keys::update_period,
710 "Update period length for dummy::Provider setup.",712 "Update period length for dummy::Provider setup.",
711 std::uint32_t{100});713 std::uint32_t{10});
712714
713 options.add(Keys::client_count,715 options.add(Keys::client_count,
714 "Number of clients that should be fired up.",716 "Number of clients that should be fired up.",
@@ -761,6 +763,8 @@
761};763};
762}764}
763765
766#include "did_finish_successfully.h"
767
764TEST_F(LocationServiceStandaloneLoad, MultipleClientsConnectingAndDisconnectingWorks)768TEST_F(LocationServiceStandaloneLoad, MultipleClientsConnectingAndDisconnectingWorks)
765{769{
766 EXPECT_TRUE(trust_store_is_set_up_for_testing);770 EXPECT_TRUE(trust_store_is_set_up_for_testing);
@@ -801,8 +805,8 @@
801 };805 };
802806
803 cul::service::Daemon::Configuration config;807 cul::service::Daemon::Configuration config;
804 config.incoming = session_bus();808 config.incoming = std::make_shared<core::dbus::Bus>(core::posix::this_process::env::get_or_throw("DBUS_SESSION_BUS_ADDRESS"));
805 config.outgoing = session_bus();809 config.outgoing = std::make_shared<core::dbus::Bus>(core::posix::this_process::env::get_or_throw("DBUS_SESSION_BUS_ADDRESS"));
806 config.is_testing_enabled = false;810 config.is_testing_enabled = false;
807 config.providers =811 config.providers =
808 {812 {
@@ -829,7 +833,7 @@
829 status;833 status;
830 }, core::posix::StandardStream::empty);834 }, core::posix::StandardStream::empty);
831835
832 std::this_thread::sleep_for(std::chrono::seconds{2});836 std::this_thread::sleep_for(std::chrono::seconds{15});
833837
834 auto client = [this]()838 auto client = [this]()
835 {839 {
@@ -957,17 +961,11 @@
957 {961 {
958 VLOG(1) << "Stopping client...: " << client.pid();962 VLOG(1) << "Stopping client...: " << client.pid();
959 client.send_signal_or_throw(core::posix::Signal::sig_term);963 client.send_signal_or_throw(core::posix::Signal::sig_term);
960 auto result = client.wait_for(core::posix::wait::Flags::untraced);964 EXPECT_TRUE(did_finish_successfully(client.wait_for(core::posix::wait::Flags::untraced)));
961
962 EXPECT_EQ(core::posix::wait::Result::Status::exited, result.status);
963 EXPECT_EQ(core::posix::exit::Status::success, result.detail.if_exited.status);
964 }965 }
965966
966 VLOG(1) << "Cleaned up clients, shutting down the service...";967 VLOG(1) << "Cleaned up clients, shutting down the service...";
967968
968 server.send_signal_or_throw(core::posix::Signal::sig_term);969 server.send_signal_or_throw(core::posix::Signal::sig_term);
969 auto result = server.wait_for(core::posix::wait::Flags::untraced);970 EXPECT_TRUE(did_finish_successfully(server.wait_for(core::posix::wait::Flags::untraced)));
970
971 EXPECT_EQ(core::posix::wait::Result::Status::exited, result.status);
972 EXPECT_EQ(core::posix::exit::Status::success, result.detail.if_exited.status);
973}971}
974972
=== modified file 'tests/position_test.cpp'
--- tests/position_test.cpp 2014-06-20 07:40:34 +0000
+++ tests/position_test.cpp 2015-11-26 08:30:38 +0000
@@ -40,7 +40,7 @@
40 cul::wgs84::Latitude{},40 cul::wgs84::Latitude{},
41 cul::wgs84::Longitude{},41 cul::wgs84::Longitude{},
42 cul::wgs84::Altitude{}};42 cul::wgs84::Altitude{}};
43 EXPECT_TRUE(p.altitude);43 EXPECT_TRUE(p.altitude ? true : false);
44}44}
4545
46#include <com/ubuntu/location/codec.h>46#include <com/ubuntu/location/codec.h>
4747
=== added file 'tests/runtime_test.cpp'
--- tests/runtime_test.cpp 1970-01-01 00:00:00 +0000
+++ tests/runtime_test.cpp 2015-11-26 08:30:38 +0000
@@ -0,0 +1,118 @@
1/*
2 * Copyright © 2015Canonical 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: Thomas Voß <thomas.voss@canonical.com>
17 */
18#include <com/ubuntu/location/service/runtime.h>
19
20#include <gtest/gtest.h>
21
22#include <condition_variable>
23#include <thread>
24
25namespace culs = com::ubuntu::location::service;
26
27TEST(Runtime, cleanly_shuts_down_threads)
28{
29 culs::Runtime::create();
30}
31
32TEST(Runtime, executes_service)
33{
34 std::mutex m;
35 std::unique_lock<std::mutex> ul{m};
36 std::condition_variable wc;
37
38 bool signaled = false;
39
40 auto rt = culs::Runtime::create();
41 rt->start();
42 boost::asio::deadline_timer timer{rt->service(), boost::posix_time::milliseconds(500)};
43 timer.async_wait([&wc, &signaled](const boost::system::error_code&)
44 {
45 signaled = true;
46 wc.notify_all();
47 });
48
49 auto result = wc.wait_for(ul, std::chrono::seconds{1}, [&signaled]() { return signaled; });
50 EXPECT_TRUE(result);
51}
52
53TEST(Runtime, catches_exceptions_thrown_from_handlers)
54{
55 std::mutex m;
56 std::unique_lock<std::mutex> ul{m};
57 std::condition_variable wc;
58
59 bool signaled = false;
60
61 auto rt = culs::Runtime::create();
62 rt->start();
63 boost::asio::deadline_timer fast{rt->service(), boost::posix_time::milliseconds(100)};
64 fast.async_wait([](const boost::system::error_code&)
65 {
66 throw std::runtime_error{"Should not propagate"};
67 });
68
69 boost::asio::deadline_timer slow{rt->service(), boost::posix_time::milliseconds(500)};
70 slow.async_wait([&wc, &signaled](const boost::system::error_code&)
71 {
72 signaled = true;
73 wc.notify_all();
74 });
75
76 auto result = wc.wait_for(ul, std::chrono::seconds{1}, [&signaled]() { return signaled; });
77 EXPECT_TRUE(result);
78}
79
80// sets_up_pool_of_threads ensures that the pool size
81// passed to the Runtime on construction is honored. The idea is simple:
82// We set up two deadline timers, fast and slow. fast fires before slow,
83// with fast blocking in a wait on a common condition_variable. When slow
84// fires, it notifies the condition variable, thereby unblocking the handler of fast,
85// enabling clean shutdown without errors and timeouts. This only works if the
86// pool contains at least 2 threads. Otherwise, the handler of slow would not be executed
87// until the handler of fast times out in the wait, marking the test as failed.
88TEST(Runtime, sets_up_pool_of_threads)
89{
90 struct State
91 {
92 bool signaled{false};
93 std::mutex m;
94 std::condition_variable wc;
95 };
96
97 auto state = std::make_shared<State>();
98
99 auto rt = culs::Runtime::create(2);
100 rt->start();
101 boost::asio::deadline_timer fast{rt->service(), boost::posix_time::milliseconds(100)};
102 fast.async_wait([state](const boost::system::error_code&)
103 {
104 std::unique_lock<std::mutex> ul{state->m};
105 EXPECT_TRUE(state->wc.wait_for(ul, std::chrono::seconds{1}, [state]() { return state->signaled; }));
106 });
107
108 boost::asio::deadline_timer slow{rt->service(), boost::posix_time::milliseconds(500)};
109 slow.async_wait([state](const boost::system::error_code&)
110 {
111 state->signaled = true;
112 state->wc.notify_all();
113 });
114
115 std::unique_lock<std::mutex> ul{state->m};
116 auto result = state->wc.wait_for(ul, std::chrono::seconds{1}, [state]() { return state->signaled; });
117 EXPECT_TRUE(result);
118}

Subscribers

People subscribed via source and target branches