Imported Upstream version 1.57.0
[platform/upstream/boost.git] / libs / asio / test / strand.cpp
1 //
2 // strand.cpp
3 // ~~~~~~~~~~
4 //
5 // Copyright (c) 2003-2014 Christopher M. Kohlhoff (chris at kohlhoff dot com)
6 //
7 // Distributed under the Boost Software License, Version 1.0. (See accompanying
8 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
9 //
10
11 // Disable autolinking for unit tests.
12 #if !defined(BOOST_ALL_NO_LIB)
13 #define BOOST_ALL_NO_LIB 1
14 #endif // !defined(BOOST_ALL_NO_LIB)
15
16 // Test that header file is self-contained.
17 #include <boost/asio/strand.hpp>
18
19 #include <sstream>
20 #include <boost/asio/io_service.hpp>
21 #include <boost/asio/detail/thread.hpp>
22 #include "unit_test.hpp"
23
24 #if defined(BOOST_ASIO_HAS_BOOST_DATE_TIME)
25 # include <boost/asio/deadline_timer.hpp>
26 #else // defined(BOOST_ASIO_HAS_BOOST_DATE_TIME)
27 # include <boost/asio/steady_timer.hpp>
28 #endif // defined(BOOST_ASIO_HAS_BOOST_DATE_TIME)
29
30 #if defined(BOOST_ASIO_HAS_BOOST_BIND)
31 # include <boost/bind.hpp>
32 #else // defined(BOOST_ASIO_HAS_BOOST_BIND)
33 # include <functional>
34 #endif // defined(BOOST_ASIO_HAS_BOOST_BIND)
35
36 using namespace boost::asio;
37 typedef io_service::strand strand;
38
39 #if defined(BOOST_ASIO_HAS_BOOST_BIND)
40 namespace bindns = boost;
41 #else // defined(BOOST_ASIO_HAS_BOOST_BIND)
42 namespace bindns = std;
43 #endif
44
45 #if defined(BOOST_ASIO_HAS_BOOST_DATE_TIME)
46 typedef deadline_timer timer;
47 namespace chronons = boost::posix_time;
48 #elif defined(BOOST_ASIO_HAS_STD_CHRONO)
49 typedef steady_timer timer;
50 namespace chronons = std::chrono;
51 #elif defined(BOOST_ASIO_HAS_BOOST_CHRONO)
52 typedef steady_timer timer;
53 namespace chronons = boost::chrono;
54 #endif // defined(BOOST_ASIO_HAS_BOOST_DATE_TIME)
55
56 void increment(int* count)
57 {
58   ++(*count);
59 }
60
61 void increment_without_lock(strand* s, int* count)
62 {
63   BOOST_ASIO_CHECK(!s->running_in_this_thread());
64
65   int original_count = *count;
66
67   s->dispatch(bindns::bind(increment, count));
68
69   // No other functions are currently executing through the locking dispatcher,
70   // so the previous call to dispatch should have successfully nested.
71   BOOST_ASIO_CHECK(*count == original_count + 1);
72 }
73
74 void increment_with_lock(strand* s, int* count)
75 {
76   BOOST_ASIO_CHECK(s->running_in_this_thread());
77
78   int original_count = *count;
79
80   s->dispatch(bindns::bind(increment, count));
81
82   // The current function already holds the strand's lock, so the
83   // previous call to dispatch should have successfully nested.
84   BOOST_ASIO_CHECK(*count == original_count + 1);
85 }
86
87 void sleep_increment(io_service* ios, int* count)
88 {
89   timer t(*ios, chronons::seconds(2));
90   t.wait();
91
92   ++(*count);
93 }
94
95 void start_sleep_increments(io_service* ios, strand* s, int* count)
96 {
97   // Give all threads a chance to start.
98   timer t(*ios, chronons::seconds(2));
99   t.wait();
100
101   // Start three increments.
102   s->post(bindns::bind(sleep_increment, ios, count));
103   s->post(bindns::bind(sleep_increment, ios, count));
104   s->post(bindns::bind(sleep_increment, ios, count));
105 }
106
107 void throw_exception()
108 {
109   throw 1;
110 }
111
112 void io_service_run(io_service* ios)
113 {
114   ios->run();
115 }
116
117 void strand_test()
118 {
119   io_service ios;
120   strand s(ios);
121   int count = 0;
122
123   ios.post(bindns::bind(increment_without_lock, &s, &count));
124
125   // No handlers can be called until run() is called.
126   BOOST_ASIO_CHECK(count == 0);
127
128   ios.run();
129
130   // The run() call will not return until all work has finished.
131   BOOST_ASIO_CHECK(count == 1);
132
133   count = 0;
134   ios.reset();
135   s.post(bindns::bind(increment_with_lock, &s, &count));
136
137   // No handlers can be called until run() is called.
138   BOOST_ASIO_CHECK(count == 0);
139
140   ios.run();
141
142   // The run() call will not return until all work has finished.
143   BOOST_ASIO_CHECK(count == 1);
144
145   count = 0;
146   ios.reset();
147   ios.post(bindns::bind(start_sleep_increments, &ios, &s, &count));
148   boost::asio::detail::thread thread1(bindns::bind(io_service_run, &ios));
149   boost::asio::detail::thread thread2(bindns::bind(io_service_run, &ios));
150
151   // Check all events run one after another even though there are two threads.
152   timer timer1(ios, chronons::seconds(3));
153   timer1.wait();
154   BOOST_ASIO_CHECK(count == 0);
155   timer1.expires_at(timer1.expires_at() + chronons::seconds(2));
156   timer1.wait();
157   BOOST_ASIO_CHECK(count == 1);
158   timer1.expires_at(timer1.expires_at() + chronons::seconds(2));
159   timer1.wait();
160   BOOST_ASIO_CHECK(count == 2);
161
162   thread1.join();
163   thread2.join();
164
165   // The run() calls will not return until all work has finished.
166   BOOST_ASIO_CHECK(count == 3);
167
168   count = 0;
169   int exception_count = 0;
170   ios.reset();
171   s.post(throw_exception);
172   s.post(bindns::bind(increment, &count));
173   s.post(bindns::bind(increment, &count));
174   s.post(throw_exception);
175   s.post(bindns::bind(increment, &count));
176
177   // No handlers can be called until run() is called.
178   BOOST_ASIO_CHECK(count == 0);
179   BOOST_ASIO_CHECK(exception_count == 0);
180
181   for (;;)
182   {
183     try
184     {
185       ios.run();
186       break;
187     }
188     catch (int)
189     {
190       ++exception_count;
191     }
192   }
193
194   // The run() calls will not return until all work has finished.
195   BOOST_ASIO_CHECK(count == 3);
196   BOOST_ASIO_CHECK(exception_count == 2);
197
198   count = 0;
199   ios.reset();
200
201   // Check for clean shutdown when handlers posted through an orphaned strand
202   // are abandoned.
203   {
204     strand s2(ios);
205     s2.post(bindns::bind(increment, &count));
206     s2.post(bindns::bind(increment, &count));
207     s2.post(bindns::bind(increment, &count));
208   }
209
210   // No handlers can be called until run() is called.
211   BOOST_ASIO_CHECK(count == 0);
212 }
213
214 BOOST_ASIO_TEST_SUITE
215 (
216   "strand",
217   BOOST_ASIO_TEST_CASE(strand_test)
218 )