]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/context/test/test_fiber.cpp
update sources to ceph Nautilus 14.2.1
[ceph.git] / ceph / src / boost / libs / context / test / test_fiber.cpp
1
2 // Copyright Oliver Kowalke 2009.
3 // Distributed under the Boost Software License, Version 1.0.
4 // (See accompanying file LICENSE_1_0.txt or copy at
5 // http://www.boost.org/LICENSE_1_0.txt)
6
7 #include <stdio.h>
8 #include <stdlib.h>
9
10 #include <cmath>
11 #include <cstdint>
12 #include <cstdio>
13 #include <iostream>
14 #include <memory>
15 #include <sstream>
16 #include <stdexcept>
17 #include <string>
18 #include <thread>
19 #include <utility>
20 #include <vector>
21
22 #include <boost/array.hpp>
23 #include <boost/assert.hpp>
24 #include <boost/lexical_cast.hpp>
25 #include <boost/test/unit_test.hpp>
26 #include <boost/utility.hpp>
27 #include <boost/variant.hpp>
28
29 #include <boost/context/fiber.hpp>
30 #include <boost/context/detail/config.hpp>
31
32 #ifdef BOOST_WINDOWS
33 #include <windows.h>
34 #endif
35
36 #if defined(BOOST_MSVC)
37 # pragma warning(push)
38 # pragma warning(disable: 4702 4723 4996)
39 #endif
40
41 typedef boost::variant<int,std::string> variant_t;
42
43 namespace ctx = boost::context;
44
45 int value1 = 0;
46 std::string value2;
47 double value3 = 0.;
48
49 struct X {
50 ctx::fiber foo( ctx::fiber && f, int i) {
51 value1 = i;
52 return std::move( f);
53 }
54 };
55
56 struct Y {
57 Y() {
58 value1 = 3;
59 }
60
61 Y( Y const&) = delete;
62 Y & operator=( Y const&) = delete;
63
64 ~Y() {
65 value1 = 7;
66 }
67 };
68
69 class moveable {
70 public:
71 bool state;
72 int value;
73
74 moveable() :
75 state( false),
76 value( -1) {
77 }
78
79 moveable( int v) :
80 state( true),
81 value( v) {
82 }
83
84 moveable( moveable && other) :
85 state( other.state),
86 value( other.value) {
87 other.state = false;
88 other.value = -1;
89 }
90
91 moveable & operator=( moveable && other) {
92 if ( this == & other) return * this;
93 state = other.state;
94 value = other.value;
95 other.state = false;
96 other.value = -1;
97 return * this;
98 }
99
100 moveable( moveable const& other) = delete;
101 moveable & operator=( moveable const& other) = delete;
102
103 void operator()() {
104 value1 = value;
105 }
106 };
107
108 struct my_exception : public std::runtime_error {
109 ctx::fiber f;
110 my_exception( ctx::fiber && f_, char const* what) :
111 std::runtime_error( what),
112 f{ std::move( f_) } {
113 }
114 };
115
116 #ifdef BOOST_MSVC
117 // Optimizations can remove the integer-divide-by-zero here.
118 #pragma optimize("", off)
119 void seh( bool & catched) {
120 __try {
121 int i = 1;
122 i /= 0;
123 } __except( EXCEPTION_EXECUTE_HANDLER) {
124 catched = true;
125 }
126 }
127 #pragma optimize("", on)
128 #endif
129
130 void test_move() {
131 value1 = 0;
132 int i = 1;
133 BOOST_CHECK_EQUAL( 0, value1);
134 ctx::fiber f1{
135 [&i](ctx::fiber && f) {
136 value1 = i;
137 f = std::move( f).resume();
138 value1 = i;
139 return std::move( f);
140 }};
141 f1 = std::move( f1).resume();
142 BOOST_CHECK_EQUAL( 1, value1);
143 BOOST_CHECK( f1);
144 ctx::fiber f2;
145 BOOST_CHECK( ! f2);
146 f2 = std::move( f1);
147 BOOST_CHECK( ! f1);
148 BOOST_CHECK( f2);
149 i = 3;
150 f2 = std::move( f2).resume();
151 BOOST_CHECK_EQUAL( 3, value1);
152 BOOST_CHECK( ! f1);
153 BOOST_CHECK( ! f2);
154 }
155
156 void test_bind() {
157 value1 = 0;
158 X x;
159 ctx::fiber f{ std::bind( & X::foo, x, std::placeholders::_1, 7) };
160 f = std::move( f).resume();
161 BOOST_CHECK_EQUAL( 7, value1);
162 }
163
164 void test_exception() {
165 {
166 const char * what = "hello world";
167 ctx::fiber f{
168 [&what](ctx::fiber && f) {
169 try {
170 throw std::runtime_error( what);
171 } catch ( std::runtime_error const& e) {
172 value2 = e.what();
173 }
174 return std::move( f);
175 }};
176 f = std::move( f).resume();
177 BOOST_CHECK_EQUAL( std::string( what), value2);
178 BOOST_CHECK( ! f);
179 }
180 #ifdef BOOST_MSVC
181 {
182 bool catched = false;
183 std::thread([&catched](){
184 ctx::fiber f{ [&catched](ctx::fiber && f){
185 seh( catched);
186 return std::move( f);
187 }};
188 BOOST_CHECK( f);
189 f = std::move( f).resume();
190 }).join();
191 BOOST_CHECK( catched);
192 }
193 #endif
194 }
195
196 void test_fp() {
197 value3 = 0.;
198 double d = 7.13;
199 ctx::fiber f{
200 [&d]( ctx::fiber && f) {
201 d += 3.45;
202 value3 = d;
203 return std::move( f);
204 }};
205 f = std::move( f).resume();
206 BOOST_CHECK_EQUAL( 10.58, value3);
207 BOOST_CHECK( ! f);
208 }
209
210 void test_stacked() {
211 value1 = 0;
212 value3 = 0.;
213 ctx::fiber f{
214 [](ctx::fiber && f) {
215 ctx::fiber f1{
216 [](ctx::fiber && f) {
217 value1 = 3;
218 return std::move( f);
219 }};
220 f1 = std::move( f1).resume();
221 value3 = 3.14;
222 return std::move( f);
223 }};
224 f = std::move( f).resume();
225 BOOST_CHECK_EQUAL( 3, value1);
226 BOOST_CHECK_EQUAL( 3.14, value3);
227 BOOST_CHECK( ! f);
228 }
229
230 void test_prealloc() {
231 value1 = 0;
232 ctx::default_stack alloc;
233 ctx::stack_context sctx( alloc.allocate() );
234 void * sp = static_cast< char * >( sctx.sp) - 10;
235 std::size_t size = sctx.size - 10;
236 int i = 7;
237 ctx::fiber f{
238 std::allocator_arg, ctx::preallocated( sp, size, sctx), alloc,
239 [&i]( ctx::fiber && f) {
240 value1 = i;
241 return std::move( f);
242 }};
243 f = std::move( f).resume();
244 BOOST_CHECK_EQUAL( 7, value1);
245 BOOST_CHECK( ! f);
246 }
247
248 void test_ontop() {
249 {
250 int i = 3;
251 ctx::fiber f{ [&i](ctx::fiber && f) {
252 for (;;) {
253 i *= 10;
254 f = std::move( f).resume();
255 }
256 return std::move( f);
257 }};
258 f = std::move( f).resume();
259 f = std::move( f).resume_with(
260 [&i](ctx::fiber && f){
261 i -= 10;
262 return std::move( f);
263 });
264 BOOST_CHECK( f);
265 BOOST_CHECK_EQUAL( i, 200);
266 }
267 {
268 ctx::fiber f1;
269 ctx::fiber f{ [&f1](ctx::fiber && f) {
270 f = std::move( f).resume();
271 BOOST_CHECK( ! f);
272 return std::move( f1);
273 }};
274 f = std::move( f).resume();
275 f = std::move( f).resume_with(
276 [&f1](ctx::fiber && f){
277 f1 = std::move( f);
278 return std::move( f);
279 });
280 }
281 }
282
283 void test_ontop_exception() {
284 value1 = 0;
285 value2 = "";
286 ctx::fiber f{ [](ctx::fiber && f){
287 for (;;) {
288 value1 = 3;
289 try {
290 f = std::move( f).resume();
291 } catch ( my_exception & ex) {
292 value2 = ex.what();
293 return std::move( ex.f);
294 }
295 }
296 return std::move( f);
297 }};
298 f = std::move( f).resume();
299 BOOST_CHECK_EQUAL( 3, value1);
300 const char * what = "hello world";
301 f = std::move( f).resume_with(
302 [what](ctx::fiber && f){
303 throw my_exception( std::move( f), what);
304 return std::move( f);
305 });
306 BOOST_CHECK_EQUAL( 3, value1);
307 BOOST_CHECK_EQUAL( std::string( what), value2);
308 }
309
310 void test_termination() {
311 {
312 value1 = 0;
313 ctx::fiber f{
314 [](ctx::fiber && f){
315 Y y;
316 f = std::move( f).resume();
317 return std::move(f);
318 }};
319 f = std::move( f).resume();
320 BOOST_CHECK_EQUAL( 3, value1);
321 }
322 BOOST_CHECK_EQUAL( 7, value1);
323 {
324 value1 = 0;
325 BOOST_CHECK_EQUAL( 0, value1);
326 ctx::fiber f{
327 [](ctx::fiber && f) {
328 value1 = 3;
329 return std::move( f);
330 }};
331 f = std::move( f).resume();
332 BOOST_CHECK_EQUAL( 3, value1);
333 BOOST_CHECK( ! f);
334 }
335 {
336 value1 = 0;
337 BOOST_CHECK_EQUAL( 0, value1);
338 int i = 3;
339 ctx::fiber f{
340 [&i](ctx::fiber && f){
341 value1 = i;
342 f = std::move( f).resume();
343 value1 = i;
344 return std::move( f);
345 }};
346 f = std::move( f).resume();
347 BOOST_CHECK( f);
348 BOOST_CHECK_EQUAL( i, value1);
349 BOOST_CHECK( f);
350 i = 7;
351 f = std::move( f).resume();
352 BOOST_CHECK( ! f);
353 BOOST_CHECK_EQUAL( i, value1);
354 }
355 }
356
357 void test_sscanf() {
358 ctx::fiber{
359 []( ctx::fiber && f) {
360 {
361 double n1 = 0;
362 double n2 = 0;
363 sscanf("3.14 7.13", "%lf %lf", & n1, & n2);
364 BOOST_CHECK( n1 == 3.14);
365 BOOST_CHECK( n2 == 7.13);
366 }
367 {
368 int n1=0;
369 int n2=0;
370 sscanf("1 23", "%d %d", & n1, & n2);
371 BOOST_CHECK( n1 == 1);
372 BOOST_CHECK( n2 == 23);
373 }
374 {
375 int n1=0;
376 int n2=0;
377 sscanf("1 jjj 23", "%d %*[j] %d", & n1, & n2);
378 BOOST_CHECK( n1 == 1);
379 BOOST_CHECK( n2 == 23);
380 }
381 return std::move( f);
382 }}.resume();
383 }
384
385 void test_snprintf() {
386 ctx::fiber{
387 []( ctx::fiber && f) {
388 {
389 const char *fmt = "sqrt(2) = %f";
390 char buf[19];
391 snprintf( buf, sizeof( buf), fmt, std::sqrt( 2) );
392 BOOST_CHECK( 0 < sizeof( buf) );
393 BOOST_ASSERT( std::string("sqrt(2) = 1.41") == std::string( buf, 14) );
394 }
395 {
396 std::uint64_t n = 0xbcdef1234567890;
397 const char *fmt = "0x%016llX";
398 char buf[100];
399 snprintf( buf, sizeof( buf), fmt, n);
400 BOOST_ASSERT( std::string("0x0BCDEF1234567890") == std::string( buf, 18) );
401 }
402 return std::move( f);
403 }}.resume();
404 }
405
406 #ifdef BOOST_WINDOWS
407 void test_bug12215() {
408 ctx::fiber{
409 [](ctx::fiber && f) {
410 char buffer[MAX_PATH];
411 GetModuleFileName( nullptr, buffer, MAX_PATH);
412 return std::move( f);
413 }}.resume();
414 }
415 #endif
416
417 boost::unit_test::test_suite * init_unit_test_suite( int, char* [])
418 {
419 boost::unit_test::test_suite * test =
420 BOOST_TEST_SUITE("Boost.Context: fiber test suite");
421
422 test->add( BOOST_TEST_CASE( & test_move) );
423 test->add( BOOST_TEST_CASE( & test_bind) );
424 test->add( BOOST_TEST_CASE( & test_exception) );
425 test->add( BOOST_TEST_CASE( & test_fp) );
426 test->add( BOOST_TEST_CASE( & test_stacked) );
427 test->add( BOOST_TEST_CASE( & test_prealloc) );
428 test->add( BOOST_TEST_CASE( & test_ontop) );
429 test->add( BOOST_TEST_CASE( & test_ontop_exception) );
430 test->add( BOOST_TEST_CASE( & test_termination) );
431 test->add( BOOST_TEST_CASE( & test_sscanf) );
432 test->add( BOOST_TEST_CASE( & test_snprintf) );
433 #ifdef BOOST_WINDOWS
434 test->add( BOOST_TEST_CASE( & test_bug12215) );
435 #endif
436
437 return test;
438 }
439
440 #if defined(BOOST_MSVC)
441 # pragma warning(pop)
442 #endif