1 // (C) Copyright 2008-10 Anthony Williams 2 // 3 // Distributed under the Boost Software License, Version 1.0. (See 4 // accompanying file LICENSE_1_0.txt or copy at 5 // http://www.boost.org/LICENSE_1_0.txt) 6 7 #include <utility> 8 #include <memory> 9 #include <stdexcept> 10 #include <string> 11 12 #include <boost/test/unit_test.hpp> 13 14 #include <boost/fiber/all.hpp> 15 16 int gi = 7; 17 18 struct my_exception : public std::runtime_error { my_exceptionmy_exception19 my_exception() : 20 std::runtime_error("my_exception") { 21 } 22 }; 23 24 struct A { 25 A() = default; 26 27 A( A const&) = delete; 28 A( A &&) = default; 29 30 A & operator=( A const&) = delete; 31 A & operator=( A &&) = default; 32 33 int value; 34 }; 35 36 struct B { 37 bool bset{ false }; 38 39 B() = default; 40 BB41 B( bool set) : 42 bset{ set } { 43 gi = 3; 44 } 45 ~BB46 ~B() { 47 if ( bset) { 48 gi = -1; 49 } 50 } 51 BB52 B( B && other) : 53 bset{ other.bset } { 54 other.bset = false; 55 } 56 operator =B57 B & operator=( B && other) { 58 if ( this == & other) return * this; 59 bset = other.bset; 60 other.bset = false; 61 return * this; 62 } 63 64 B( B const&) = delete; 65 B & operator=( B const&) = delete; 66 }; 67 fn1(boost::fibers::promise<int> * p,int i)68void fn1( boost::fibers::promise< int > * p, int i) { 69 boost::this_fiber::yield(); 70 p->set_value( i); 71 } 72 fn2()73void fn2() { 74 boost::fibers::promise< int > p; 75 boost::fibers::future< int > f( p.get_future() ); 76 boost::this_fiber::yield(); 77 boost::fibers::fiber( boost::fibers::launch::dispatch, fn1, & p, 7).detach(); 78 boost::this_fiber::yield(); 79 BOOST_CHECK( 7 == f.get() ); 80 } 81 fn3()82int fn3() { 83 return 3; 84 } 85 fn4()86void fn4() { 87 } 88 fn5()89int fn5() { 90 boost::throw_exception( my_exception() ); 91 return 3; 92 } 93 fn6()94void fn6() { 95 boost::throw_exception( my_exception() ); 96 } 97 fn7()98int & fn7() { 99 return gi; 100 } 101 fn8(int i)102int fn8( int i) { 103 return i; 104 } 105 fn9()106A fn9() { 107 A a; 108 a.value = 3; 109 return a; 110 } 111 fn10()112A fn10() { 113 boost::throw_exception( my_exception() ); 114 return A(); 115 } 116 fn11(bool set)117B fn11( bool set) { 118 B b( set); 119 return b; 120 } 121 122 // packaged_task test_packaged_task_create()123void test_packaged_task_create() { 124 // default constructed packaged_task is not valid 125 boost::fibers::packaged_task< int() > t1; 126 BOOST_CHECK( ! t1.valid() ); 127 128 // packaged_task from function 129 boost::fibers::packaged_task< int() > t2( fn3); 130 BOOST_CHECK( t2.valid() ); 131 } 132 133 // packaged_task test_packaged_task_create_move()134void test_packaged_task_create_move() { 135 // default constructed packaged_task is not valid 136 boost::fibers::packaged_task< A() > t1; 137 BOOST_CHECK( ! t1.valid() ); 138 139 // packaged_task from function 140 boost::fibers::packaged_task< A() > t2( fn9); 141 BOOST_CHECK( t2.valid() ); 142 } 143 test_packaged_task_create_void()144void test_packaged_task_create_void() { 145 // default constructed packaged_task is not valid 146 boost::fibers::packaged_task< void() > t1; 147 BOOST_CHECK( ! t1.valid() ); 148 149 // packaged_task from function 150 boost::fibers::packaged_task< void() > t2( fn4); 151 BOOST_CHECK( t2.valid() ); 152 } 153 test_packaged_task_move()154void test_packaged_task_move() { 155 boost::fibers::packaged_task< int() > t1( fn3); 156 BOOST_CHECK( t1.valid() ); 157 158 // move construction 159 boost::fibers::packaged_task< int() > t2( std::move( t1) ); 160 BOOST_CHECK( ! t1.valid() ); 161 BOOST_CHECK( t2.valid() ); 162 163 // move assignment 164 t1 = std::move( t2); 165 BOOST_CHECK( t1.valid() ); 166 BOOST_CHECK( ! t2.valid() ); 167 } 168 test_packaged_task_move_move()169void test_packaged_task_move_move() { 170 boost::fibers::packaged_task< A() > t1( fn9); 171 BOOST_CHECK( t1.valid() ); 172 173 // move construction 174 boost::fibers::packaged_task< A() > t2( std::move( t1) ); 175 BOOST_CHECK( ! t1.valid() ); 176 BOOST_CHECK( t2.valid() ); 177 178 // move assignment 179 t1 = std::move( t2); 180 BOOST_CHECK( t1.valid() ); 181 BOOST_CHECK( ! t2.valid() ); 182 } 183 test_packaged_task_move_void()184void test_packaged_task_move_void() { 185 boost::fibers::packaged_task< void() > t1( fn4); 186 BOOST_CHECK( t1.valid() ); 187 188 // move construction 189 boost::fibers::packaged_task< void() > t2( std::move( t1) ); 190 BOOST_CHECK( ! t1.valid() ); 191 BOOST_CHECK( t2.valid() ); 192 193 // move assignment 194 t1 = std::move( t2); 195 BOOST_CHECK( t1.valid() ); 196 BOOST_CHECK( ! t2.valid() ); 197 } 198 test_packaged_task_swap()199void test_packaged_task_swap() { 200 boost::fibers::packaged_task< int() > t1( fn3); 201 BOOST_CHECK( t1.valid() ); 202 203 boost::fibers::packaged_task< int() > t2; 204 BOOST_CHECK( ! t2.valid() ); 205 206 // swap 207 t1.swap( t2); 208 BOOST_CHECK( ! t1.valid() ); 209 BOOST_CHECK( t2.valid() ); 210 } 211 test_packaged_task_swap_move()212void test_packaged_task_swap_move() { 213 boost::fibers::packaged_task< A() > t1( fn9); 214 BOOST_CHECK( t1.valid() ); 215 216 boost::fibers::packaged_task< A() > t2; 217 BOOST_CHECK( ! t2.valid() ); 218 219 // swap 220 t1.swap( t2); 221 BOOST_CHECK( ! t1.valid() ); 222 BOOST_CHECK( t2.valid() ); 223 } 224 test_packaged_task_swap_void()225void test_packaged_task_swap_void() { 226 boost::fibers::packaged_task< void() > t1( fn4); 227 BOOST_CHECK( t1.valid() ); 228 229 boost::fibers::packaged_task< void() > t2; 230 BOOST_CHECK( ! t2.valid() ); 231 232 // swap 233 t1.swap( t2); 234 BOOST_CHECK( ! t1.valid() ); 235 BOOST_CHECK( t2.valid() ); 236 } 237 test_packaged_task_reset()238void test_packaged_task_reset() { 239 { 240 boost::fibers::packaged_task< int() > p( fn3); 241 boost::fibers::future< int > f( p.get_future() ); 242 BOOST_CHECK( p.valid() ); 243 244 p(); 245 BOOST_CHECK( 3 == f.get() ); 246 247 // reset 248 p.reset(); 249 p(); 250 f = p.get_future(); 251 BOOST_CHECK( 3 == f.get() ); 252 } 253 { 254 boost::fibers::packaged_task< int() > p; 255 256 bool thrown = false; 257 try { 258 p.reset(); 259 } catch ( boost::fibers::packaged_task_uninitialized const&) { 260 thrown = true; 261 } 262 BOOST_CHECK( thrown); 263 } 264 } 265 test_packaged_task_reset_destruction()266void test_packaged_task_reset_destruction() { 267 gi = 0; 268 boost::fibers::packaged_task< B( bool) > p( fn11); 269 BOOST_CHECK( p.valid() ); 270 271 BOOST_CHECK( 0 == gi); 272 p( true); 273 BOOST_CHECK( 3 == gi); 274 275 // reset 276 p.reset(); 277 BOOST_CHECK( -1 == gi); 278 p( false); 279 BOOST_CHECK( 3 == gi); 280 281 // reset 282 p.reset(); 283 BOOST_CHECK( 3 == gi); 284 } 285 test_packaged_task_reset_move()286void test_packaged_task_reset_move() { 287 { 288 boost::fibers::packaged_task< A() > p( fn9); 289 boost::fibers::future< A > f( p.get_future() ); 290 BOOST_CHECK( p.valid() ); 291 292 p(); 293 BOOST_CHECK( 3 == f.get().value); 294 295 // reset 296 p.reset(); 297 p(); 298 f = p.get_future(); 299 BOOST_CHECK( 3 == f.get().value); 300 } 301 { 302 boost::fibers::packaged_task< A() > p; 303 304 bool thrown = false; 305 try { 306 p.reset(); 307 } catch ( boost::fibers::packaged_task_uninitialized const&) { 308 thrown = true; 309 } 310 BOOST_CHECK( thrown); 311 } 312 } 313 test_packaged_task_reset_void()314void test_packaged_task_reset_void() { 315 { 316 boost::fibers::packaged_task< void() > p( fn4); 317 boost::fibers::future< void > f( p.get_future() ); 318 BOOST_CHECK( p.valid() ); 319 320 p(); 321 f.get(); 322 323 // reset 324 p.reset(); 325 p(); 326 f = p.get_future(); 327 f.get(); 328 } 329 { 330 boost::fibers::packaged_task< void() > p; 331 332 bool thrown = false; 333 try { 334 p.reset(); 335 } catch ( boost::fibers::packaged_task_uninitialized const&) { 336 thrown = true; 337 } 338 BOOST_CHECK( thrown); 339 } 340 } 341 test_packaged_task_get_future()342void test_packaged_task_get_future() { 343 boost::fibers::packaged_task< int() > t1( fn3); 344 BOOST_CHECK( t1.valid() ); 345 346 // retrieve future 347 boost::fibers::future< int > f1 = t1.get_future(); 348 BOOST_CHECK( f1.valid() ); 349 350 // retrieve future a second time 351 bool thrown = false; 352 try { 353 f1 = t1.get_future(); 354 } catch ( boost::fibers::future_already_retrieved const&) { 355 thrown = true; 356 } 357 BOOST_CHECK( thrown); 358 359 // move construction 360 boost::fibers::packaged_task< int() > t2( std::move( t1) ); 361 BOOST_CHECK( ! t1.valid() ); 362 BOOST_CHECK( t2.valid() ); 363 364 // retrieve future from uninitialized 365 thrown = false; 366 try { 367 f1 = t1.get_future(); 368 } catch ( boost::fibers::packaged_task_uninitialized const&) { 369 thrown = true; 370 } 371 BOOST_CHECK( thrown); 372 } 373 test_packaged_task_get_future_move()374void test_packaged_task_get_future_move() { 375 boost::fibers::packaged_task< A() > t1( fn9); 376 BOOST_CHECK( t1.valid() ); 377 378 // retrieve future 379 boost::fibers::future< A > f1 = t1.get_future(); 380 BOOST_CHECK( f1.valid() ); 381 382 // retrieve future a second time 383 bool thrown = false; 384 try { 385 f1 = t1.get_future(); 386 } catch ( boost::fibers::future_already_retrieved const&) { 387 thrown = true; 388 } 389 BOOST_CHECK( thrown); 390 391 // move construction 392 boost::fibers::packaged_task< A() > t2( std::move( t1) ); 393 BOOST_CHECK( ! t1.valid() ); 394 BOOST_CHECK( t2.valid() ); 395 396 // retrieve future from uninitialized 397 thrown = false; 398 try { 399 f1 = t1.get_future(); 400 } catch ( boost::fibers::packaged_task_uninitialized const&) { 401 thrown = true; 402 } 403 BOOST_CHECK( thrown); 404 } 405 test_packaged_task_get_future_void()406void test_packaged_task_get_future_void() { 407 boost::fibers::packaged_task< void() > t1( fn4); 408 BOOST_CHECK( t1.valid() ); 409 410 // retrieve future 411 boost::fibers::future< void > f1 = t1.get_future(); 412 BOOST_CHECK( f1.valid() ); 413 414 // retrieve future a second time 415 bool thrown = false; 416 try { 417 f1 = t1.get_future(); 418 } catch ( boost::fibers::future_already_retrieved const&) { 419 thrown = true; 420 } 421 BOOST_CHECK( thrown); 422 423 // move construction 424 boost::fibers::packaged_task< void() > t2( std::move( t1) ); 425 BOOST_CHECK( ! t1.valid() ); 426 BOOST_CHECK( t2.valid() ); 427 428 // retrieve future from uninitialized 429 thrown = false; 430 try { 431 f1 = t1.get_future(); 432 } catch ( boost::fibers::packaged_task_uninitialized const&) { 433 thrown = true; 434 } 435 BOOST_CHECK( thrown); 436 } 437 test_packaged_task_exec()438void test_packaged_task_exec() { 439 // promise takes a copyable as return type 440 boost::fibers::packaged_task< int() > t1( fn3); 441 BOOST_CHECK( t1.valid() ); 442 boost::fibers::future< int > f1 = t1.get_future(); 443 BOOST_CHECK( f1.valid() ); 444 445 // exec 446 t1(); 447 BOOST_CHECK( 3 == f1.get() ); 448 449 // exec a second time 450 bool thrown = false; 451 try { 452 t1(); 453 } catch ( boost::fibers::promise_already_satisfied const&) { 454 thrown = true; 455 } 456 BOOST_CHECK( thrown); 457 } 458 test_packaged_task_exec_move()459void test_packaged_task_exec_move() { 460 // promise takes a copyable as return type 461 boost::fibers::packaged_task< A() > t1( fn9); 462 BOOST_CHECK( t1.valid() ); 463 boost::fibers::future< A > f1 = t1.get_future(); 464 BOOST_CHECK( f1.valid() ); 465 466 // exec 467 t1(); 468 BOOST_CHECK( 3 == f1.get().value); 469 470 // exec a second time 471 bool thrown = false; 472 try { 473 t1(); 474 } catch ( boost::fibers::promise_already_satisfied const&) { 475 thrown = true; 476 } 477 BOOST_CHECK( thrown); 478 } 479 test_packaged_task_exec_param()480void test_packaged_task_exec_param() { 481 // promise takes a copyable as return type 482 boost::fibers::packaged_task< int( int) > t1( fn8); 483 BOOST_CHECK( t1.valid() ); 484 boost::fibers::future< int > f1 = t1.get_future(); 485 BOOST_CHECK( f1.valid() ); 486 487 // exec 488 t1( 3); 489 BOOST_CHECK( 3 == f1.get() ); 490 491 // exec a second time 492 bool thrown = false; 493 try { 494 t1( 7); 495 } catch ( boost::fibers::promise_already_satisfied const&) { 496 thrown = true; 497 } 498 BOOST_CHECK( thrown); 499 500 //TODO: packaged_task returns a moveable-only as return type 501 } 502 test_packaged_task_exec_ref()503void test_packaged_task_exec_ref() { 504 // promise takes a copyable as return type 505 boost::fibers::packaged_task< int&() > t1( fn7); 506 BOOST_CHECK( t1.valid() ); 507 boost::fibers::future< int& > f1 = t1.get_future(); 508 BOOST_CHECK( f1.valid() ); 509 510 // exec 511 t1(); 512 int & i = f1.get(); 513 BOOST_CHECK( &gi == &i); 514 515 // exec a second time 516 bool thrown = false; 517 try { 518 t1(); 519 } catch ( boost::fibers::promise_already_satisfied const&) { 520 thrown = true; 521 } 522 BOOST_CHECK( thrown); 523 524 //TODO: packaged_task returns a moveable-only as return type 525 } 526 test_packaged_task_exec_void()527void test_packaged_task_exec_void() { 528 // promise takes a copyable as return type 529 boost::fibers::packaged_task< void() > t1( fn4); 530 BOOST_CHECK( t1.valid() ); 531 boost::fibers::future< void > f1 = t1.get_future(); 532 BOOST_CHECK( f1.valid() ); 533 534 // set void 535 t1(); 536 f1.get(); 537 538 // exec a second time 539 bool thrown = false; 540 try { 541 t1(); 542 } catch ( boost::fibers::promise_already_satisfied const&) { 543 thrown = true; 544 } 545 BOOST_CHECK( thrown); 546 } 547 test_packaged_task_exception()548void test_packaged_task_exception() { 549 // promise takes a copyable as return type 550 boost::fibers::packaged_task< int() > t1( fn5); 551 BOOST_CHECK( t1.valid() ); 552 boost::fibers::future< int > f1 = t1.get_future(); 553 BOOST_CHECK( f1.valid() ); 554 555 // exec 556 t1(); 557 bool thrown = false; 558 try { 559 f1.get(); 560 } catch ( my_exception const&) { 561 thrown = true; 562 } 563 BOOST_CHECK( thrown); 564 565 boost::fibers::packaged_task< int() > t2( fn5); 566 BOOST_CHECK( t2.valid() ); 567 boost::fibers::future< int > f2 = t2.get_future(); 568 BOOST_CHECK( f2.valid() ); 569 570 // exec 571 t2(); 572 BOOST_CHECK( f2.get_exception_ptr() ); 573 thrown = false; 574 try 575 { std::rethrow_exception( f2.get_exception_ptr() ); } 576 catch ( my_exception const&) 577 { thrown = true; } 578 BOOST_CHECK( thrown); 579 } 580 test_packaged_task_exception_move()581void test_packaged_task_exception_move() { 582 // promise takes a moveable as return type 583 boost::fibers::packaged_task< A() > t1( fn10); 584 BOOST_CHECK( t1.valid() ); 585 boost::fibers::future< A > f1 = t1.get_future(); 586 BOOST_CHECK( f1.valid() ); 587 588 // exec 589 t1(); 590 bool thrown = false; 591 try { 592 f1.get(); 593 } catch ( my_exception const&) { 594 thrown = true; 595 } 596 BOOST_CHECK( thrown); 597 598 boost::fibers::packaged_task< A() > t2( fn10); 599 BOOST_CHECK( t2.valid() ); 600 boost::fibers::future< A > f2 = t2.get_future(); 601 BOOST_CHECK( f2.valid() ); 602 603 // exec 604 t2(); 605 BOOST_CHECK( f2.get_exception_ptr() ); 606 thrown = false; 607 try 608 { std::rethrow_exception( f2.get_exception_ptr() ); } 609 catch ( my_exception const&) 610 { thrown = true; } 611 BOOST_CHECK( thrown); 612 } 613 test_packaged_task_exception_void()614void test_packaged_task_exception_void() { 615 // promise takes a copyable as return type 616 boost::fibers::packaged_task< void() > t1( fn6); 617 BOOST_CHECK( t1.valid() ); 618 boost::fibers::future< void > f1 = t1.get_future(); 619 BOOST_CHECK( f1.valid() ); 620 621 // set void 622 t1(); 623 bool thrown = false; 624 try { 625 f1.get(); 626 } catch ( my_exception const&) { 627 thrown = true; 628 } 629 BOOST_CHECK( thrown); 630 631 boost::fibers::packaged_task< void() > t2( fn6); 632 BOOST_CHECK( t2.valid() ); 633 boost::fibers::future< void > f2 = t2.get_future(); 634 BOOST_CHECK( f2.valid() ); 635 636 // exec 637 t2(); 638 BOOST_CHECK( f2.get_exception_ptr() ); 639 thrown = false; 640 try { 641 std::rethrow_exception( f2.get_exception_ptr() ); 642 } catch ( my_exception const&) { 643 thrown = true; 644 } 645 BOOST_CHECK( thrown); 646 } 647 648 init_unit_test_suite(int,char * [])649boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[]) { 650 boost::unit_test_framework::test_suite* test = 651 BOOST_TEST_SUITE("Boost.Fiber: packaged_task test suite"); 652 653 test->add(BOOST_TEST_CASE(test_packaged_task_create)); 654 test->add(BOOST_TEST_CASE(test_packaged_task_create_move)); 655 test->add(BOOST_TEST_CASE(test_packaged_task_create_void)); 656 test->add(BOOST_TEST_CASE(test_packaged_task_move)); 657 test->add(BOOST_TEST_CASE(test_packaged_task_move_move)); 658 test->add(BOOST_TEST_CASE(test_packaged_task_move_void)); 659 test->add(BOOST_TEST_CASE(test_packaged_task_swap)); 660 test->add(BOOST_TEST_CASE(test_packaged_task_swap_move)); 661 test->add(BOOST_TEST_CASE(test_packaged_task_swap_void)); 662 test->add(BOOST_TEST_CASE(test_packaged_task_reset)); 663 test->add(BOOST_TEST_CASE(test_packaged_task_reset_destruction)); 664 test->add(BOOST_TEST_CASE(test_packaged_task_reset_move)); 665 test->add(BOOST_TEST_CASE(test_packaged_task_reset_void)); 666 test->add(BOOST_TEST_CASE(test_packaged_task_get_future)); 667 test->add(BOOST_TEST_CASE(test_packaged_task_get_future_move)); 668 test->add(BOOST_TEST_CASE(test_packaged_task_get_future_void)); 669 test->add(BOOST_TEST_CASE(test_packaged_task_exec)); 670 test->add(BOOST_TEST_CASE(test_packaged_task_exec_move)); 671 test->add(BOOST_TEST_CASE(test_packaged_task_exec_param)); 672 test->add(BOOST_TEST_CASE(test_packaged_task_exec_ref)); 673 test->add(BOOST_TEST_CASE(test_packaged_task_exec_void)); 674 test->add(BOOST_TEST_CASE(test_packaged_task_exception)); 675 test->add(BOOST_TEST_CASE(test_packaged_task_exception_move)); 676 test->add(BOOST_TEST_CASE(test_packaged_task_exception_void)); 677 678 return test; 679 } 680