diff options
Diffstat (limited to '3rdparty/asio/src/tests/unit/strand.cpp')
-rw-r--r-- | 3rdparty/asio/src/tests/unit/strand.cpp | 224 |
1 files changed, 224 insertions, 0 deletions
diff --git a/3rdparty/asio/src/tests/unit/strand.cpp b/3rdparty/asio/src/tests/unit/strand.cpp new file mode 100644 index 00000000000..02a0f7d58fa --- /dev/null +++ b/3rdparty/asio/src/tests/unit/strand.cpp @@ -0,0 +1,224 @@ +// +// strand.cpp +// ~~~~~~~~~~ +// +// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Disable autolinking for unit tests. +#if !defined(BOOST_ALL_NO_LIB) +#define BOOST_ALL_NO_LIB 1 +#endif // !defined(BOOST_ALL_NO_LIB) + +// Test that header file is self-contained. +#include "asio/strand.hpp" + +#include <sstream> +#include "asio/io_context.hpp" +#include "asio/dispatch.hpp" +#include "asio/post.hpp" +#include "asio/thread.hpp" +#include "unit_test.hpp" + +#if defined(ASIO_HAS_BOOST_DATE_TIME) +# include "asio/deadline_timer.hpp" +#else // defined(ASIO_HAS_BOOST_DATE_TIME) +# include "asio/steady_timer.hpp" +#endif // defined(ASIO_HAS_BOOST_DATE_TIME) + +#if defined(ASIO_HAS_BOOST_BIND) +# include <boost/bind.hpp> +#else // defined(ASIO_HAS_BOOST_BIND) +# include <functional> +#endif // defined(ASIO_HAS_BOOST_BIND) + +using namespace asio; + +#if defined(ASIO_HAS_BOOST_BIND) +namespace bindns = boost; +#else // defined(ASIO_HAS_BOOST_BIND) +namespace bindns = std; +#endif + +#if defined(ASIO_HAS_BOOST_DATE_TIME) +typedef deadline_timer timer; +namespace chronons = boost::posix_time; +#elif defined(ASIO_HAS_CHRONO) +typedef steady_timer timer; +namespace chronons = asio::chrono; +#endif // defined(ASIO_HAS_BOOST_DATE_TIME) + +void increment(int* count) +{ + ++(*count); +} + +void increment_without_lock(io_context::strand* s, int* count) +{ + ASIO_CHECK(!s->running_in_this_thread()); + + int original_count = *count; + + dispatch(*s, bindns::bind(increment, count)); + + // No other functions are currently executing through the locking dispatcher, + // so the previous call to dispatch should have successfully nested. + ASIO_CHECK(*count == original_count + 1); +} + +void increment_with_lock(io_context::strand* s, int* count) +{ + ASIO_CHECK(s->running_in_this_thread()); + + int original_count = *count; + + dispatch(*s, bindns::bind(increment, count)); + + // The current function already holds the strand's lock, so the + // previous call to dispatch should have successfully nested. + ASIO_CHECK(*count == original_count + 1); +} + +void sleep_increment(io_context* ioc, int* count) +{ + timer t(*ioc, chronons::seconds(2)); + t.wait(); + + ++(*count); +} + +void start_sleep_increments(io_context* ioc, io_context::strand* s, int* count) +{ + // Give all threads a chance to start. + timer t(*ioc, chronons::seconds(2)); + t.wait(); + + // Start three increments. + post(*s, bindns::bind(sleep_increment, ioc, count)); + post(*s, bindns::bind(sleep_increment, ioc, count)); + post(*s, bindns::bind(sleep_increment, ioc, count)); +} + +void throw_exception() +{ + throw 1; +} + +void io_context_run(io_context* ioc) +{ + ioc->run(); +} + +void strand_test() +{ + io_context ioc; + io_context::strand s(ioc); + int count = 0; + + post(ioc, bindns::bind(increment_without_lock, &s, &count)); + + // No handlers can be called until run() is called. + ASIO_CHECK(count == 0); + + ioc.run(); + + // The run() call will not return until all work has finished. + ASIO_CHECK(count == 1); + + count = 0; + ioc.restart(); + post(s, bindns::bind(increment_with_lock, &s, &count)); + + // No handlers can be called until run() is called. + ASIO_CHECK(count == 0); + + ioc.run(); + + // The run() call will not return until all work has finished. + ASIO_CHECK(count == 1); + + count = 0; + ioc.restart(); + post(ioc, bindns::bind(start_sleep_increments, &ioc, &s, &count)); + thread thread1(bindns::bind(io_context_run, &ioc)); + thread thread2(bindns::bind(io_context_run, &ioc)); + + // Check all events run one after another even though there are two threads. + timer timer1(ioc, chronons::seconds(3)); + timer1.wait(); + ASIO_CHECK(count == 0); +#if defined(ASIO_HAS_BOOST_DATE_TIME) + timer1.expires_at(timer1.expires_at() + chronons::seconds(2)); +#else // defined(ASIO_HAS_BOOST_DATE_TIME) + timer1.expires_at(timer1.expiry() + chronons::seconds(2)); +#endif // defined(ASIO_HAS_BOOST_DATE_TIME) + timer1.wait(); + ASIO_CHECK(count == 1); +#if defined(ASIO_HAS_BOOST_DATE_TIME) + timer1.expires_at(timer1.expires_at() + chronons::seconds(2)); +#else // defined(ASIO_HAS_BOOST_DATE_TIME) + timer1.expires_at(timer1.expiry() + chronons::seconds(2)); +#endif // defined(ASIO_HAS_BOOST_DATE_TIME) + timer1.wait(); + ASIO_CHECK(count == 2); + + thread1.join(); + thread2.join(); + + // The run() calls will not return until all work has finished. + ASIO_CHECK(count == 3); + + count = 0; + int exception_count = 0; + ioc.restart(); + post(s, throw_exception); + post(s, bindns::bind(increment, &count)); + post(s, bindns::bind(increment, &count)); + post(s, throw_exception); + post(s, bindns::bind(increment, &count)); + + // No handlers can be called until run() is called. + ASIO_CHECK(count == 0); + ASIO_CHECK(exception_count == 0); + + for (;;) + { + try + { + ioc.run(); + break; + } + catch (int) + { + ++exception_count; + } + } + + // The run() calls will not return until all work has finished. + ASIO_CHECK(count == 3); + ASIO_CHECK(exception_count == 2); + + count = 0; + ioc.restart(); + + // Check for clean shutdown when handlers posted through an orphaned strand + // are abandoned. + { + io_context::strand s2(ioc); + post(s2, bindns::bind(increment, &count)); + post(s2, bindns::bind(increment, &count)); + post(s2, bindns::bind(increment, &count)); + } + + // No handlers can be called until run() is called. + ASIO_CHECK(count == 0); +} + +ASIO_TEST_SUITE +( + "strand", + ASIO_TEST_CASE(strand_test) +) |