diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-27 18:24:20 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-27 18:24:20 +0000 |
commit | 483eb2f56657e8e7f419ab1a4fab8dce9ade8609 (patch) | |
tree | e5d88d25d870d5dedacb6bbdbe2a966086a0a5cf /src/boost/libs/fiber/test | |
parent | Initial commit. (diff) | |
download | ceph-483eb2f56657e8e7f419ab1a4fab8dce9ade8609.tar.xz ceph-483eb2f56657e8e7f419ab1a4fab8dce9ade8609.zip |
Adding upstream version 14.2.21.upstream/14.2.21upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/boost/libs/fiber/test')
33 files changed, 13234 insertions, 0 deletions
diff --git a/src/boost/libs/fiber/test/Jamfile.v2 b/src/boost/libs/fiber/test/Jamfile.v2 new file mode 100644 index 00000000..fac5c9e2 --- /dev/null +++ b/src/boost/libs/fiber/test/Jamfile.v2 @@ -0,0 +1,1294 @@ +# Boost.Fiber Library Tests Jamfile + +# Copyright Oliver Kowalke 2013. +# 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) + +import common ; +import feature ; +import indirect ; +import modules ; +import os ; +import path ; +import testing ; +import toolset ; +import ../../config/checks/config : requires ; + +project boost/fiber/test + : requirements + <library>../../test/build//boost_unit_test_framework + <library>/boost/context//boost_context + <library>/boost/fiber//boost_fiber + <library>/boost/thread//boost_thread + <target-os>solaris:<linkflags>"-llgrp" + <target-os>windows:<define>_WIN32_WINNT=0x0601 + <toolset>gcc,<segmented-stacks>on:<cxxflags>-fsplit-stack + <toolset>gcc,<segmented-stacks>on:<cxxflags>-DBOOST_USE_SEGMENTED_STACKS + <toolset>clang,<segmented-stacks>on:<cxxflags>-fsplit-stack + <toolset>clang,<segmented-stacks>on:<cxxflags>-DBOOST_USE_SEGMENTED_STACKS + <link>static + <threading>multi + <optimization>speed + <variant>release + ; + + +rule native-impl ( properties * ) +{ + local result ; + if ( <target-os>darwin in $(properties) || <target-os>android in $(properties) ) + { + result = <build>no ; + } + else if ( ! ( <target-os>windows in $(properties) ) ) + { + result = <context-impl>ucontext ; + } + else + { + result = <context-impl>winfib ; + } + return $(result) ; +} + + +# tests using assembler API +test-suite asm : +[ run test_fiber_post.cpp : + : : + <context-impl>fcontext + [ requires cxx11_auto_declarations + cxx11_constexpr + cxx11_defaulted_functions + cxx11_final + cxx11_hdr_mutex + cxx11_hdr_thread + cxx11_hdr_tuple + cxx11_lambdas + cxx11_noexcept + cxx11_nullptr + cxx11_rvalue_references + cxx11_template_aliases + cxx11_thread_local + cxx11_variadic_templates ] + : test_fiber_post_asm ] + +[ run test_fiber_dispatch.cpp : + : : + <context-impl>fcontext + [ requires cxx11_auto_declarations + cxx11_constexpr + cxx11_defaulted_functions + cxx11_final + cxx11_hdr_mutex + cxx11_hdr_thread + cxx11_hdr_tuple + cxx11_lambdas + cxx11_noexcept + cxx11_nullptr + cxx11_rvalue_references + cxx11_template_aliases + cxx11_thread_local + cxx11_variadic_templates ] + : test_fiber_dispatch_asm ] + +[ run test_mutex_post.cpp : + : : + <context-impl>fcontext + [ requires cxx11_auto_declarations + cxx11_constexpr + cxx11_defaulted_functions + cxx11_final + cxx11_hdr_mutex + cxx11_hdr_thread + cxx11_hdr_tuple + cxx11_lambdas + cxx11_noexcept + cxx11_nullptr + cxx11_rvalue_references + cxx11_template_aliases + cxx11_thread_local + cxx11_variadic_templates ] + : test_mutex_post_asm ] + +[ run test_mutex_dispatch.cpp : + : : + <context-impl>fcontext + [ requires cxx11_auto_declarations + cxx11_constexpr + cxx11_defaulted_functions + cxx11_final + cxx11_hdr_mutex + cxx11_hdr_thread + cxx11_hdr_tuple + cxx11_lambdas + cxx11_noexcept + cxx11_nullptr + cxx11_rvalue_references + cxx11_template_aliases + cxx11_thread_local + cxx11_variadic_templates ] + : test_mutex_dispatch_asm ] + +[ run test_condition_variable_any_post.cpp : + : : + <context-impl>fcontext + [ requires cxx11_auto_declarations + cxx11_constexpr + cxx11_defaulted_functions + cxx11_final + cxx11_hdr_mutex + cxx11_hdr_thread + cxx11_hdr_tuple + cxx11_lambdas + cxx11_noexcept + cxx11_nullptr + cxx11_rvalue_references + cxx11_template_aliases + cxx11_thread_local + cxx11_variadic_templates ] + : test_condition_variable_any_post_asm ] + +[ run test_condition_variable_any_dispatch.cpp : + : : + <context-impl>fcontext + [ requires cxx11_auto_declarations + cxx11_constexpr + cxx11_defaulted_functions + cxx11_final + cxx11_hdr_mutex + cxx11_hdr_thread + cxx11_hdr_tuple + cxx11_lambdas + cxx11_noexcept + cxx11_nullptr + cxx11_rvalue_references + cxx11_template_aliases + cxx11_thread_local + cxx11_variadic_templates ] + : test_condition_variable_any_dispatch_asm ] + +[ run test_condition_variable_post.cpp : + : : + <context-impl>fcontext + [ requires cxx11_auto_declarations + cxx11_constexpr + cxx11_defaulted_functions + cxx11_final + cxx11_hdr_mutex + cxx11_hdr_thread + cxx11_hdr_tuple + cxx11_lambdas + cxx11_noexcept + cxx11_nullptr + cxx11_rvalue_references + cxx11_template_aliases + cxx11_thread_local + cxx11_variadic_templates ] + : test_condition_variable_post_asm ] + +[ run test_condition_variable_dispatch.cpp : + : : + <context-impl>fcontext + [ requires cxx11_auto_declarations + cxx11_constexpr + cxx11_defaulted_functions + cxx11_final + cxx11_hdr_mutex + cxx11_hdr_thread + cxx11_hdr_tuple + cxx11_lambdas + cxx11_noexcept + cxx11_nullptr + cxx11_rvalue_references + cxx11_template_aliases + cxx11_thread_local + cxx11_variadic_templates ] + : test_condition_variable_dispatch_asm ] + +[ run test_barrier_post.cpp : + : : + <context-impl>fcontext + [ requires cxx11_auto_declarations + cxx11_constexpr + cxx11_defaulted_functions + cxx11_final + cxx11_hdr_mutex + cxx11_hdr_thread + cxx11_hdr_tuple + cxx11_lambdas + cxx11_noexcept + cxx11_nullptr + cxx11_rvalue_references + cxx11_template_aliases + cxx11_thread_local + cxx11_variadic_templates ] + : test_barrier_post_asm ] + +[ run test_barrier_dispatch.cpp : + : : + <context-impl>fcontext + [ requires cxx11_auto_declarations + cxx11_constexpr + cxx11_defaulted_functions + cxx11_final + cxx11_hdr_mutex + cxx11_hdr_thread + cxx11_hdr_tuple + cxx11_lambdas + cxx11_noexcept + cxx11_nullptr + cxx11_rvalue_references + cxx11_template_aliases + cxx11_thread_local + cxx11_variadic_templates ] + : test_barrier_dispatch_asm ] + +[ run test_buffered_channel_post.cpp : + : : + <context-impl>fcontext + [ requires cxx11_auto_declarations + cxx11_constexpr + cxx11_defaulted_functions + cxx11_final + cxx11_hdr_mutex + cxx11_hdr_thread + cxx11_hdr_tuple + cxx11_lambdas + cxx11_noexcept + cxx11_nullptr + cxx11_rvalue_references + cxx11_template_aliases + cxx11_thread_local + cxx11_variadic_templates ] + : test_buffered_channel_post_asm ] + +[ run test_buffered_channel_dispatch.cpp : + : : + <context-impl>fcontext + [ requires cxx11_auto_declarations + cxx11_constexpr + cxx11_defaulted_functions + cxx11_final + cxx11_hdr_mutex + cxx11_hdr_thread + cxx11_hdr_tuple + cxx11_lambdas + cxx11_noexcept + cxx11_nullptr + cxx11_rvalue_references + cxx11_template_aliases + cxx11_thread_local + cxx11_variadic_templates ] + : test_buffered_channel_dispatch_asm ] + +[ run test_unbuffered_channel_post.cpp : + : : + <context-impl>fcontext + [ requires cxx11_auto_declarations + cxx11_constexpr + cxx11_defaulted_functions + cxx11_final + cxx11_hdr_mutex + cxx11_hdr_thread + cxx11_hdr_tuple + cxx11_lambdas + cxx11_noexcept + cxx11_nullptr + cxx11_rvalue_references + cxx11_template_aliases + cxx11_thread_local + cxx11_variadic_templates ] + : test_unbuffered_channel_post_asm ] + +[ run test_unbuffered_channel_dispatch.cpp : + : : + <context-impl>fcontext + [ requires cxx11_auto_declarations + cxx11_constexpr + cxx11_defaulted_functions + cxx11_final + cxx11_hdr_mutex + cxx11_hdr_thread + cxx11_hdr_tuple + cxx11_lambdas + cxx11_noexcept + cxx11_nullptr + cxx11_rvalue_references + cxx11_template_aliases + cxx11_thread_local + cxx11_variadic_templates ] + : test_unbuffered_channel_dispatch_asm ] + +[ run test_fss_post.cpp : + : : + <context-impl>fcontext + [ requires cxx11_auto_declarations + cxx11_constexpr + cxx11_defaulted_functions + cxx11_final + cxx11_hdr_mutex + cxx11_hdr_thread + cxx11_hdr_tuple + cxx11_lambdas + cxx11_noexcept + cxx11_nullptr + cxx11_rvalue_references + cxx11_template_aliases + cxx11_thread_local + cxx11_variadic_templates ] + : test_fss_post_asm ] + +[ run test_fss_dispatch.cpp : + : : + <context-impl>fcontext + [ requires cxx11_auto_declarations + cxx11_constexpr + cxx11_defaulted_functions + cxx11_final + cxx11_hdr_mutex + cxx11_hdr_thread + cxx11_hdr_tuple + cxx11_lambdas + cxx11_noexcept + cxx11_nullptr + cxx11_rvalue_references + cxx11_template_aliases + cxx11_thread_local + cxx11_variadic_templates ] + : test_fss_dispatch_asm ] + +[ run test_promise_post.cpp : + : : + <context-impl>fcontext + [ requires cxx11_auto_declarations + cxx11_constexpr + cxx11_defaulted_functions + cxx11_final + cxx11_hdr_mutex + cxx11_hdr_thread + cxx11_hdr_tuple + cxx11_lambdas + cxx11_noexcept + cxx11_nullptr + cxx11_rvalue_references + cxx11_template_aliases + cxx11_thread_local + cxx11_variadic_templates ] + : test_promise_post_asm ] + +[ run test_promise_dispatch.cpp : + : : + <context-impl>fcontext + [ requires cxx11_auto_declarations + cxx11_constexpr + cxx11_defaulted_functions + cxx11_final + cxx11_hdr_mutex + cxx11_hdr_thread + cxx11_hdr_tuple + cxx11_lambdas + cxx11_noexcept + cxx11_nullptr + cxx11_rvalue_references + cxx11_template_aliases + cxx11_thread_local + cxx11_variadic_templates ] + : test_promise_dispatch_asm ] + +[ run test_future_post.cpp : + : : + <context-impl>fcontext + [ requires cxx11_auto_declarations + cxx11_constexpr + cxx11_defaulted_functions + cxx11_final + cxx11_hdr_mutex + cxx11_hdr_thread + cxx11_hdr_tuple + cxx11_lambdas + cxx11_noexcept + cxx11_nullptr + cxx11_rvalue_references + cxx11_template_aliases + cxx11_thread_local + cxx11_variadic_templates ] + : test_future_post_asm ] + +[ run test_future_dispatch.cpp : + : : + <context-impl>fcontext + [ requires cxx11_auto_declarations + cxx11_constexpr + cxx11_defaulted_functions + cxx11_final + cxx11_hdr_mutex + cxx11_hdr_thread + cxx11_hdr_tuple + cxx11_lambdas + cxx11_noexcept + cxx11_nullptr + cxx11_rvalue_references + cxx11_template_aliases + cxx11_thread_local + cxx11_variadic_templates ] + : test_future_dispatch_asm ] + +[ run test_shared_future_post.cpp : + : : + <context-impl>fcontext + [ requires cxx11_auto_declarations + cxx11_constexpr + cxx11_defaulted_functions + cxx11_final + cxx11_hdr_mutex + cxx11_hdr_thread + cxx11_hdr_tuple + cxx11_lambdas + cxx11_noexcept + cxx11_nullptr + cxx11_rvalue_references + cxx11_template_aliases + cxx11_thread_local + cxx11_variadic_templates ] + : test_shared_future_post_asm ] + +[ run test_shared_future_dispatch.cpp : + : : + <context-impl>fcontext + [ requires cxx11_auto_declarations + cxx11_constexpr + cxx11_defaulted_functions + cxx11_final + cxx11_hdr_mutex + cxx11_hdr_thread + cxx11_hdr_tuple + cxx11_lambdas + cxx11_noexcept + cxx11_nullptr + cxx11_rvalue_references + cxx11_template_aliases + cxx11_thread_local + cxx11_variadic_templates ] + : test_shared_future_dispatch_asm ] + +[ run test_packaged_task_post.cpp : + : : + <context-impl>fcontext + [ requires cxx11_auto_declarations + cxx11_constexpr + cxx11_defaulted_functions + cxx11_final + cxx11_hdr_mutex + cxx11_hdr_thread + cxx11_hdr_tuple + cxx11_lambdas + cxx11_noexcept + cxx11_nullptr + cxx11_rvalue_references + cxx11_template_aliases + cxx11_thread_local + cxx11_variadic_templates ] + : test_packaged_task_post_asm ] + +[ run test_packaged_task_dispatch.cpp : + : : + <context-impl>fcontext + [ requires cxx11_auto_declarations + cxx11_constexpr + cxx11_defaulted_functions + cxx11_final + cxx11_hdr_mutex + cxx11_hdr_thread + cxx11_hdr_tuple + cxx11_lambdas + cxx11_noexcept + cxx11_nullptr + cxx11_rvalue_references + cxx11_template_aliases + cxx11_thread_local + cxx11_variadic_templates ] + : test_packaged_task_dispatch_asm ] + +[ run test_async_post.cpp : + : : + <context-impl>fcontext + [ requires cxx11_auto_declarations + cxx11_constexpr + cxx11_defaulted_functions + cxx11_final + cxx11_hdr_mutex + cxx11_hdr_thread + cxx11_hdr_tuple + cxx11_lambdas + cxx11_noexcept + cxx11_nullptr + cxx11_rvalue_references + cxx11_template_aliases + cxx11_thread_local + cxx11_variadic_templates ] + : test_async_post_asm ] + +[ run test_async_dispatch.cpp : + : : + <context-impl>fcontext + [ requires cxx11_auto_declarations + cxx11_constexpr + cxx11_defaulted_functions + cxx11_final + cxx11_hdr_mutex + cxx11_hdr_thread + cxx11_hdr_tuple + cxx11_lambdas + cxx11_noexcept + cxx11_nullptr + cxx11_rvalue_references + cxx11_template_aliases + cxx11_thread_local + cxx11_variadic_templates ] + : test_async_dispatch_asm ] ; + + +# tests using native API +test-suite native : +[ run test_fiber_post.cpp : + : : + <conditional>@native-impl + [ requires cxx11_auto_declarations + cxx11_constexpr + cxx11_defaulted_functions + cxx11_final + cxx11_hdr_mutex + cxx11_hdr_thread + cxx11_hdr_tuple + cxx11_lambdas + cxx11_noexcept + cxx11_nullptr + cxx11_rvalue_references + cxx11_template_aliases + cxx11_thread_local + cxx11_variadic_templates ] + : test_fiber_post_native ] + +[ run test_fiber_dispatch.cpp : + : : + <conditional>@native-impl + [ requires cxx11_auto_declarations + cxx11_constexpr + cxx11_defaulted_functions + cxx11_final + cxx11_hdr_mutex + cxx11_hdr_thread + cxx11_hdr_tuple + cxx11_lambdas + cxx11_noexcept + cxx11_nullptr + cxx11_rvalue_references + cxx11_template_aliases + cxx11_thread_local + cxx11_variadic_templates ] + : test_fiber_dispatch_native ] + +[ run test_mutex_post.cpp : + : : + <conditional>@native-impl + [ requires cxx11_auto_declarations + cxx11_constexpr + cxx11_defaulted_functions + cxx11_final + cxx11_hdr_mutex + cxx11_hdr_thread + cxx11_hdr_tuple + cxx11_lambdas + cxx11_noexcept + cxx11_nullptr + cxx11_rvalue_references + cxx11_template_aliases + cxx11_thread_local + cxx11_variadic_templates ] + : test_mutex_post_native ] + +[ run test_mutex_dispatch.cpp : + : : + <conditional>@native-impl + [ requires cxx11_auto_declarations + cxx11_constexpr + cxx11_defaulted_functions + cxx11_final + cxx11_hdr_mutex + cxx11_hdr_thread + cxx11_hdr_tuple + cxx11_lambdas + cxx11_noexcept + cxx11_nullptr + cxx11_rvalue_references + cxx11_template_aliases + cxx11_thread_local + cxx11_variadic_templates ] + : test_mutex_dispatch_native ] + +[ run test_condition_variable_any_post.cpp : + : : + <conditional>@native-impl + [ requires cxx11_auto_declarations + cxx11_constexpr + cxx11_defaulted_functions + cxx11_final + cxx11_hdr_mutex + cxx11_hdr_thread + cxx11_hdr_tuple + cxx11_lambdas + cxx11_noexcept + cxx11_nullptr + cxx11_rvalue_references + cxx11_template_aliases + cxx11_thread_local + cxx11_variadic_templates ] + : test_cond_var_any_post_native ] + +[ run test_condition_variable_any_dispatch.cpp : + : : + <conditional>@native-impl + [ requires cxx11_auto_declarations + cxx11_constexpr + cxx11_defaulted_functions + cxx11_final + cxx11_hdr_mutex + cxx11_hdr_thread + cxx11_hdr_tuple + cxx11_lambdas + cxx11_noexcept + cxx11_nullptr + cxx11_rvalue_references + cxx11_template_aliases + cxx11_thread_local + cxx11_variadic_templates ] + : test_cond_vare_any_dispatch_native ] + +[ run test_condition_variable_post.cpp : + : : + <conditional>@native-impl + [ requires cxx11_auto_declarations + cxx11_constexpr + cxx11_defaulted_functions + cxx11_final + cxx11_hdr_mutex + cxx11_hdr_thread + cxx11_hdr_tuple + cxx11_lambdas + cxx11_noexcept + cxx11_nullptr + cxx11_rvalue_references + cxx11_template_aliases + cxx11_thread_local + cxx11_variadic_templates ] + : test_cond_var_post_native ] + +[ run test_condition_variable_dispatch.cpp : + : : + <conditional>@native-impl + [ requires cxx11_auto_declarations + cxx11_constexpr + cxx11_defaulted_functions + cxx11_final + cxx11_hdr_mutex + cxx11_hdr_thread + cxx11_hdr_tuple + cxx11_lambdas + cxx11_noexcept + cxx11_nullptr + cxx11_rvalue_references + cxx11_template_aliases + cxx11_thread_local + cxx11_variadic_templates ] + : test_cond_var_dispatch_native ] + +[ run test_barrier_post.cpp : + : : + <conditional>@native-impl + [ requires cxx11_auto_declarations + cxx11_constexpr + cxx11_defaulted_functions + cxx11_final + cxx11_hdr_mutex + cxx11_hdr_thread + cxx11_hdr_tuple + cxx11_lambdas + cxx11_noexcept + cxx11_nullptr + cxx11_rvalue_references + cxx11_template_aliases + cxx11_thread_local + cxx11_variadic_templates ] + : test_barrier_post_native ] + +[ run test_barrier_dispatch.cpp : + : : + <conditional>@native-impl + [ requires cxx11_auto_declarations + cxx11_constexpr + cxx11_defaulted_functions + cxx11_final + cxx11_hdr_mutex + cxx11_hdr_thread + cxx11_hdr_tuple + cxx11_lambdas + cxx11_noexcept + cxx11_nullptr + cxx11_rvalue_references + cxx11_template_aliases + cxx11_thread_local + cxx11_variadic_templates ] + : test_barrier_dispatch_native ] + +[ run test_buffered_channel_post.cpp : + : : + <conditional>@native-impl + [ requires cxx11_auto_declarations + cxx11_constexpr + cxx11_defaulted_functions + cxx11_final + cxx11_hdr_mutex + cxx11_hdr_thread + cxx11_hdr_tuple + cxx11_lambdas + cxx11_noexcept + cxx11_nullptr + cxx11_rvalue_references + cxx11_template_aliases + cxx11_thread_local + cxx11_variadic_templates ] + : test_buf_channel_post_native ] + +[ run test_buffered_channel_dispatch.cpp : + : : + <conditional>@native-impl + [ requires cxx11_auto_declarations + cxx11_constexpr + cxx11_defaulted_functions + cxx11_final + cxx11_hdr_mutex + cxx11_hdr_thread + cxx11_hdr_tuple + cxx11_lambdas + cxx11_noexcept + cxx11_nullptr + cxx11_rvalue_references + cxx11_template_aliases + cxx11_thread_local + cxx11_variadic_templates ] + : test_buf_channel_dispatch_native ] + +[ run test_unbuffered_channel_post.cpp : + : : + <conditional>@native-impl + [ requires cxx11_auto_declarations + cxx11_constexpr + cxx11_defaulted_functions + cxx11_final + cxx11_hdr_mutex + cxx11_hdr_thread + cxx11_hdr_tuple + cxx11_lambdas + cxx11_noexcept + cxx11_nullptr + cxx11_rvalue_references + cxx11_template_aliases + cxx11_thread_local + cxx11_variadic_templates ] + : test_unbuf_channel_post_native ] + +[ run test_unbuffered_channel_dispatch.cpp : + : : + <conditional>@native-impl + [ requires cxx11_auto_declarations + cxx11_constexpr + cxx11_defaulted_functions + cxx11_final + cxx11_hdr_mutex + cxx11_hdr_thread + cxx11_hdr_tuple + cxx11_lambdas + cxx11_noexcept + cxx11_nullptr + cxx11_rvalue_references + cxx11_template_aliases + cxx11_thread_local + cxx11_variadic_templates ] + : test_unbuf_channel_dispatch_native ] + +[ run test_fss_post.cpp : + : : + <conditional>@native-impl + [ requires cxx11_auto_declarations + cxx11_constexpr + cxx11_defaulted_functions + cxx11_final + cxx11_hdr_mutex + cxx11_hdr_thread + cxx11_hdr_tuple + cxx11_lambdas + cxx11_noexcept + cxx11_nullptr + cxx11_rvalue_references + cxx11_template_aliases + cxx11_thread_local + cxx11_variadic_templates ] + : test_fss_post_native ] + +[ run test_fss_dispatch.cpp : + : : + <conditional>@native-impl + [ requires cxx11_auto_declarations + cxx11_constexpr + cxx11_defaulted_functions + cxx11_final + cxx11_hdr_mutex + cxx11_hdr_thread + cxx11_hdr_tuple + cxx11_lambdas + cxx11_noexcept + cxx11_nullptr + cxx11_rvalue_references + cxx11_template_aliases + cxx11_thread_local + cxx11_variadic_templates ] + : test_fss_dispatch_native ] + +[ run test_promise_post.cpp : + : : + <conditional>@native-impl + [ requires cxx11_auto_declarations + cxx11_constexpr + cxx11_defaulted_functions + cxx11_final + cxx11_hdr_mutex + cxx11_hdr_thread + cxx11_hdr_tuple + cxx11_lambdas + cxx11_noexcept + cxx11_nullptr + cxx11_rvalue_references + cxx11_template_aliases + cxx11_thread_local + cxx11_variadic_templates ] + : test_promise_post_native ] + +[ run test_promise_dispatch.cpp : + : : + <conditional>@native-impl + [ requires cxx11_auto_declarations + cxx11_constexpr + cxx11_defaulted_functions + cxx11_final + cxx11_hdr_mutex + cxx11_hdr_thread + cxx11_hdr_tuple + cxx11_lambdas + cxx11_noexcept + cxx11_nullptr + cxx11_rvalue_references + cxx11_template_aliases + cxx11_thread_local + cxx11_variadic_templates ] + : test_promise_dispatch_native ] + +[ run test_future_post.cpp : + : : + <conditional>@native-impl + [ requires cxx11_auto_declarations + cxx11_constexpr + cxx11_defaulted_functions + cxx11_final + cxx11_hdr_mutex + cxx11_hdr_thread + cxx11_hdr_tuple + cxx11_lambdas + cxx11_noexcept + cxx11_nullptr + cxx11_rvalue_references + cxx11_template_aliases + cxx11_thread_local + cxx11_variadic_templates ] + : test_future_post_native ] + +[ run test_future_dispatch.cpp : + : : + <conditional>@native-impl + [ requires cxx11_auto_declarations + cxx11_constexpr + cxx11_defaulted_functions + cxx11_final + cxx11_hdr_mutex + cxx11_hdr_thread + cxx11_hdr_tuple + cxx11_lambdas + cxx11_noexcept + cxx11_nullptr + cxx11_rvalue_references + cxx11_template_aliases + cxx11_thread_local + cxx11_variadic_templates ] + : test_future_dispatch_native ] + +[ run test_shared_future_post.cpp : + : : + <conditional>@native-impl + [ requires cxx11_auto_declarations + cxx11_constexpr + cxx11_defaulted_functions + cxx11_final + cxx11_hdr_mutex + cxx11_hdr_thread + cxx11_hdr_tuple + cxx11_lambdas + cxx11_noexcept + cxx11_nullptr + cxx11_rvalue_references + cxx11_template_aliases + cxx11_thread_local + cxx11_variadic_templates ] + : test_shared_future_post_native ] + +[ run test_shared_future_dispatch.cpp : + : : + <conditional>@native-impl + [ requires cxx11_auto_declarations + cxx11_constexpr + cxx11_defaulted_functions + cxx11_final + cxx11_hdr_mutex + cxx11_hdr_thread + cxx11_hdr_tuple + cxx11_lambdas + cxx11_noexcept + cxx11_nullptr + cxx11_rvalue_references + cxx11_template_aliases + cxx11_thread_local + cxx11_variadic_templates ] + : test_shared_future_dispatch_native ] + +[ run test_packaged_task_post.cpp : + : : + <conditional>@native-impl + [ requires cxx11_auto_declarations + cxx11_constexpr + cxx11_defaulted_functions + cxx11_final + cxx11_hdr_mutex + cxx11_hdr_thread + cxx11_hdr_tuple + cxx11_lambdas + cxx11_noexcept + cxx11_nullptr + cxx11_rvalue_references + cxx11_template_aliases + cxx11_thread_local + cxx11_variadic_templates ] + : test_packaged_task_post_native ] + +[ run test_packaged_task_dispatch.cpp : + : : + <conditional>@native-impl + [ requires cxx11_auto_declarations + cxx11_constexpr + cxx11_defaulted_functions + cxx11_final + cxx11_hdr_mutex + cxx11_hdr_thread + cxx11_hdr_tuple + cxx11_lambdas + cxx11_noexcept + cxx11_nullptr + cxx11_rvalue_references + cxx11_template_aliases + cxx11_thread_local + cxx11_variadic_templates ] + : test_packaged_task_dispatch_native ] + +[ run test_async_post.cpp : + : : + <conditional>@native-impl + [ requires cxx11_auto_declarations + cxx11_constexpr + cxx11_defaulted_functions + cxx11_final + cxx11_hdr_mutex + cxx11_hdr_thread + cxx11_hdr_tuple + cxx11_lambdas + cxx11_noexcept + cxx11_nullptr + cxx11_rvalue_references + cxx11_template_aliases + cxx11_thread_local + cxx11_variadic_templates ] + : test_async_post_native ] + +[ run test_async_dispatch.cpp : + : : + <conditional>@native-impl + [ requires cxx11_auto_declarations + cxx11_constexpr + cxx11_defaulted_functions + cxx11_final + cxx11_hdr_mutex + cxx11_hdr_thread + cxx11_hdr_tuple + cxx11_lambdas + cxx11_noexcept + cxx11_nullptr + cxx11_rvalue_references + cxx11_template_aliases + cxx11_thread_local + cxx11_variadic_templates ] + : test_async_dispatch_native ] ; + + +#etra tests using asm API +test-suite extra-asm : +[ run test_mutex_mt_post.cpp : + : : + <context-impl>fcontext + [ requires cxx11_auto_declarations + cxx11_constexpr + cxx11_defaulted_functions + cxx11_final + cxx11_hdr_mutex + cxx11_hdr_thread + cxx11_hdr_tuple + cxx11_lambdas + cxx11_noexcept + cxx11_nullptr + cxx11_rvalue_references + cxx11_template_aliases + cxx11_thread_local + cxx11_variadic_templates ] + : test_mutex_mt_post_asm ] + +[ run test_mutex_mt_dispatch.cpp : + : : + <context-impl>fcontext + [ requires cxx11_auto_declarations + cxx11_constexpr + cxx11_defaulted_functions + cxx11_final + cxx11_hdr_mutex + cxx11_hdr_thread + cxx11_hdr_tuple + cxx11_lambdas + cxx11_noexcept + cxx11_nullptr + cxx11_rvalue_references + cxx11_template_aliases + cxx11_thread_local + cxx11_variadic_templates ] + : test_mutex_mt_dispatch_asm ] + +[ run test_condition_mt_post.cpp : + : : + <context-impl>fcontext + [ requires cxx11_auto_declarations + cxx11_constexpr + cxx11_defaulted_functions + cxx11_final + cxx11_hdr_mutex + cxx11_hdr_thread + cxx11_hdr_tuple + cxx11_lambdas + cxx11_noexcept + cxx11_nullptr + cxx11_rvalue_references + cxx11_template_aliases + cxx11_thread_local + cxx11_variadic_templates ] + : test_condition_mt_post_asm ] + +[ run test_condition_mt_dispatch.cpp : + : : + <context-impl>fcontext + [ requires cxx11_auto_declarations + cxx11_constexpr + cxx11_defaulted_functions + cxx11_final + cxx11_hdr_mutex + cxx11_hdr_thread + cxx11_hdr_tuple + cxx11_lambdas + cxx11_noexcept + cxx11_nullptr + cxx11_rvalue_references + cxx11_template_aliases + cxx11_thread_local + cxx11_variadic_templates ] + : test_condition_mt_dispatch_asm ] + +[ run test_future_mt_post.cpp : + : : + <context-impl>fcontext + [ requires cxx11_auto_declarations + cxx11_constexpr + cxx11_defaulted_functions + cxx11_final + cxx11_hdr_mutex + cxx11_hdr_thread + cxx11_hdr_tuple + cxx11_lambdas + cxx11_noexcept + cxx11_nullptr + cxx11_rvalue_references + cxx11_template_aliases + cxx11_thread_local + cxx11_variadic_templates ] + : test_future_mt_post_asm ] + +[ run test_future_mt_dispatch.cpp : + : : + <context-impl>fcontext + [ requires cxx11_auto_declarations + cxx11_constexpr + cxx11_defaulted_functions + cxx11_final + cxx11_hdr_mutex + cxx11_hdr_thread + cxx11_hdr_tuple + cxx11_lambdas + cxx11_noexcept + cxx11_nullptr + cxx11_rvalue_references + cxx11_template_aliases + cxx11_thread_local + cxx11_variadic_templates ] + : test_future_mt_dispatch_asm ] ; + + +#etra tests using native API +test-suite extra-native : +[ run test_mutex_mt_post.cpp : + : : + <conditional>@native-impl + [ requires cxx11_auto_declarations + cxx11_constexpr + cxx11_defaulted_functions + cxx11_final + cxx11_hdr_mutex + cxx11_hdr_thread + cxx11_hdr_tuple + cxx11_lambdas + cxx11_noexcept + cxx11_nullptr + cxx11_rvalue_references + cxx11_template_aliases + cxx11_thread_local + cxx11_variadic_templates ] + : test_mutex_mt_post_native ] + +[ run test_mutex_mt_dispatch.cpp : + : : + <conditional>@native-impl + [ requires cxx11_auto_declarations + cxx11_constexpr + cxx11_defaulted_functions + cxx11_final + cxx11_hdr_mutex + cxx11_hdr_thread + cxx11_hdr_tuple + cxx11_lambdas + cxx11_noexcept + cxx11_nullptr + cxx11_rvalue_references + cxx11_template_aliases + cxx11_thread_local + cxx11_variadic_templates ] + : test_mutex_mt_dispatch_native ] + +[ run test_condition_mt_post.cpp : + : : + <conditional>@native-impl + [ requires cxx11_auto_declarations + cxx11_constexpr + cxx11_defaulted_functions + cxx11_final + cxx11_hdr_mutex + cxx11_hdr_thread + cxx11_hdr_tuple + cxx11_lambdas + cxx11_noexcept + cxx11_nullptr + cxx11_rvalue_references + cxx11_template_aliases + cxx11_thread_local + cxx11_variadic_templates ] + : test_condition_mt_post_native ] + +[ run test_condition_mt_dispatch.cpp : + : : + <conditional>@native-impl + [ requires cxx11_auto_declarations + cxx11_constexpr + cxx11_defaulted_functions + cxx11_final + cxx11_hdr_mutex + cxx11_hdr_thread + cxx11_hdr_tuple + cxx11_lambdas + cxx11_noexcept + cxx11_nullptr + cxx11_rvalue_references + cxx11_template_aliases + cxx11_thread_local + cxx11_variadic_templates ] + : test_condition_mt_dispatch_native ] + +[ run test_future_mt_post.cpp : + : : + <conditional>@native-impl + [ requires cxx11_auto_declarations + cxx11_constexpr + cxx11_defaulted_functions + cxx11_final + cxx11_hdr_mutex + cxx11_hdr_thread + cxx11_hdr_tuple + cxx11_lambdas + cxx11_noexcept + cxx11_nullptr + cxx11_rvalue_references + cxx11_template_aliases + cxx11_thread_local + cxx11_variadic_templates ] + : test_future_mt_post_native ] + +[ run test_future_mt_dispatch.cpp : + : : + <conditional>@native-impl + [ requires cxx11_auto_declarations + cxx11_constexpr + cxx11_defaulted_functions + cxx11_final + cxx11_hdr_mutex + cxx11_hdr_thread + cxx11_hdr_tuple + cxx11_lambdas + cxx11_noexcept + cxx11_nullptr + cxx11_rvalue_references + cxx11_template_aliases + cxx11_thread_local + cxx11_variadic_templates ] + : test_future_mt_dispatch_native ] ; + + +test-suite minimal : + asm native ; + +test-suite extra : + extra-asm extra-native ; + +explicit minmal ; +explicit extra ; + +test-suite full : + minimal extra ; diff --git a/src/boost/libs/fiber/test/test_async_dispatch.cpp b/src/boost/libs/fiber/test/test_async_dispatch.cpp new file mode 100644 index 00000000..55e050e2 --- /dev/null +++ b/src/boost/libs/fiber/test/test_async_dispatch.cpp @@ -0,0 +1,157 @@ +// (C) Copyright 2008-10 Anthony Williams +// 2015 Oliver Kowalke +// +// 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) + +#include <utility> +#include <memory> +#include <stdexcept> +#include <string> + +#include <boost/test/unit_test.hpp> + +#include <boost/fiber/all.hpp> + +struct A { + A() = default; + + A( A const&) = delete; + A & operator=( A const&) = delete; + + A( A && other) : + value{ other.value } { + other.value = 0; + } + + A & operator=( A && other) { + if ( this == & other) return * this; + value = other.value; + other.value = 0; + return * this; + } + + int value{ 0 }; +}; + +struct X { + int value; + + void foo( int i) { + value = i; + } +}; + +void fn1() { +} + +int fn2( int i) { + return i; +} + +int & fn3( int & i) { + return i; +} + +A fn4( A && a) { + return std::forward< A >( a); +} + +void test_async_1() { + boost::fibers::future< void > f1 = boost::fibers::async( boost::fibers::launch::dispatch, fn1); + BOOST_CHECK( f1.valid() ); + + f1.get(); +} + +void test_async_2() { + int i = 3; + boost::fibers::future< int > f1 = boost::fibers::async( boost::fibers::launch::dispatch, fn2, i); + BOOST_CHECK( f1.valid() ); + + BOOST_CHECK( i == f1.get()); +} + +void test_async_3() { + int i = 7; + boost::fibers::future< int& > f1 = boost::fibers::async( boost::fibers::launch::dispatch, fn3, std::ref( i) ); + BOOST_CHECK( f1.valid() ); + + BOOST_CHECK( & i == & f1.get()); +} + +void test_async_4() { + A a1; + a1.value = 7; + boost::fibers::future< A > f1 = boost::fibers::async( boost::fibers::launch::dispatch, fn4, std::move( a1) ); + BOOST_CHECK( f1.valid() ); + + A a2 = f1.get(); + BOOST_CHECK( 7 == a2.value); +} + +void test_async_5() { + X x = {0}; + BOOST_CHECK( 0 == x.value); + boost::fibers::future< void > f1 = boost::fibers::async( + boost::fibers::launch::dispatch, + std::bind( & X::foo, std::ref( x), 3) ); + BOOST_CHECK( f1.valid() ); + + f1.get(); + BOOST_CHECK( 3 == x.value); +} + +void test_async_6() { + X x = {0}; + BOOST_CHECK( 0 == x.value); + boost::fibers::future< void > f1 = boost::fibers::async( + boost::fibers::launch::dispatch, + std::bind( & X::foo, std::ref( x), std::placeholders::_1), 3); + BOOST_CHECK( f1.valid() ); + + f1.get(); + BOOST_CHECK( 3 == x.value); +} + +void test_async_stack_alloc() { + boost::fibers::future< void > f1 = boost::fibers::async( + boost::fibers::launch::dispatch, + std::allocator_arg, + boost::fibers::fixedsize_stack{}, + fn1); + BOOST_CHECK( f1.valid() ); + + f1.get(); +} + +void test_async_std_alloc() { + struct none {}; + boost::fibers::future< void > f1 = boost::fibers::async( + boost::fibers::launch::dispatch, + std::allocator_arg, + boost::fibers::fixedsize_stack{}, + std::allocator< none >{}, + fn1); + BOOST_CHECK( f1.valid() ); + + f1.get(); +} + + +boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[]) { + boost::unit_test_framework::test_suite* test = + BOOST_TEST_SUITE("Boost.Fiber: async test suite"); + + test->add(BOOST_TEST_CASE(test_async_1)); + test->add(BOOST_TEST_CASE(test_async_2)); + test->add(BOOST_TEST_CASE(test_async_3)); + test->add(BOOST_TEST_CASE(test_async_4)); + test->add(BOOST_TEST_CASE(test_async_5)); + test->add(BOOST_TEST_CASE(test_async_6)); + test->add(BOOST_TEST_CASE(test_async_stack_alloc)); + test->add(BOOST_TEST_CASE(test_async_std_alloc)); + + return test; +} diff --git a/src/boost/libs/fiber/test/test_async_post.cpp b/src/boost/libs/fiber/test/test_async_post.cpp new file mode 100644 index 00000000..95ab36ed --- /dev/null +++ b/src/boost/libs/fiber/test/test_async_post.cpp @@ -0,0 +1,131 @@ +// (C) Copyright 2008-10 Anthony Williams +// 2015 Oliver Kowalke +// +// 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) + +#include <utility> +#include <memory> +#include <stdexcept> +#include <string> + +#include <boost/test/unit_test.hpp> + +#include <boost/fiber/all.hpp> + +struct A { + A() = default; + + A( A const&) = delete; + A & operator=( A const&) = delete; + + A( A && other) : + value{ other.value } { + other.value = 0; + } + + A & operator=( A && other) { + if ( this == & other) return * this; + value = other.value; + other.value = 0; + return * this; + } + + int value{ 0 }; +}; + +struct X { + int value; + + void foo( int i) { + value = i; + } +}; + +void fn1() { +} + +int fn2( int i) { + return i; +} + +int & fn3( int & i) { + return i; +} + +A fn4( A && a) { + return std::forward< A >( a); +} + +void test_async_1() { + boost::fibers::future< void > f1 = boost::fibers::async( boost::fibers::launch::post, fn1); + BOOST_CHECK( f1.valid() ); + + f1.get(); +} + +void test_async_2() { + int i = 3; + boost::fibers::future< int > f1 = boost::fibers::async( boost::fibers::launch::post, fn2, i); + BOOST_CHECK( f1.valid() ); + + BOOST_CHECK( i == f1.get()); +} + +void test_async_3() { + int i = 7; + boost::fibers::future< int& > f1 = boost::fibers::async( boost::fibers::launch::post, fn3, std::ref( i) ); + BOOST_CHECK( f1.valid() ); + + BOOST_CHECK( & i == & f1.get()); +} + +void test_async_4() { + A a1; + a1.value = 7; + boost::fibers::future< A > f1 = boost::fibers::async( boost::fibers::launch::post, fn4, std::move( a1) ); + BOOST_CHECK( f1.valid() ); + + A a2 = f1.get(); + BOOST_CHECK( 7 == a2.value); +} + +void test_async_5() { + X x = {0}; + BOOST_CHECK( 0 == x.value); + boost::fibers::future< void > f1 = boost::fibers::async( + boost::fibers::launch::post, + std::bind( & X::foo, std::ref( x), 3) ); + BOOST_CHECK( f1.valid() ); + + f1.get(); + BOOST_CHECK( 3 == x.value); +} + +void test_async_6() { + X x = {0}; + BOOST_CHECK( 0 == x.value); + boost::fibers::future< void > f1 = boost::fibers::async( + boost::fibers::launch::post, + std::bind( & X::foo, std::ref( x), std::placeholders::_1), 3); + BOOST_CHECK( f1.valid() ); + + f1.get(); + BOOST_CHECK( 3 == x.value); +} + + +boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[]) { + boost::unit_test_framework::test_suite* test = + BOOST_TEST_SUITE("Boost.Fiber: async test suite"); + + test->add(BOOST_TEST_CASE(test_async_1)); + test->add(BOOST_TEST_CASE(test_async_2)); + test->add(BOOST_TEST_CASE(test_async_3)); + test->add(BOOST_TEST_CASE(test_async_4)); + test->add(BOOST_TEST_CASE(test_async_5)); + test->add(BOOST_TEST_CASE(test_async_6)); + + return test; +} diff --git a/src/boost/libs/fiber/test/test_barrier_dispatch.cpp b/src/boost/libs/fiber/test/test_barrier_dispatch.cpp new file mode 100644 index 00000000..8f1716d5 --- /dev/null +++ b/src/boost/libs/fiber/test/test_barrier_dispatch.cpp @@ -0,0 +1,71 @@ + +// Copyright Oliver Kowalke 2013. +// 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) +// +// This test is based on the tests of Boost.Thread + +#include <sstream> +#include <string> + +#include <boost/test/unit_test.hpp> + +#include <boost/fiber/all.hpp> + +int value1 = 0; +int value2 = 0; + +void fn1( boost::fibers::barrier & b) { + ++value1; + boost::this_fiber::yield(); + + b.wait(); + + ++value1; + boost::this_fiber::yield(); + ++value1; + boost::this_fiber::yield(); + ++value1; + boost::this_fiber::yield(); + ++value1; +} + +void fn2( boost::fibers::barrier & b) { + ++value2; + boost::this_fiber::yield(); + ++value2; + boost::this_fiber::yield(); + ++value2; + boost::this_fiber::yield(); + + b.wait(); + + ++value2; + boost::this_fiber::yield(); + ++value2; +} + +void test_barrier() { + value1 = 0; + value2 = 0; + + boost::fibers::barrier b( 2); + boost::fibers::fiber f1( boost::fibers::launch::dispatch, fn1, std::ref( b) ); + boost::fibers::fiber f2( boost::fibers::launch::dispatch, fn2, std::ref( b) ); + + f1.join(); + f2.join(); + + BOOST_CHECK_EQUAL( 5, value1); + BOOST_CHECK_EQUAL( 5, value2); +} + +boost::unit_test::test_suite * init_unit_test_suite( int, char* []) { + boost::unit_test::test_suite * test = + BOOST_TEST_SUITE("Boost.Fiber: barrier test suite"); + + test->add( BOOST_TEST_CASE( & test_barrier) ); + + return test; +} diff --git a/src/boost/libs/fiber/test/test_barrier_post.cpp b/src/boost/libs/fiber/test/test_barrier_post.cpp new file mode 100644 index 00000000..15354dde --- /dev/null +++ b/src/boost/libs/fiber/test/test_barrier_post.cpp @@ -0,0 +1,71 @@ + +// Copyright Oliver Kowalke 2013. +// 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) +// +// This test is based on the tests of Boost.Thread + +#include <sstream> +#include <string> + +#include <boost/test/unit_test.hpp> + +#include <boost/fiber/all.hpp> + +int value1 = 0; +int value2 = 0; + +void fn1( boost::fibers::barrier & b) { + ++value1; + boost::this_fiber::yield(); + + b.wait(); + + ++value1; + boost::this_fiber::yield(); + ++value1; + boost::this_fiber::yield(); + ++value1; + boost::this_fiber::yield(); + ++value1; +} + +void fn2( boost::fibers::barrier & b) { + ++value2; + boost::this_fiber::yield(); + ++value2; + boost::this_fiber::yield(); + ++value2; + boost::this_fiber::yield(); + + b.wait(); + + ++value2; + boost::this_fiber::yield(); + ++value2; +} + +void test_barrier() { + value1 = 0; + value2 = 0; + + boost::fibers::barrier b( 2); + boost::fibers::fiber f1( boost::fibers::launch::post, fn1, std::ref( b) ); + boost::fibers::fiber f2( boost::fibers::launch::post, fn2, std::ref( b) ); + + f1.join(); + f2.join(); + + BOOST_CHECK_EQUAL( 5, value1); + BOOST_CHECK_EQUAL( 5, value2); +} + +boost::unit_test::test_suite * init_unit_test_suite( int, char* []) { + boost::unit_test::test_suite * test = + BOOST_TEST_SUITE("Boost.Fiber: barrier test suite"); + + test->add( BOOST_TEST_CASE( & test_barrier) ); + + return test; +} diff --git a/src/boost/libs/fiber/test/test_buffered_channel_dispatch.cpp b/src/boost/libs/fiber/test/test_buffered_channel_dispatch.cpp new file mode 100644 index 00000000..980fdb91 --- /dev/null +++ b/src/boost/libs/fiber/test/test_buffered_channel_dispatch.cpp @@ -0,0 +1,531 @@ + +// Copyright Oliver Kowalke 2013. +// 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) + +#include <chrono> +#include <sstream> +#include <string> +#include <vector> + +#include <boost/assert.hpp> +#include <boost/test/unit_test.hpp> + +#include <boost/fiber/all.hpp> + +struct moveable { + bool state; + int value; + + moveable() : + state( false), + value( -1) { + } + + moveable( int v) : + state( true), + value( v) { + } + + moveable( moveable && other) : + state( other.state), + value( other.value) { + other.state = false; + other.value = -1; + } + + moveable & operator=( moveable && other) { + if ( this == & other) return * this; + state = other.state; + other.state = false; + value = other.value; + other.value = -1; + return * this; + } +}; + +void test_zero_wm() { + bool thrown = false; + try { + boost::fibers::buffered_channel< int > c( 0); + } catch ( boost::fibers::fiber_error const&) { + thrown = true; + } + BOOST_CHECK( thrown); +} + +void test_push() { + boost::fibers::buffered_channel< int > c( 16); + BOOST_CHECK( boost::fibers::channel_op_status::success == c.push( 1) ); +} + +void test_push_closed() { + boost::fibers::buffered_channel< int > c( 16); + c.close(); + BOOST_CHECK( boost::fibers::channel_op_status::closed == c.push( 1) ); +} + +void test_try_push() { + boost::fibers::buffered_channel< int > c( 2); + BOOST_CHECK( boost::fibers::channel_op_status::success == c.push( 1) ); +} + +void test_try_push_closed() { + boost::fibers::buffered_channel< int > c( 2); + BOOST_CHECK( boost::fibers::channel_op_status::success == c.try_push( 1) ); + c.close(); + BOOST_CHECK( boost::fibers::channel_op_status::closed == c.try_push( 2) ); +} + +void test_try_push_full() { + boost::fibers::buffered_channel< int > c( 2); + BOOST_CHECK( boost::fibers::channel_op_status::success == c.try_push( 1) ); + BOOST_CHECK( boost::fibers::channel_op_status::full == c.try_push( 1) ); +} + +void test_push_wait_for() { + boost::fibers::buffered_channel< int > c( 2); + BOOST_CHECK( boost::fibers::channel_op_status::success == c.push_wait_for( 1, std::chrono::seconds( 1) ) ); +} + +void test_push_wait_for_closed() { + boost::fibers::buffered_channel< int > c( 2); + c.close(); + BOOST_CHECK( boost::fibers::channel_op_status::closed == c.push_wait_for( 1, std::chrono::seconds( 1) ) ); +} + +void test_push_wait_for_timeout() { + boost::fibers::buffered_channel< int > c( 2); + BOOST_CHECK( boost::fibers::channel_op_status::success == c.push_wait_for( 1, std::chrono::seconds( 1) ) ); + BOOST_CHECK( boost::fibers::channel_op_status::timeout == c.push_wait_for( 1, std::chrono::seconds( 1) ) ); +} + +void test_push_wait_until() { + boost::fibers::buffered_channel< int > c( 2); + BOOST_CHECK( boost::fibers::channel_op_status::success == c.push_wait_until( 1, + std::chrono::system_clock::now() + std::chrono::seconds( 1) ) ); +} + +void test_push_wait_until_closed() { + boost::fibers::buffered_channel< int > c( 2); + c.close(); + BOOST_CHECK( boost::fibers::channel_op_status::closed == c.push_wait_until( 1, + std::chrono::system_clock::now() + std::chrono::seconds( 1) ) ); +} + +void test_push_wait_until_timeout() { + boost::fibers::buffered_channel< int > c( 2); + BOOST_CHECK( boost::fibers::channel_op_status::success == c.push_wait_until( 1, + std::chrono::system_clock::now() + std::chrono::seconds( 1) ) ); + BOOST_CHECK( boost::fibers::channel_op_status::timeout == c.push_wait_until( 1, + std::chrono::system_clock::now() + std::chrono::seconds( 1) ) ); +} + +void test_pop() { + boost::fibers::buffered_channel< int > c( 16); + int v1 = 2, v2 = 0; + BOOST_CHECK( boost::fibers::channel_op_status::success == c.push( v1) ); + BOOST_CHECK( boost::fibers::channel_op_status::success == c.pop( v2) ); + BOOST_CHECK_EQUAL( v1, v2); +} + +void test_pop_closed() { + boost::fibers::buffered_channel< int > c( 16); + int v1 = 2, v2 = 0; + BOOST_CHECK( boost::fibers::channel_op_status::success == c.push( v1) ); + c.close(); + BOOST_CHECK( boost::fibers::channel_op_status::success == c.pop( v2) ); + BOOST_CHECK_EQUAL( v1, v2); + BOOST_CHECK( boost::fibers::channel_op_status::closed == c.pop( v2) ); +} + +void test_pop_success() { + boost::fibers::buffered_channel< int > c( 16); + int v1 = 2, v2 = 0; + boost::fibers::fiber f1( boost::fibers::launch::dispatch, [&c,&v2](){ + BOOST_CHECK( boost::fibers::channel_op_status::success == c.pop( v2) ); + }); + boost::fibers::fiber f2( boost::fibers::launch::dispatch, [&c,v1](){ + BOOST_CHECK( boost::fibers::channel_op_status::success == c.push( v1) ); + }); + f1.join(); + f2.join(); + BOOST_CHECK_EQUAL( v1, v2); +} + +void test_value_pop() { + boost::fibers::buffered_channel< int > c( 16); + int v1 = 2, v2 = 0; + BOOST_CHECK( boost::fibers::channel_op_status::success == c.push( v1) ); + v2 = c.value_pop(); + BOOST_CHECK_EQUAL( v1, v2); +} + +void test_value_pop_closed() { + boost::fibers::buffered_channel< int > c( 16); + int v1 = 2, v2 = 0; + BOOST_CHECK( boost::fibers::channel_op_status::success == c.push( v1) ); + c.close(); + v2 = c.value_pop(); + BOOST_CHECK_EQUAL( v1, v2); + bool thrown = false; + try { + c.value_pop(); + } catch ( boost::fibers::fiber_error const&) { + thrown = true; + } + BOOST_CHECK( thrown); +} + +void test_value_pop_success() { + boost::fibers::buffered_channel< int > c( 16); + int v1 = 2, v2 = 0; + boost::fibers::fiber f1( boost::fibers::launch::dispatch, [&c,&v2](){ + v2 = c.value_pop(); + }); + boost::fibers::fiber f2( boost::fibers::launch::dispatch, [&c,v1](){ + BOOST_CHECK( boost::fibers::channel_op_status::success == c.push( v1) ); + }); + f1.join(); + f2.join(); + BOOST_CHECK_EQUAL( v1, v2); +} + +void test_try_pop() { + boost::fibers::buffered_channel< int > c( 16); + int v1 = 2, v2 = 0; + BOOST_CHECK( boost::fibers::channel_op_status::success == c.push( v1) ); + BOOST_CHECK( boost::fibers::channel_op_status::success == c.try_pop( v2) ); + BOOST_CHECK_EQUAL( v1, v2); +} + +void test_try_pop_closed() { + boost::fibers::buffered_channel< int > c( 16); + int v1 = 2, v2 = 0; + BOOST_CHECK( boost::fibers::channel_op_status::success == c.push( v1) ); + c.close(); + BOOST_CHECK( boost::fibers::channel_op_status::success == c.try_pop( v2) ); + BOOST_CHECK_EQUAL( v1, v2); + BOOST_CHECK( boost::fibers::channel_op_status::closed == c.try_pop( v2) ); +} + +void test_try_pop_success() { + boost::fibers::buffered_channel< int > c( 16); + int v1 = 2, v2 = 0; + boost::fibers::fiber f1( boost::fibers::launch::dispatch, [&c,&v2](){ + while ( boost::fibers::channel_op_status::success != c.try_pop( v2) ) { + boost::this_fiber::yield(); + } + }); + boost::fibers::fiber f2( boost::fibers::launch::dispatch, [&c,v1](){ + BOOST_CHECK( boost::fibers::channel_op_status::success == c.push( v1) ); + }); + f1.join(); + f2.join(); + BOOST_CHECK_EQUAL( v1, v2); +} + +void test_pop_wait_for() { + boost::fibers::buffered_channel< int > c( 16); + int v1 = 2, v2 = 0; + BOOST_CHECK( boost::fibers::channel_op_status::success == c.push( v1) ); + BOOST_CHECK( boost::fibers::channel_op_status::success == c.pop_wait_for( v2, std::chrono::seconds( 1) ) ); + BOOST_CHECK_EQUAL( v1, v2); +} + +void test_pop_wait_for_closed() { + boost::fibers::buffered_channel< int > c( 16); + int v1 = 2, v2 = 0; + BOOST_CHECK( boost::fibers::channel_op_status::success == c.push( v1) ); + c.close(); + BOOST_CHECK( boost::fibers::channel_op_status::success == c.pop_wait_for( v2, std::chrono::seconds( 1) ) ); + BOOST_CHECK_EQUAL( v1, v2); + BOOST_CHECK( boost::fibers::channel_op_status::closed == c.pop_wait_for( v2, std::chrono::seconds( 1) ) ); +} + +void test_pop_wait_for_success() { + boost::fibers::buffered_channel< int > c( 16); + int v1 = 2, v2 = 0; + boost::fibers::fiber f1( boost::fibers::launch::dispatch, [&c,&v2](){ + BOOST_CHECK( boost::fibers::channel_op_status::success == c.pop_wait_for( v2, std::chrono::seconds( 1) ) ); + }); + boost::fibers::fiber f2( boost::fibers::launch::dispatch, [&c,v1](){ + BOOST_CHECK( boost::fibers::channel_op_status::success == c.push( v1) ); + }); + f1.join(); + f2.join(); + BOOST_CHECK_EQUAL( v1, v2); +} + +void test_pop_wait_for_timeout() { + boost::fibers::buffered_channel< int > c( 16); + int v = 0; + boost::fibers::fiber f( boost::fibers::launch::dispatch, [&c,&v](){ + BOOST_CHECK( boost::fibers::channel_op_status::timeout == c.pop_wait_for( v, std::chrono::seconds( 1) ) ); + }); + f.join(); +} + +void test_pop_wait_until() { + boost::fibers::buffered_channel< int > c( 16); + int v1 = 2, v2 = 0; + BOOST_CHECK( boost::fibers::channel_op_status::success == c.push( v1) ); + BOOST_CHECK( boost::fibers::channel_op_status::success == c.pop_wait_until( v2, + std::chrono::system_clock::now() + std::chrono::seconds( 1) ) ); + BOOST_CHECK_EQUAL( v1, v2); +} + +void test_pop_wait_until_closed() { + boost::fibers::buffered_channel< int > c( 16); + int v1 = 2, v2 = 0; + BOOST_CHECK( boost::fibers::channel_op_status::success == c.push( v1) ); + c.close(); + BOOST_CHECK( boost::fibers::channel_op_status::success == c.pop_wait_until( v2, + std::chrono::system_clock::now() + std::chrono::seconds( 1) ) ); + BOOST_CHECK_EQUAL( v1, v2); + BOOST_CHECK( boost::fibers::channel_op_status::closed == c.pop_wait_until( v2, + std::chrono::system_clock::now() + std::chrono::seconds( 1) ) ); +} + +void test_pop_wait_until_success() { + boost::fibers::buffered_channel< int > c( 16); + int v1 = 2, v2 = 0; + boost::fibers::fiber f1( boost::fibers::launch::dispatch, [&c,&v2](){ + BOOST_CHECK( boost::fibers::channel_op_status::success == c.pop_wait_until( v2, + std::chrono::system_clock::now() + std::chrono::seconds( 1) ) ); + }); + boost::fibers::fiber f2( boost::fibers::launch::dispatch, [&c,v1](){ + BOOST_CHECK( boost::fibers::channel_op_status::success == c.push( v1) ); + }); + f1.join(); + f2.join(); + BOOST_CHECK_EQUAL( v1, v2); +} + +void test_pop_wait_until_timeout() { + boost::fibers::buffered_channel< int > c( 16); + int v = 0; + boost::fibers::fiber f( boost::fibers::launch::dispatch, [&c,&v](){ + BOOST_CHECK( boost::fibers::channel_op_status::timeout == c.pop_wait_until( v, + std::chrono::system_clock::now() + std::chrono::seconds( 1) ) ); + }); + f.join(); +} + +void test_wm_1() { + boost::fibers::buffered_channel< int > c( 4); + std::vector< boost::fibers::fiber::id > ids; + boost::fibers::fiber f1( boost::fibers::launch::dispatch, [&c,&ids](){ + ids.push_back( boost::this_fiber::get_id() ); + BOOST_CHECK( boost::fibers::channel_op_status::success == c.push( 1) ); + + ids.push_back( boost::this_fiber::get_id() ); + BOOST_CHECK( boost::fibers::channel_op_status::success == c.push( 2) ); + + ids.push_back( boost::this_fiber::get_id() ); + BOOST_CHECK( boost::fibers::channel_op_status::success == c.push( 3) ); + + ids.push_back( boost::this_fiber::get_id() ); + // would be blocked because channel is full + BOOST_CHECK( boost::fibers::channel_op_status::success == c.push( 4) ); + + ids.push_back( boost::this_fiber::get_id() ); + // would be blocked because channel is full + BOOST_CHECK( boost::fibers::channel_op_status::success == c.push( 5) ); + + ids.push_back( boost::this_fiber::get_id() ); + }); + boost::fibers::fiber f2( boost::fibers::launch::dispatch, [&c,&ids](){ + ids.push_back( boost::this_fiber::get_id() ); + BOOST_CHECK_EQUAL( 1, c.value_pop() ); + + // let other fiber run + boost::this_fiber::yield(); + + ids.push_back( boost::this_fiber::get_id() ); + BOOST_CHECK_EQUAL( 2, c.value_pop() ); + + ids.push_back( boost::this_fiber::get_id() ); + BOOST_CHECK_EQUAL( 3, c.value_pop() ); + + ids.push_back( boost::this_fiber::get_id() ); + BOOST_CHECK_EQUAL( 4, c.value_pop() ); + + ids.push_back( boost::this_fiber::get_id() ); + // would block because channel is empty + BOOST_CHECK_EQUAL( 5, c.value_pop() ); + + ids.push_back( boost::this_fiber::get_id() ); + }); + boost::fibers::fiber::id id1 = f1.get_id(); + boost::fibers::fiber::id id2 = f2.get_id(); + f1.join(); + f2.join(); + BOOST_CHECK_EQUAL( 12u, ids.size() ); + BOOST_CHECK_EQUAL( id1, ids[0]); + BOOST_CHECK_EQUAL( id1, ids[1]); + BOOST_CHECK_EQUAL( id1, ids[2]); + BOOST_CHECK_EQUAL( id1, ids[3]); + BOOST_CHECK_EQUAL( id2, ids[4]); + BOOST_CHECK_EQUAL( id1, ids[5]); + BOOST_CHECK_EQUAL( id2, ids[6]); + BOOST_CHECK_EQUAL( id2, ids[7]); + BOOST_CHECK_EQUAL( id2, ids[8]); + BOOST_CHECK_EQUAL( id2, ids[9]); + BOOST_CHECK_EQUAL( id1, ids[10]); + BOOST_CHECK_EQUAL( id2, ids[11]); +} + +void test_wm_2() { + boost::fibers::buffered_channel< int > c( 4); + std::vector< boost::fibers::fiber::id > ids; + boost::fibers::fiber f1( boost::fibers::launch::dispatch, [&c,&ids](){ + ids.push_back( boost::this_fiber::get_id() ); + BOOST_CHECK( boost::fibers::channel_op_status::success == c.push( 1) ); + + ids.push_back( boost::this_fiber::get_id() ); + BOOST_CHECK( boost::fibers::channel_op_status::success == c.push( 2) ); + + ids.push_back( boost::this_fiber::get_id() ); + BOOST_CHECK( boost::fibers::channel_op_status::success == c.push( 3) ); + + ids.push_back( boost::this_fiber::get_id() ); + // would be blocked because channel is full + BOOST_CHECK( boost::fibers::channel_op_status::success == c.push( 4) ); + + ids.push_back( boost::this_fiber::get_id() ); + // would be blocked because channel is full + BOOST_CHECK( boost::fibers::channel_op_status::success == c.push( 5) ); + + ids.push_back( boost::this_fiber::get_id() ); + }); + boost::fibers::fiber f2( boost::fibers::launch::dispatch, [&c,&ids](){ + ids.push_back( boost::this_fiber::get_id() ); + BOOST_CHECK_EQUAL( 1, c.value_pop() ); + + // let other fiber run + boost::this_fiber::yield(); + + ids.push_back( boost::this_fiber::get_id() ); + BOOST_CHECK_EQUAL( 2, c.value_pop() ); + + // let other fiber run + boost::this_fiber::yield(); + + ids.push_back( boost::this_fiber::get_id() ); + BOOST_CHECK_EQUAL( 3, c.value_pop() ); + + ids.push_back( boost::this_fiber::get_id() ); + BOOST_CHECK_EQUAL( 4, c.value_pop() ); + + ids.push_back( boost::this_fiber::get_id() ); + BOOST_CHECK_EQUAL( 5, c.value_pop() ); + + ids.push_back( boost::this_fiber::get_id() ); + }); + boost::fibers::fiber::id id1 = f1.get_id(); + boost::fibers::fiber::id id2 = f2.get_id(); + f1.join(); + f2.join(); + BOOST_CHECK_EQUAL( (std::size_t)12, ids.size() ); + BOOST_CHECK_EQUAL( id1, ids[0]); + BOOST_CHECK_EQUAL( id1, ids[1]); + BOOST_CHECK_EQUAL( id1, ids[2]); + BOOST_CHECK_EQUAL( id1, ids[3]); + BOOST_CHECK_EQUAL( id2, ids[4]); + BOOST_CHECK_EQUAL( id1, ids[5]); + BOOST_CHECK_EQUAL( id2, ids[6]); + BOOST_CHECK_EQUAL( id1, ids[7]); + BOOST_CHECK_EQUAL( id2, ids[8]); + BOOST_CHECK_EQUAL( id2, ids[9]); + BOOST_CHECK_EQUAL( id2, ids[10]); + BOOST_CHECK_EQUAL( id2, ids[11]); +} + +void test_moveable() { + boost::fibers::buffered_channel< moveable > c( 16); + moveable m1( 3), m2; + BOOST_CHECK( m1.state); + BOOST_CHECK_EQUAL( 3, m1.value); + BOOST_CHECK( ! m2.state); + BOOST_CHECK_EQUAL( -1, m2.value); + BOOST_CHECK( boost::fibers::channel_op_status::success == c.push( std::move( m1) ) ); + BOOST_CHECK( ! m1.state); + BOOST_CHECK( ! m2.state); + BOOST_CHECK( boost::fibers::channel_op_status::success == c.pop( m2) ); + BOOST_CHECK( ! m1.state); + BOOST_CHECK_EQUAL( -1, m1.value); + BOOST_CHECK( m2.state); + BOOST_CHECK_EQUAL( 3, m2.value); +} + +void test_rangefor() { + boost::fibers::buffered_channel< int > chan{ 4 }; + std::vector< int > vec; + boost::fibers::fiber f1( boost::fibers::launch::dispatch, [&chan]{ + chan.push( 1); + chan.push( 1); + chan.push( 2); + chan.push( 3); + chan.push( 5); + chan.push( 8); + chan.push( 12); + chan.close(); + }); + boost::fibers::fiber f2( boost::fibers::launch::dispatch, [&vec,&chan]{ + for ( int value : chan) { + vec.push_back( value); + } + }); + f1.join(); + f2.join(); + BOOST_CHECK_EQUAL( 1, vec[0]); + BOOST_CHECK_EQUAL( 1, vec[1]); + BOOST_CHECK_EQUAL( 2, vec[2]); + BOOST_CHECK_EQUAL( 3, vec[3]); + BOOST_CHECK_EQUAL( 5, vec[4]); + BOOST_CHECK_EQUAL( 8, vec[5]); + BOOST_CHECK_EQUAL( 12, vec[6]); +} + +boost::unit_test::test_suite * init_unit_test_suite( int, char* []) { + boost::unit_test::test_suite * test = + BOOST_TEST_SUITE("Boost.Fiber: buffered_channel test suite"); + + test->add( BOOST_TEST_CASE( & test_zero_wm) ); + test->add( BOOST_TEST_CASE( & test_push) ); + test->add( BOOST_TEST_CASE( & test_push_closed) ); + test->add( BOOST_TEST_CASE( & test_try_push) ); + test->add( BOOST_TEST_CASE( & test_try_push_closed) ); + test->add( BOOST_TEST_CASE( & test_try_push_full) ); + test->add( BOOST_TEST_CASE( & test_push_wait_for) ); + test->add( BOOST_TEST_CASE( & test_push_wait_for_closed) ); + test->add( BOOST_TEST_CASE( & test_push_wait_for_timeout) ); + test->add( BOOST_TEST_CASE( & test_push_wait_until) ); + test->add( BOOST_TEST_CASE( & test_push_wait_until_closed) ); + test->add( BOOST_TEST_CASE( & test_push_wait_until_timeout) ); + test->add( BOOST_TEST_CASE( & test_pop) ); + test->add( BOOST_TEST_CASE( & test_pop_closed) ); + test->add( BOOST_TEST_CASE( & test_pop_success) ); + test->add( BOOST_TEST_CASE( & test_value_pop) ); + test->add( BOOST_TEST_CASE( & test_value_pop_closed) ); + test->add( BOOST_TEST_CASE( & test_value_pop_success) ); + test->add( BOOST_TEST_CASE( & test_try_pop) ); + test->add( BOOST_TEST_CASE( & test_try_pop_closed) ); + test->add( BOOST_TEST_CASE( & test_try_pop_success) ); + test->add( BOOST_TEST_CASE( & test_pop_wait_for) ); + test->add( BOOST_TEST_CASE( & test_pop_wait_for_closed) ); + test->add( BOOST_TEST_CASE( & test_pop_wait_for_success) ); + test->add( BOOST_TEST_CASE( & test_pop_wait_for_timeout) ); + test->add( BOOST_TEST_CASE( & test_pop_wait_until) ); + test->add( BOOST_TEST_CASE( & test_pop_wait_until_closed) ); + test->add( BOOST_TEST_CASE( & test_pop_wait_until_success) ); + test->add( BOOST_TEST_CASE( & test_pop_wait_until_timeout) ); + test->add( BOOST_TEST_CASE( & test_wm_1) ); + test->add( BOOST_TEST_CASE( & test_wm_2) ); + test->add( BOOST_TEST_CASE( & test_moveable) ); + test->add( BOOST_TEST_CASE( & test_rangefor) ); + + return test; +} diff --git a/src/boost/libs/fiber/test/test_buffered_channel_post.cpp b/src/boost/libs/fiber/test/test_buffered_channel_post.cpp new file mode 100644 index 00000000..ffc14a7b --- /dev/null +++ b/src/boost/libs/fiber/test/test_buffered_channel_post.cpp @@ -0,0 +1,529 @@ + +// Copyright Oliver Kowalke 2013. +// 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) + +#include <chrono> +#include <sstream> +#include <string> +#include <vector> + +#include <boost/assert.hpp> +#include <boost/test/unit_test.hpp> + +#include <boost/fiber/all.hpp> + +struct moveable { + bool state; + int value; + + moveable() : + state( false), + value( -1) { + } + + moveable( int v) : + state( true), + value( v) { + } + + moveable( moveable && other) : + state( other.state), + value( other.value) { + other.state = false; + other.value = -1; + } + + moveable & operator=( moveable && other) { + if ( this == & other) return * this; + state = other.state; + other.state = false; + value = other.value; + other.value = -1; + return * this; + } +}; + +void test_zero_wm() { + bool thrown = false; + try { + boost::fibers::buffered_channel< int > c( 0); + } catch ( boost::fibers::fiber_error const&) { + thrown = true; + } + BOOST_CHECK( thrown); +} + +void test_push() { + boost::fibers::buffered_channel< int > c( 16); + BOOST_CHECK( boost::fibers::channel_op_status::success == c.push( 1) ); +} + +void test_push_closed() { + boost::fibers::buffered_channel< int > c( 16); + c.close(); + BOOST_CHECK( boost::fibers::channel_op_status::closed == c.push( 1) ); +} + +void test_try_push() { + boost::fibers::buffered_channel< int > c( 2); + BOOST_CHECK( boost::fibers::channel_op_status::success == c.push( 1) ); +} + +void test_try_push_closed() { + boost::fibers::buffered_channel< int > c( 2); + BOOST_CHECK( boost::fibers::channel_op_status::success == c.try_push( 1) ); + c.close(); + BOOST_CHECK( boost::fibers::channel_op_status::closed == c.try_push( 2) ); +} + +void test_try_push_full() { + boost::fibers::buffered_channel< int > c( 2); + BOOST_CHECK( boost::fibers::channel_op_status::success == c.try_push( 1) ); + BOOST_CHECK( boost::fibers::channel_op_status::full == c.try_push( 2) ); +} + +void test_push_wait_for() { + boost::fibers::buffered_channel< int > c( 2); + BOOST_CHECK( boost::fibers::channel_op_status::success == c.push_wait_for( 1, std::chrono::seconds( 1) ) ); +} + +void test_push_wait_for_closed() { + boost::fibers::buffered_channel< int > c( 2); + c.close(); + BOOST_CHECK( boost::fibers::channel_op_status::closed == c.push_wait_for( 1, std::chrono::seconds( 1) ) ); +} + +void test_push_wait_for_timeout() { + boost::fibers::buffered_channel< int > c( 2); + BOOST_CHECK( boost::fibers::channel_op_status::success == c.push_wait_for( 1, std::chrono::seconds( 1) ) ); + BOOST_CHECK( boost::fibers::channel_op_status::timeout == c.push_wait_for( 2, std::chrono::seconds( 1) ) ); +} + +void test_push_wait_until() { + boost::fibers::buffered_channel< int > c( 2); + BOOST_CHECK( boost::fibers::channel_op_status::success == c.push_wait_until( 1, + std::chrono::system_clock::now() + std::chrono::seconds( 1) ) ); +} + +void test_push_wait_until_closed() { + boost::fibers::buffered_channel< int > c( 2); + c.close(); + BOOST_CHECK( boost::fibers::channel_op_status::closed == c.push_wait_until( 1, + std::chrono::system_clock::now() + std::chrono::seconds( 1) ) ); +} + +void test_push_wait_until_timeout() { + boost::fibers::buffered_channel< int > c( 2); + BOOST_CHECK( boost::fibers::channel_op_status::success == c.push_wait_until( 1, + std::chrono::system_clock::now() + std::chrono::seconds( 1) ) ); + BOOST_CHECK( boost::fibers::channel_op_status::timeout == c.push_wait_until( 2, + std::chrono::system_clock::now() + std::chrono::seconds( 1) ) ); +} + +void test_pop() { + boost::fibers::buffered_channel< int > c( 16); + int v1 = 2, v2 = 0; + BOOST_CHECK( boost::fibers::channel_op_status::success == c.push( v1) ); + BOOST_CHECK( boost::fibers::channel_op_status::success == c.pop( v2) ); + BOOST_CHECK_EQUAL( v1, v2); +} + +void test_pop_closed() { + boost::fibers::buffered_channel< int > c( 16); + int v1 = 2, v2 = 0; + BOOST_CHECK( boost::fibers::channel_op_status::success == c.push( v1) ); + c.close(); + BOOST_CHECK( boost::fibers::channel_op_status::success == c.pop( v2) ); + BOOST_CHECK_EQUAL( v1, v2); + BOOST_CHECK( boost::fibers::channel_op_status::closed == c.pop( v2) ); +} + +void test_pop_success() { + boost::fibers::buffered_channel< int > c( 16); + int v1 = 2, v2 = 0; + boost::fibers::fiber f1( boost::fibers::launch::post, [&c,&v2](){ + BOOST_CHECK( boost::fibers::channel_op_status::success == c.pop( v2) ); + }); + boost::fibers::fiber f2( boost::fibers::launch::post, [&c,v1](){ + BOOST_CHECK( boost::fibers::channel_op_status::success == c.push( v1) ); + }); + f1.join(); + f2.join(); + BOOST_CHECK_EQUAL( v1, v2); +} + +void test_value_pop() { + boost::fibers::buffered_channel< int > c( 16); + int v1 = 2, v2 = 0; + BOOST_CHECK( boost::fibers::channel_op_status::success == c.push( v1) ); + v2 = c.value_pop(); + BOOST_CHECK_EQUAL( v1, v2); +} + +void test_value_pop_closed() { + boost::fibers::buffered_channel< int > c( 16); + int v1 = 2, v2 = 0; + BOOST_CHECK( boost::fibers::channel_op_status::success == c.push( v1) ); + c.close(); + v2 = c.value_pop(); + BOOST_CHECK_EQUAL( v1, v2); + bool thrown = false; + try { + c.value_pop(); + } catch ( boost::fibers::fiber_error const&) { + thrown = true; + } + BOOST_CHECK( thrown); +} + +void test_value_pop_success() { + boost::fibers::buffered_channel< int > c( 16); + int v1 = 2, v2 = 0; + boost::fibers::fiber f1( boost::fibers::launch::post, [&c,&v2](){ + v2 = c.value_pop(); + }); + boost::fibers::fiber f2( boost::fibers::launch::post, [&c,v1](){ + BOOST_CHECK( boost::fibers::channel_op_status::success == c.push( v1) ); + }); + f1.join(); + f2.join(); + BOOST_CHECK_EQUAL( v1, v2); +} + +void test_try_pop() { + boost::fibers::buffered_channel< int > c( 16); + int v1 = 2, v2 = 0; + BOOST_CHECK( boost::fibers::channel_op_status::success == c.push( v1) ); + BOOST_CHECK( boost::fibers::channel_op_status::success == c.try_pop( v2) ); + BOOST_CHECK_EQUAL( v1, v2); +} + +void test_try_pop_closed() { + boost::fibers::buffered_channel< int > c( 16); + int v1 = 2, v2 = 0; + BOOST_CHECK( boost::fibers::channel_op_status::success == c.push( v1) ); + c.close(); + BOOST_CHECK( boost::fibers::channel_op_status::success == c.try_pop( v2) ); + BOOST_CHECK_EQUAL( v1, v2); + BOOST_CHECK( boost::fibers::channel_op_status::closed == c.try_pop( v2) ); +} + +void test_try_pop_success() { + boost::fibers::buffered_channel< int > c( 16); + int v1 = 2, v2 = 0; + boost::fibers::fiber f1( boost::fibers::launch::post, [&c,&v2](){ + while ( boost::fibers::channel_op_status::success != c.try_pop( v2) ) { + boost::this_fiber::yield(); + } + }); + boost::fibers::fiber f2( boost::fibers::launch::post, [&c,v1](){ + BOOST_CHECK( boost::fibers::channel_op_status::success == c.push( v1) ); + }); + f1.join(); + f2.join(); + BOOST_CHECK_EQUAL( v1, v2); +} + +void test_pop_wait_for() { + boost::fibers::buffered_channel< int > c( 16); + int v1 = 2, v2 = 0; + BOOST_CHECK( boost::fibers::channel_op_status::success == c.push( v1) ); + BOOST_CHECK( boost::fibers::channel_op_status::success == c.pop_wait_for( v2, std::chrono::seconds( 1) ) ); + BOOST_CHECK_EQUAL( v1, v2); +} + +void test_pop_wait_for_closed() { + boost::fibers::buffered_channel< int > c( 16); + int v1 = 2, v2 = 0; + BOOST_CHECK( boost::fibers::channel_op_status::success == c.push( v1) ); + c.close(); + BOOST_CHECK( boost::fibers::channel_op_status::success == c.pop_wait_for( v2, std::chrono::seconds( 1) ) ); + BOOST_CHECK_EQUAL( v1, v2); + BOOST_CHECK( boost::fibers::channel_op_status::closed == c.pop_wait_for( v2, std::chrono::seconds( 1) ) ); +} + +void test_pop_wait_for_success() { + boost::fibers::buffered_channel< int > c( 16); + int v1 = 2, v2 = 0; + boost::fibers::fiber f1( boost::fibers::launch::post, [&c,&v2](){ + BOOST_CHECK( boost::fibers::channel_op_status::success == c.pop_wait_for( v2, std::chrono::seconds( 1) ) ); + }); + boost::fibers::fiber f2( boost::fibers::launch::post, [&c,v1](){ + BOOST_CHECK( boost::fibers::channel_op_status::success == c.push( v1) ); + }); + f1.join(); + f2.join(); + BOOST_CHECK_EQUAL( v1, v2); +} + +void test_pop_wait_for_timeout() { + boost::fibers::buffered_channel< int > c( 16); + int v = 0; + boost::fibers::fiber f( boost::fibers::launch::post, [&c,&v](){ + BOOST_CHECK( boost::fibers::channel_op_status::timeout == c.pop_wait_for( v, std::chrono::seconds( 1) ) ); + }); + f.join(); +} + +void test_pop_wait_until() { + boost::fibers::buffered_channel< int > c( 16); + int v1 = 2, v2 = 0; + BOOST_CHECK( boost::fibers::channel_op_status::success == c.push( v1) ); + BOOST_CHECK( boost::fibers::channel_op_status::success == c.pop_wait_until( v2, + std::chrono::system_clock::now() + std::chrono::seconds( 1) ) ); + BOOST_CHECK_EQUAL( v1, v2); +} + +void test_pop_wait_until_closed() { + boost::fibers::buffered_channel< int > c( 16); + int v1 = 2, v2 = 0; + BOOST_CHECK( boost::fibers::channel_op_status::success == c.push( v1) ); + c.close(); + BOOST_CHECK( boost::fibers::channel_op_status::success == c.pop_wait_until( v2, + std::chrono::system_clock::now() + std::chrono::seconds( 1) ) ); + BOOST_CHECK_EQUAL( v1, v2); + BOOST_CHECK( boost::fibers::channel_op_status::closed == c.pop_wait_until( v2, + std::chrono::system_clock::now() + std::chrono::seconds( 1) ) ); +} + +void test_pop_wait_until_success() { + boost::fibers::buffered_channel< int > c( 16); + int v1 = 2, v2 = 0; + boost::fibers::fiber f1( boost::fibers::launch::post, [&c,&v2](){ + BOOST_CHECK( boost::fibers::channel_op_status::success == c.pop_wait_until( v2, + std::chrono::system_clock::now() + std::chrono::seconds( 1) ) ); + }); + boost::fibers::fiber f2( boost::fibers::launch::post, [&c,v1](){ + BOOST_CHECK( boost::fibers::channel_op_status::success == c.push( v1) ); + }); + f1.join(); + f2.join(); + BOOST_CHECK_EQUAL( v1, v2); +} + +void test_pop_wait_until_timeout() { + boost::fibers::buffered_channel< int > c( 16); + int v = 0; + boost::fibers::fiber f( boost::fibers::launch::post, [&c,&v](){ + BOOST_CHECK( boost::fibers::channel_op_status::timeout == c.pop_wait_until( v, + std::chrono::system_clock::now() + std::chrono::seconds( 1) ) ); + }); + f.join(); +} + +void test_wm_1() { + boost::fibers::buffered_channel< int > c( 4); + std::vector< boost::fibers::fiber::id > ids; + boost::fibers::fiber f1( boost::fibers::launch::post, [&c,&ids](){ + ids.push_back( boost::this_fiber::get_id() ); + BOOST_CHECK( boost::fibers::channel_op_status::success == c.push( 1) ); + + ids.push_back( boost::this_fiber::get_id() ); + BOOST_CHECK( boost::fibers::channel_op_status::success == c.push( 2) ); + + ids.push_back( boost::this_fiber::get_id() ); + BOOST_CHECK( boost::fibers::channel_op_status::success == c.push( 3) ); + + ids.push_back( boost::this_fiber::get_id() ); + // would be blocked because channel is full + BOOST_CHECK( boost::fibers::channel_op_status::success == c.push( 4) ); + + ids.push_back( boost::this_fiber::get_id() ); + // would be blocked because channel is full + BOOST_CHECK( boost::fibers::channel_op_status::success == c.push( 5) ); + + ids.push_back( boost::this_fiber::get_id() ); + }); + boost::fibers::fiber f2( boost::fibers::launch::post, [&c,&ids](){ + ids.push_back( boost::this_fiber::get_id() ); + BOOST_CHECK_EQUAL( 1, c.value_pop() ); + + // let other fiber run + boost::this_fiber::yield(); + + ids.push_back( boost::this_fiber::get_id() ); + BOOST_CHECK_EQUAL( 2, c.value_pop() ); + + ids.push_back( boost::this_fiber::get_id() ); + BOOST_CHECK_EQUAL( 3, c.value_pop() ); + + ids.push_back( boost::this_fiber::get_id() ); + BOOST_CHECK_EQUAL( 4, c.value_pop() ); + + ids.push_back( boost::this_fiber::get_id() ); + // would block because channel is empty + BOOST_CHECK_EQUAL( 5, c.value_pop() ); + + ids.push_back( boost::this_fiber::get_id() ); + }); + boost::fibers::fiber::id id1 = f1.get_id(); + boost::fibers::fiber::id id2 = f2.get_id(); + f1.join(); + f2.join(); + BOOST_CHECK_EQUAL( (std::size_t)12, ids.size() ); + BOOST_CHECK_EQUAL( id1, ids[0]); + BOOST_CHECK_EQUAL( id1, ids[1]); + BOOST_CHECK_EQUAL( id1, ids[2]); + BOOST_CHECK_EQUAL( id1, ids[3]); + BOOST_CHECK_EQUAL( id2, ids[4]); + BOOST_CHECK_EQUAL( id1, ids[5]); + BOOST_CHECK_EQUAL( id2, ids[6]); + BOOST_CHECK_EQUAL( id2, ids[7]); + BOOST_CHECK_EQUAL( id2, ids[8]); + BOOST_CHECK_EQUAL( id2, ids[9]); + BOOST_CHECK_EQUAL( id1, ids[10]); + BOOST_CHECK_EQUAL( id2, ids[11]); +} + +void test_wm_2() { + boost::fibers::buffered_channel< int > c( 8); + std::vector< boost::fibers::fiber::id > ids; + boost::fibers::fiber f1( boost::fibers::launch::post, [&c,&ids](){ + ids.push_back( boost::this_fiber::get_id() ); + BOOST_CHECK( boost::fibers::channel_op_status::success == c.push( 1) ); + + ids.push_back( boost::this_fiber::get_id() ); + BOOST_CHECK( boost::fibers::channel_op_status::success == c.push( 2) ); + + ids.push_back( boost::this_fiber::get_id() ); + BOOST_CHECK( boost::fibers::channel_op_status::success == c.push( 3) ); + + ids.push_back( boost::this_fiber::get_id() ); + BOOST_CHECK( boost::fibers::channel_op_status::success == c.push( 4) ); + + ids.push_back( boost::this_fiber::get_id() ); + BOOST_CHECK( boost::fibers::channel_op_status::success == c.push( 5) ); + + ids.push_back( boost::this_fiber::get_id() ); + }); + boost::fibers::fiber f2( boost::fibers::launch::post, [&c,&ids](){ + ids.push_back( boost::this_fiber::get_id() ); + BOOST_CHECK_EQUAL( 1, c.value_pop() ); + + // let other fiber run + boost::this_fiber::yield(); + + ids.push_back( boost::this_fiber::get_id() ); + BOOST_CHECK_EQUAL( 2, c.value_pop() ); + + // let other fiber run + boost::this_fiber::yield(); + + ids.push_back( boost::this_fiber::get_id() ); + BOOST_CHECK_EQUAL( 3, c.value_pop() ); + + ids.push_back( boost::this_fiber::get_id() ); + BOOST_CHECK_EQUAL( 4, c.value_pop() ); + + ids.push_back( boost::this_fiber::get_id() ); + BOOST_CHECK_EQUAL( 5, c.value_pop() ); + + ids.push_back( boost::this_fiber::get_id() ); + }); + boost::fibers::fiber::id id1 = f1.get_id(); + boost::fibers::fiber::id id2 = f2.get_id(); + f1.join(); + f2.join(); + BOOST_CHECK_EQUAL( (std::size_t)12, ids.size() ); + BOOST_CHECK_EQUAL( id1, ids[0]); + BOOST_CHECK_EQUAL( id1, ids[1]); + BOOST_CHECK_EQUAL( id1, ids[2]); + BOOST_CHECK_EQUAL( id1, ids[3]); + BOOST_CHECK_EQUAL( id1, ids[4]); + BOOST_CHECK_EQUAL( id1, ids[5]); + BOOST_CHECK_EQUAL( id2, ids[6]); + BOOST_CHECK_EQUAL( id2, ids[7]); + BOOST_CHECK_EQUAL( id2, ids[8]); + BOOST_CHECK_EQUAL( id2, ids[9]); + BOOST_CHECK_EQUAL( id2, ids[10]); + BOOST_CHECK_EQUAL( id2, ids[11]); +} + +void test_moveable() { + boost::fibers::buffered_channel< moveable > c( 16); + moveable m1( 3), m2; + BOOST_CHECK( m1.state); + BOOST_CHECK_EQUAL( 3, m1.value); + BOOST_CHECK( ! m2.state); + BOOST_CHECK_EQUAL( -1, m2.value); + BOOST_CHECK( boost::fibers::channel_op_status::success == c.push( std::move( m1) ) ); + BOOST_CHECK( ! m1.state); + BOOST_CHECK( ! m2.state); + BOOST_CHECK( boost::fibers::channel_op_status::success == c.pop( m2) ); + BOOST_CHECK( ! m1.state); + BOOST_CHECK_EQUAL( -1, m1.value); + BOOST_CHECK( m2.state); + BOOST_CHECK_EQUAL( 3, m2.value); +} + +void test_rangefor() { + boost::fibers::buffered_channel< int > chan{ 2 }; + std::vector< int > vec; + boost::fibers::fiber f1([&chan]{ + chan.push( 1); + chan.push( 1); + chan.push( 2); + chan.push( 3); + chan.push( 5); + chan.push( 8); + chan.push( 12); + chan.close(); + }); + boost::fibers::fiber f2([&vec,&chan]{ + for ( int value : chan) { + vec.push_back( value); + } + }); + f1.join(); + f2.join(); + BOOST_CHECK_EQUAL( 1, vec[0]); + BOOST_CHECK_EQUAL( 1, vec[1]); + BOOST_CHECK_EQUAL( 2, vec[2]); + BOOST_CHECK_EQUAL( 3, vec[3]); + BOOST_CHECK_EQUAL( 5, vec[4]); + BOOST_CHECK_EQUAL( 8, vec[5]); + BOOST_CHECK_EQUAL( 12, vec[6]); +} + +boost::unit_test::test_suite * init_unit_test_suite( int, char* []) { + boost::unit_test::test_suite * test = + BOOST_TEST_SUITE("Boost.Fiber: buffered_channel test suite"); + + test->add( BOOST_TEST_CASE( & test_zero_wm) ); + test->add( BOOST_TEST_CASE( & test_push) ); + test->add( BOOST_TEST_CASE( & test_push_closed) ); + test->add( BOOST_TEST_CASE( & test_try_push) ); + test->add( BOOST_TEST_CASE( & test_try_push_closed) ); + test->add( BOOST_TEST_CASE( & test_try_push_full) ); + test->add( BOOST_TEST_CASE( & test_push_wait_for) ); + test->add( BOOST_TEST_CASE( & test_push_wait_for_closed) ); + test->add( BOOST_TEST_CASE( & test_push_wait_for_timeout) ); + test->add( BOOST_TEST_CASE( & test_push_wait_until) ); + test->add( BOOST_TEST_CASE( & test_push_wait_until_closed) ); + test->add( BOOST_TEST_CASE( & test_push_wait_until_timeout) ); + test->add( BOOST_TEST_CASE( & test_pop) ); + test->add( BOOST_TEST_CASE( & test_pop_closed) ); + test->add( BOOST_TEST_CASE( & test_pop_success) ); + test->add( BOOST_TEST_CASE( & test_value_pop) ); + test->add( BOOST_TEST_CASE( & test_value_pop_closed) ); + test->add( BOOST_TEST_CASE( & test_value_pop_success) ); + test->add( BOOST_TEST_CASE( & test_try_pop) ); + test->add( BOOST_TEST_CASE( & test_try_pop_closed) ); + test->add( BOOST_TEST_CASE( & test_try_pop_success) ); + test->add( BOOST_TEST_CASE( & test_pop_wait_for) ); + test->add( BOOST_TEST_CASE( & test_pop_wait_for_closed) ); + test->add( BOOST_TEST_CASE( & test_pop_wait_for_success) ); + test->add( BOOST_TEST_CASE( & test_pop_wait_for_timeout) ); + test->add( BOOST_TEST_CASE( & test_pop_wait_until) ); + test->add( BOOST_TEST_CASE( & test_pop_wait_until_closed) ); + test->add( BOOST_TEST_CASE( & test_pop_wait_until_success) ); + test->add( BOOST_TEST_CASE( & test_pop_wait_until_timeout) ); + test->add( BOOST_TEST_CASE( & test_wm_1) ); + test->add( BOOST_TEST_CASE( & test_wm_2) ); + test->add( BOOST_TEST_CASE( & test_moveable) ); + test->add( BOOST_TEST_CASE( & test_rangefor) ); + + return test; +} diff --git a/src/boost/libs/fiber/test/test_condition_mt_dispatch.cpp b/src/boost/libs/fiber/test/test_condition_mt_dispatch.cpp new file mode 100644 index 00000000..e57fd087 --- /dev/null +++ b/src/boost/libs/fiber/test/test_condition_mt_dispatch.cpp @@ -0,0 +1,164 @@ + +// Copyright Oliver Kowalke 2013. +// 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) +// +// This test is based on the tests of Boost.Thread + +#include <cstdio> +#include <cstdlib> +#include <iostream> +#include <map> +#include <mutex> +#include <stdexcept> +#include <vector> + +#include <boost/atomic.hpp> +#include <boost/bind.hpp> +#include <boost/chrono.hpp> +#include <boost/cstdint.hpp> +#include <boost/function.hpp> +#include <boost/ref.hpp> +#include <boost/test/unit_test.hpp> +#include <boost/thread.hpp> +#include <boost/utility.hpp> + +#include <boost/fiber/all.hpp> + +typedef boost::chrono::milliseconds ms; + +boost::atomic< int > value1; + +void wait_fn( boost::barrier & b, + boost::fibers::mutex & mtx, + boost::fibers::condition_variable & cond, + bool & flag) { + b.wait(); + std::unique_lock< boost::fibers::mutex > lk( mtx); + cond.wait( lk, [&flag](){ return flag; }); + ++value1; +} + +void notify_one_fn( boost::barrier & b, + boost::fibers::mutex & mtx, + boost::fibers::condition_variable & cond, + bool & flag) { + b.wait(); + std::unique_lock< boost::fibers::mutex > lk( mtx); + flag = true; + lk.unlock(); + cond.notify_one(); +} + +void notify_all_fn( boost::barrier & b, + boost::fibers::mutex & mtx, + boost::fibers::condition_variable & cond, + bool & flag) { + b.wait(); + std::unique_lock< boost::fibers::mutex > lk( mtx); + flag = true; + lk.unlock(); + cond.notify_all(); +} + +void fn1( boost::barrier & b, + boost::fibers::mutex & mtx, + boost::fibers::condition_variable & cond, + bool & flag) { + boost::fibers::fiber( + boost::fibers::launch::dispatch, + wait_fn, + std::ref( b), + std::ref( mtx), + std::ref( cond), + std::ref( flag) ).join(); +} + +void fn2( boost::barrier & b, + boost::fibers::mutex & mtx, + boost::fibers::condition_variable & cond, + bool & flag) { + boost::fibers::fiber( + boost::fibers::launch::dispatch, + notify_one_fn, + std::ref( b), + std::ref( mtx), + std::ref( cond), + std::ref( flag) ).join(); +} + +void fn3( boost::barrier & b, + boost::fibers::mutex & mtx, + boost::fibers::condition_variable & cond, + bool & flag) { + boost::fibers::fiber( + boost::fibers::launch::dispatch, + notify_all_fn, + std::ref( b), + std::ref( mtx), + std::ref( cond), + std::ref( flag) ).join(); +} + +void test_one_waiter_notify_one() { + for ( int i = 0; i < 10; ++i) { + boost::barrier b( 2); + + bool flag = false; + value1 = 0; + boost::fibers::mutex mtx; + boost::fibers::condition_variable cond; + + BOOST_CHECK( 0 == value1); + + boost::thread t1(std::bind( fn1, std::ref( b), std::ref( mtx), std::ref( cond), std::ref( flag) ) ); + boost::thread t2(std::bind( fn2, std::ref( b), std::ref( mtx), std::ref( cond), std::ref( flag) ) ); + + t1.join(); + t2.join(); + + BOOST_CHECK( 1 == value1); + } +} + +void test_two_waiter_notify_all() { + for ( int i = 0; i < 10; ++i) { + boost::barrier b( 3); + + bool flag = false; + value1 = 0; + boost::fibers::mutex mtx; + boost::fibers::condition_variable cond; + + BOOST_CHECK( 0 == value1); + + boost::thread t1(std::bind( fn1, std::ref( b), std::ref( mtx), std::ref( cond), std::ref( flag) ) ); + boost::thread t2(std::bind( fn1, std::ref( b), std::ref( mtx), std::ref( cond), std::ref( flag) ) ); + boost::thread t3(std::bind( fn3, std::ref( b), std::ref( mtx), std::ref( cond), std::ref( flag) ) ); + + t1.join(); + t2.join(); + t3.join(); + + BOOST_CHECK( 2 == value1); + } +} + +void test_dummy() { +} + +boost::unit_test::test_suite * init_unit_test_suite( int, char* []) +{ + boost::unit_test::test_suite * test = + BOOST_TEST_SUITE("Boost.Fiber: multithreaded condition_variable test suite"); + +#if ! defined(BOOST_FIBERS_NO_ATOMICS) + test->add( BOOST_TEST_CASE( & test_one_waiter_notify_one) ); + test->add( BOOST_TEST_CASE( & test_two_waiter_notify_all) ); +#else + test->add( BOOST_TEST_CASE( & test_dummy) ); +#endif + + return test; +} diff --git a/src/boost/libs/fiber/test/test_condition_mt_post.cpp b/src/boost/libs/fiber/test/test_condition_mt_post.cpp new file mode 100644 index 00000000..b85647eb --- /dev/null +++ b/src/boost/libs/fiber/test/test_condition_mt_post.cpp @@ -0,0 +1,164 @@ + +// Copyright Oliver Kowalke 2013. +// 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) +// +// This test is based on the tests of Boost.Thread + +#include <cstdio> +#include <cstdlib> +#include <iostream> +#include <map> +#include <mutex> +#include <stdexcept> +#include <vector> + +#include <boost/atomic.hpp> +#include <boost/bind.hpp> +#include <boost/chrono.hpp> +#include <boost/cstdint.hpp> +#include <boost/function.hpp> +#include <boost/ref.hpp> +#include <boost/test/unit_test.hpp> +#include <boost/thread.hpp> +#include <boost/utility.hpp> + +#include <boost/fiber/all.hpp> + +typedef boost::chrono::milliseconds ms; + +boost::atomic< int > value1; + +void wait_fn( boost::barrier & b, + boost::fibers::mutex & mtx, + boost::fibers::condition_variable & cond, + bool & flag) { + b.wait(); + std::unique_lock< boost::fibers::mutex > lk( mtx); + cond.wait( lk, [&flag](){ return flag; }); + ++value1; +} + +void notify_one_fn( boost::barrier & b, + boost::fibers::mutex & mtx, + boost::fibers::condition_variable & cond, + bool & flag) { + b.wait(); + std::unique_lock< boost::fibers::mutex > lk( mtx); + flag = true; + lk.unlock(); + cond.notify_one(); +} + +void notify_all_fn( boost::barrier & b, + boost::fibers::mutex & mtx, + boost::fibers::condition_variable & cond, + bool & flag) { + b.wait(); + std::unique_lock< boost::fibers::mutex > lk( mtx); + flag = true; + lk.unlock(); + cond.notify_all(); +} + +void fn1( boost::barrier & b, + boost::fibers::mutex & mtx, + boost::fibers::condition_variable & cond, + bool & flag) { + boost::fibers::fiber( + boost::fibers::launch::post, + wait_fn, + std::ref( b), + std::ref( mtx), + std::ref( cond), + std::ref( flag) ).join(); +} + +void fn2( boost::barrier & b, + boost::fibers::mutex & mtx, + boost::fibers::condition_variable & cond, + bool & flag) { + boost::fibers::fiber( + boost::fibers::launch::post, + notify_one_fn, + std::ref( b), + std::ref( mtx), + std::ref( cond), + std::ref( flag) ).join(); +} + +void fn3( boost::barrier & b, + boost::fibers::mutex & mtx, + boost::fibers::condition_variable & cond, + bool & flag) { + boost::fibers::fiber( + boost::fibers::launch::post, + notify_all_fn, + std::ref( b), + std::ref( mtx), + std::ref( cond), + std::ref( flag) ).join(); +} + +void test_one_waiter_notify_one() { + for ( int i = 0; i < 10; ++i) { + boost::barrier b( 2); + + bool flag = false; + value1 = 0; + boost::fibers::mutex mtx; + boost::fibers::condition_variable cond; + + BOOST_CHECK( 0 == value1); + + boost::thread t1(std::bind( fn1, std::ref( b), std::ref( mtx), std::ref( cond), std::ref( flag) ) ); + boost::thread t2(std::bind( fn2, std::ref( b), std::ref( mtx), std::ref( cond), std::ref( flag) ) ); + + t1.join(); + t2.join(); + + BOOST_CHECK( 1 == value1); + } +} + +void test_two_waiter_notify_all() { + for ( int i = 0; i < 10; ++i) { + boost::barrier b( 3); + + bool flag = false; + value1 = 0; + boost::fibers::mutex mtx; + boost::fibers::condition_variable cond; + + BOOST_CHECK( 0 == value1); + + boost::thread t1(std::bind( fn1, std::ref( b), std::ref( mtx), std::ref( cond), std::ref( flag) ) ); + boost::thread t2(std::bind( fn1, std::ref( b), std::ref( mtx), std::ref( cond), std::ref( flag) ) ); + boost::thread t3(std::bind( fn3, std::ref( b), std::ref( mtx), std::ref( cond), std::ref( flag) ) ); + + t1.join(); + t2.join(); + t3.join(); + + BOOST_CHECK( 2 == value1); + } +} + +void test_dummy() { +} + +boost::unit_test::test_suite * init_unit_test_suite( int, char* []) +{ + boost::unit_test::test_suite * test = + BOOST_TEST_SUITE("Boost.Fiber: multithreaded condition_variable test suite"); + +#if ! defined(BOOST_FIBERS_NO_ATOMICS) + test->add( BOOST_TEST_CASE( & test_one_waiter_notify_one) ); + test->add( BOOST_TEST_CASE( & test_two_waiter_notify_all) ); +#else + test->add( BOOST_TEST_CASE( & test_dummy) ); +#endif + + return test; +} diff --git a/src/boost/libs/fiber/test/test_condition_variable_any_dispatch.cpp b/src/boost/libs/fiber/test/test_condition_variable_any_dispatch.cpp new file mode 100644 index 00000000..e227fd45 --- /dev/null +++ b/src/boost/libs/fiber/test/test_condition_variable_any_dispatch.cpp @@ -0,0 +1,501 @@ + +// Copyright Oliver Kowalke 2013. +// 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) +// +// This test is based on the tests of Boost.Thread + +#include <chrono> +#include <cstdlib> +#include <cstdio> +#include <iostream> +#include <map> +#include <stdexcept> +#include <vector> + +#include <boost/test/unit_test.hpp> + +#include <boost/fiber/all.hpp> + +typedef std::chrono::nanoseconds ns; +typedef std::chrono::milliseconds ms; + +int value1 = 0; + +inline +std::chrono::system_clock::time_point delay(int secs, int msecs = 0, int /*nsecs*/ = 0) { + std::chrono::system_clock::time_point t = std::chrono::system_clock::now(); + t += std::chrono::seconds( secs); + t += std::chrono::milliseconds( msecs); + //t += std::chrono::nanoseconds( nsecs); + + return t; +} + +struct condition_test_data { + condition_test_data() : notified(0), awoken(0) { } + + boost::fibers::mutex mutex; + boost::fibers::condition_variable_any cond; + int notified; + int awoken; +}; + +void condition_test_fiber(condition_test_data* data) { + try { + data->mutex.lock(); + while (!(data->notified > 0)) + data->cond.wait(data->mutex); + data->awoken++; + } catch ( ... ) { + } + data->mutex.unlock(); +} + +struct cond_predicate { + cond_predicate(int& var, int val) : _var(var), _val(val) { } + + bool operator()() { return _var == _val; } + + int& _var; + int _val; +private: + void operator=(cond_predicate&); + +}; + +void notify_one_fn( boost::fibers::condition_variable_any & cond) { + cond.notify_one(); +} + +void notify_all_fn( boost::fibers::condition_variable_any & cond) { + cond.notify_all(); +} + +void wait_fn( + boost::fibers::mutex & mtx, + boost::fibers::condition_variable_any & cond) { + mtx.lock(); + cond.wait( mtx); + ++value1; + mtx.unlock(); +} + +void test_one_waiter_notify_one() { + value1 = 0; + boost::fibers::mutex mtx; + boost::fibers::condition_variable_any cond; + + boost::fibers::fiber f1( + boost::fibers::launch::dispatch, + wait_fn, + std::ref( mtx), + std::ref( cond) ); + BOOST_CHECK_EQUAL( 0, value1); + + boost::fibers::fiber f2( + boost::fibers::launch::dispatch, + notify_one_fn, + std::ref( cond) ); + + BOOST_CHECK_EQUAL( 0, value1); + + f1.join(); + f2.join(); + + BOOST_CHECK_EQUAL( 1, value1); +} + +void test_two_waiter_notify_one() { + value1 = 0; + boost::fibers::mutex mtx; + boost::fibers::condition_variable_any cond; + + boost::fibers::fiber f1( + boost::fibers::launch::dispatch, + wait_fn, + std::ref( mtx), + std::ref( cond) ); + BOOST_CHECK_EQUAL( 0, value1); + + boost::fibers::fiber f2( + boost::fibers::launch::dispatch, + wait_fn, + std::ref( mtx), + std::ref( cond) ); + BOOST_CHECK_EQUAL( 0, value1); + + boost::fibers::fiber f3( + boost::fibers::launch::dispatch, + notify_one_fn, + std::ref( cond) ); + BOOST_CHECK_EQUAL( 0, value1); + + boost::fibers::fiber f4( + boost::fibers::launch::dispatch, + notify_one_fn, + std::ref( cond) ); + BOOST_CHECK_EQUAL( 1, value1); + + f1.join(); + f2.join(); + f3.join(); + f4.join(); + + BOOST_CHECK_EQUAL( 2, value1); +} + +void test_two_waiter_notify_all() { + value1 = 0; + boost::fibers::mutex mtx; + boost::fibers::condition_variable_any cond; + + boost::fibers::fiber f1( + boost::fibers::launch::dispatch, + wait_fn, + std::ref( mtx), + std::ref( cond) ); + BOOST_CHECK_EQUAL( 0, value1); + + boost::fibers::fiber f2( + boost::fibers::launch::dispatch, + wait_fn, + std::ref( mtx), + std::ref( cond) ); + BOOST_CHECK_EQUAL( 0, value1); + + boost::fibers::fiber f3( + boost::fibers::launch::dispatch, + notify_all_fn, + std::ref( cond) ); + BOOST_CHECK_EQUAL( 0, value1); + + boost::fibers::fiber f4( + boost::fibers::launch::dispatch, + wait_fn, + std::ref( mtx), + std::ref( cond) ); + BOOST_CHECK_EQUAL( 2, value1); + + boost::fibers::fiber f5( + boost::fibers::launch::dispatch, + notify_all_fn, + std::ref( cond) ); + BOOST_CHECK_EQUAL( 2, value1); + + f1.join(); + f2.join(); + f3.join(); + f4.join(); + f5.join(); + + BOOST_CHECK_EQUAL( 3, value1); +} + +int test1 = 0; +int test2 = 0; + +int runs = 0; + +void fn1( boost::fibers::mutex & m, boost::fibers::condition_variable_any & cv) { + m.lock(); + BOOST_CHECK(test2 == 0); + test1 = 1; + cv.notify_one(); + while (test2 == 0) { + cv.wait(m); + } + BOOST_CHECK(test2 != 0); + m.unlock(); +} + +void fn2( boost::fibers::mutex & m, boost::fibers::condition_variable_any & cv) { + m.lock(); + BOOST_CHECK(test2 == 0); + test1 = 1; + cv.notify_one(); + std::chrono::system_clock::time_point t0 = std::chrono::system_clock::now(); + std::chrono::system_clock::time_point t = t0 + ms(250); + int count=0; + while (test2 == 0 && cv.wait_until(m, t) == boost::fibers::cv_status::no_timeout) + count++; + std::chrono::system_clock::time_point t1 = std::chrono::system_clock::now(); + if (runs == 0) { + BOOST_CHECK(t1 - t0 < ms(250)); + BOOST_CHECK(test2 != 0); + } else { + BOOST_CHECK(t1 - t0 - ms(250) < ms(count*250+100+1000)); + BOOST_CHECK(test2 == 0); + } + ++runs; + m.unlock(); +} + +class Pred { + int & i_; + +public: + explicit Pred(int& i) : + i_(i) + {} + + bool operator()() + { return i_ != 0; } +}; + +void fn3( boost::fibers::mutex & m, boost::fibers::condition_variable_any & cv) { + m.lock(); + BOOST_CHECK(test2 == 0); + test1 = 1; + cv.notify_one(); + std::chrono::steady_clock::time_point t0 = std::chrono::steady_clock::now(); + std::chrono::steady_clock::time_point t = t0 + ms(250); + bool r = cv.wait_until(m, t, Pred(test2)); + std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now(); + if (runs == 0) { + BOOST_CHECK(t1 - t0 < ms(250)); + BOOST_CHECK(test2 != 0); + BOOST_CHECK(r); + } else { + BOOST_CHECK(t1 - t0 - ms(250) < ms(250+100)); + BOOST_CHECK(test2 == 0); + BOOST_CHECK(!r); + } + ++runs; + m.unlock(); +} + +void fn4( boost::fibers::mutex & m, boost::fibers::condition_variable_any & cv) { + m.lock(); + BOOST_CHECK(test2 == 0); + test1 = 1; + cv.notify_one(); + std::chrono::steady_clock::time_point t0 = std::chrono::steady_clock::now(); + int count=0; + while (test2 == 0 && cv.wait_for(m, ms(250)) == boost::fibers::cv_status::no_timeout) + count++; + std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now(); + if (runs == 0) { + BOOST_CHECK(t1 - t0 < ms(250)); + BOOST_CHECK(test2 != 0); + } else { + BOOST_CHECK(t1 - t0 - ms(250) < ms(count*250+100+1000)); + BOOST_CHECK(test2 == 0); + } + ++runs; + m.unlock(); +} + +void fn5( boost::fibers::mutex & m, boost::fibers::condition_variable_any & cv) { + m.lock(); + BOOST_CHECK(test2 == 0); + test1 = 1; + cv.notify_one(); + std::chrono::steady_clock::time_point t0 = std::chrono::steady_clock::now(); + int count=0; + cv.wait_for(m, ms(250), Pred(test2)); + count++; + std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now(); + if (runs == 0) { + BOOST_CHECK(t1 - t0 < ms(250+1000)); + BOOST_CHECK(test2 != 0); + } else { + BOOST_CHECK(t1 - t0 - ms(250) < ms(count*250+100)); + BOOST_CHECK(test2 == 0); + } + ++runs; + m.unlock(); +} + +void do_test_condition_wait() { + test1 = 0; + test2 = 0; + runs = 0; + + boost::fibers::mutex m; + boost::fibers::condition_variable_any cv; + m.lock(); + boost::fibers::fiber f( boost::fibers::launch::dispatch, & fn1, std::ref( m), std::ref( cv) ); + BOOST_CHECK(test1 == 0); + while (test1 == 0) + cv.wait(m); + BOOST_CHECK(test1 != 0); + test2 = 1; + m.unlock(); + cv.notify_one(); + f.join(); +} + +void test_condition_wait() { + boost::fibers::fiber( boost::fibers::launch::dispatch, & do_test_condition_wait).join(); + do_test_condition_wait(); +} + +void do_test_condition_wait_until() { + test1 = 0; + test2 = 0; + runs = 0; + + boost::fibers::mutex m; + boost::fibers::condition_variable_any cv; + { + m.lock(); + boost::fibers::fiber f( boost::fibers::launch::dispatch, & fn2, std::ref( m), std::ref( cv) ); + BOOST_CHECK(test1 == 0); + while (test1 == 0) + cv.wait(m); + BOOST_CHECK(test1 != 0); + test2 = 1; + m.unlock(); + cv.notify_one(); + f.join(); + } + test1 = 0; + test2 = 0; + { + m.lock(); + boost::fibers::fiber f( boost::fibers::launch::dispatch, & fn2, std::ref( m), std::ref( cv) ); + BOOST_CHECK(test1 == 0); + while (test1 == 0) + cv.wait(m); + BOOST_CHECK(test1 != 0); + m.unlock(); + f.join(); + } +} + +void test_condition_wait_until() { + boost::fibers::fiber( boost::fibers::launch::dispatch, & do_test_condition_wait_until).join(); + do_test_condition_wait_until(); +} + +void do_test_condition_wait_until_pred() { + test1 = 0; + test2 = 0; + runs = 0; + + boost::fibers::mutex m; + boost::fibers::condition_variable_any cv; + { + m.lock(); + boost::fibers::fiber f( boost::fibers::launch::dispatch, & fn3, std::ref( m), std::ref( cv) ); + BOOST_CHECK(test1 == 0); + while (test1 == 0) + cv.wait(m); + BOOST_CHECK(test1 != 0); + test2 = 1; + m.unlock(); + cv.notify_one(); + f.join(); + } + test1 = 0; + test2 = 0; + { + m.lock(); + boost::fibers::fiber f( boost::fibers::launch::dispatch, & fn3, std::ref( m), std::ref( cv) ); + BOOST_CHECK(test1 == 0); + while (test1 == 0) + cv.wait(m); + BOOST_CHECK(test1 != 0); + m.unlock(); + f.join(); + } +} + +void test_condition_wait_until_pred() { + boost::fibers::fiber( boost::fibers::launch::dispatch, & do_test_condition_wait_until_pred).join(); + do_test_condition_wait_until_pred(); +} + +void do_test_condition_wait_for() { + test1 = 0; + test2 = 0; + runs = 0; + + boost::fibers::mutex m; + boost::fibers::condition_variable_any cv; + { + m.lock(); + boost::fibers::fiber f( boost::fibers::launch::dispatch, & fn4, std::ref( m), std::ref( cv) ); + BOOST_CHECK(test1 == 0); + while (test1 == 0) + cv.wait(m); + BOOST_CHECK(test1 != 0); + test2 = 1; + m.unlock(); + cv.notify_one(); + f.join(); + } + test1 = 0; + test2 = 0; + { + m.lock(); + boost::fibers::fiber f( boost::fibers::launch::dispatch, & fn4, std::ref( m), std::ref( cv) ); + BOOST_CHECK(test1 == 0); + while (test1 == 0) + cv.wait(m); + BOOST_CHECK(test1 != 0); + m.unlock(); + f.join(); + } +} + +void test_condition_wait_for() { + boost::fibers::fiber( boost::fibers::launch::dispatch, & do_test_condition_wait_for).join(); + do_test_condition_wait_for(); +} + +void do_test_condition_wait_for_pred() { + test1 = 0; + test2 = 0; + runs = 0; + + boost::fibers::mutex m; + boost::fibers::condition_variable_any cv; + { + m.lock(); + boost::fibers::fiber f( boost::fibers::launch::dispatch, & fn5, std::ref( m), std::ref( cv) ); + BOOST_CHECK(test1 == 0); + while (test1 == 0) + cv.wait(m); + BOOST_CHECK(test1 != 0); + test2 = 1; + m.unlock(); + cv.notify_one(); + f.join(); + } + test1 = 0; + test2 = 0; + { + m.lock(); + boost::fibers::fiber f( boost::fibers::launch::dispatch, & fn5, std::ref( m), std::ref( cv) ); + BOOST_CHECK(test1 == 0); + while (test1 == 0) + cv.wait(m); + BOOST_CHECK(test1 != 0); + m.unlock(); + f.join(); + } +} + +void test_condition_wait_for_pred() { + boost::fibers::fiber( boost::fibers::launch::dispatch, & do_test_condition_wait_for_pred).join(); + do_test_condition_wait_for_pred(); +} + +boost::unit_test::test_suite * init_unit_test_suite( int, char* []) { + boost::unit_test::test_suite * test = + BOOST_TEST_SUITE("Boost.Fiber: condition_variable_any test suite"); + + test->add( BOOST_TEST_CASE( & test_one_waiter_notify_one) ); + test->add( BOOST_TEST_CASE( & test_two_waiter_notify_one) ); + test->add( BOOST_TEST_CASE( & test_two_waiter_notify_all) ); + test->add( BOOST_TEST_CASE( & test_condition_wait) ); + test->add( BOOST_TEST_CASE( & test_condition_wait_until) ); + test->add( BOOST_TEST_CASE( & test_condition_wait_until_pred) ); + test->add( BOOST_TEST_CASE( & test_condition_wait_for) ); + test->add( BOOST_TEST_CASE( & test_condition_wait_for_pred) ); + + return test; +} diff --git a/src/boost/libs/fiber/test/test_condition_variable_any_post.cpp b/src/boost/libs/fiber/test/test_condition_variable_any_post.cpp new file mode 100644 index 00000000..da6d882a --- /dev/null +++ b/src/boost/libs/fiber/test/test_condition_variable_any_post.cpp @@ -0,0 +1,501 @@ + +// Copyright Oliver Kowalke 2013. +// 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) +// +// This test is based on the tests of Boost.Thread + +#include <chrono> +#include <cstdlib> +#include <cstdio> +#include <iostream> +#include <map> +#include <stdexcept> +#include <vector> + +#include <boost/test/unit_test.hpp> + +#include <boost/fiber/all.hpp> + +typedef std::chrono::nanoseconds ns; +typedef std::chrono::milliseconds ms; + +int value1 = 0; + +inline +std::chrono::system_clock::time_point delay(int secs, int msecs=0, int /*nsecs*/=0) { + std::chrono::system_clock::time_point t = std::chrono::system_clock::now(); + t += std::chrono::seconds( secs); + t += std::chrono::milliseconds( msecs); + //t += std::chrono::nanoseconds( nsecs); + + return t; +} + +struct condition_test_data { + condition_test_data() : notified(0), awoken(0) { } + + boost::fibers::mutex mutex; + boost::fibers::condition_variable_any cond; + int notified; + int awoken; +}; + +void condition_test_fiber(condition_test_data* data) { + try { + data->mutex.lock(); + while (!(data->notified > 0)) + data->cond.wait(data->mutex); + data->awoken++; + } catch ( ... ) { + } + data->mutex.unlock(); +} + +struct cond_predicate { + cond_predicate(int& var, int val) : _var(var), _val(val) { } + + bool operator()() { return _var == _val; } + + int& _var; + int _val; +private: + void operator=(cond_predicate&); + +}; + +void notify_one_fn( boost::fibers::condition_variable_any & cond) { + cond.notify_one(); +} + +void notify_all_fn( boost::fibers::condition_variable_any & cond) { + cond.notify_all(); +} + +void wait_fn( + boost::fibers::mutex & mtx, + boost::fibers::condition_variable_any & cond) { + mtx.lock(); + cond.wait( mtx); + ++value1; + mtx.unlock(); +} + +void test_one_waiter_notify_one() { + value1 = 0; + boost::fibers::mutex mtx; + boost::fibers::condition_variable_any cond; + + boost::fibers::fiber f1( + boost::fibers::launch::post, + wait_fn, + std::ref( mtx), + std::ref( cond) ); + BOOST_CHECK_EQUAL( 0, value1); + + boost::fibers::fiber f2( + boost::fibers::launch::post, + notify_one_fn, + std::ref( cond) ); + + BOOST_CHECK_EQUAL( 0, value1); + + f1.join(); + f2.join(); + + BOOST_CHECK_EQUAL( 1, value1); +} + +void test_two_waiter_notify_one() { + value1 = 0; + boost::fibers::mutex mtx; + boost::fibers::condition_variable_any cond; + + boost::fibers::fiber f1( + boost::fibers::launch::post, + wait_fn, + std::ref( mtx), + std::ref( cond) ); + BOOST_CHECK_EQUAL( 0, value1); + + boost::fibers::fiber f2( + boost::fibers::launch::post, + wait_fn, + std::ref( mtx), + std::ref( cond) ); + BOOST_CHECK_EQUAL( 0, value1); + + boost::fibers::fiber f3( + boost::fibers::launch::post, + notify_one_fn, + std::ref( cond) ); + BOOST_CHECK_EQUAL( 0, value1); + + boost::fibers::fiber f4( + boost::fibers::launch::post, + notify_one_fn, + std::ref( cond) ); + BOOST_CHECK_EQUAL( 0, value1); + + f1.join(); + f2.join(); + f3.join(); + f4.join(); + + BOOST_CHECK_EQUAL( 2, value1); +} + +void test_two_waiter_notify_all() { + value1 = 0; + boost::fibers::mutex mtx; + boost::fibers::condition_variable_any cond; + + boost::fibers::fiber f1( + boost::fibers::launch::post, + wait_fn, + std::ref( mtx), + std::ref( cond) ); + BOOST_CHECK_EQUAL( 0, value1); + + boost::fibers::fiber f2( + boost::fibers::launch::post, + wait_fn, + std::ref( mtx), + std::ref( cond) ); + BOOST_CHECK_EQUAL( 0, value1); + + boost::fibers::fiber f3( + boost::fibers::launch::post, + notify_all_fn, + std::ref( cond) ); + BOOST_CHECK_EQUAL( 0, value1); + + boost::fibers::fiber f4( + boost::fibers::launch::post, + wait_fn, + std::ref( mtx), + std::ref( cond) ); + BOOST_CHECK_EQUAL( 0, value1); + + boost::fibers::fiber f5( + boost::fibers::launch::post, + notify_all_fn, + std::ref( cond) ); + BOOST_CHECK_EQUAL( 0, value1); + + f1.join(); + f2.join(); + f3.join(); + f4.join(); + f5.join(); + + BOOST_CHECK_EQUAL( 3, value1); +} + +int test1 = 0; +int test2 = 0; + +int runs = 0; + +void fn1( boost::fibers::mutex & m, boost::fibers::condition_variable_any & cv) { + m.lock(); + BOOST_CHECK(test2 == 0); + test1 = 1; + cv.notify_one(); + while (test2 == 0) { + cv.wait(m); + } + BOOST_CHECK(test2 != 0); + m.unlock(); +} + +void fn2( boost::fibers::mutex & m, boost::fibers::condition_variable_any & cv) { + m.lock(); + BOOST_CHECK(test2 == 0); + test1 = 1; + cv.notify_one(); + std::chrono::system_clock::time_point t0 = std::chrono::system_clock::now(); + std::chrono::system_clock::time_point t = t0 + ms(250); + int count=0; + while (test2 == 0 && cv.wait_until(m, t) == boost::fibers::cv_status::no_timeout) + count++; + std::chrono::system_clock::time_point t1 = std::chrono::system_clock::now(); + if (runs == 0) { + BOOST_CHECK(t1 - t0 < ms(250)); + BOOST_CHECK(test2 != 0); + } else { + BOOST_CHECK(t1 - t0 - ms(250) < ms(count*250+100+1000)); + BOOST_CHECK(test2 == 0); + } + ++runs; + m.unlock(); +} + +class Pred { + int & i_; + +public: + explicit Pred(int& i) : + i_(i) + {} + + bool operator()() + { return i_ != 0; } +}; + +void fn3( boost::fibers::mutex & m, boost::fibers::condition_variable_any & cv) { + m.lock(); + BOOST_CHECK(test2 == 0); + test1 = 1; + cv.notify_one(); + std::chrono::steady_clock::time_point t0 = std::chrono::steady_clock::now(); + std::chrono::steady_clock::time_point t = t0 + ms(250); + bool r = cv.wait_until(m, t, Pred(test2)); + std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now(); + if (runs == 0) { + BOOST_CHECK(t1 - t0 < ms(250)); + BOOST_CHECK(test2 != 0); + BOOST_CHECK(r); + } else { + BOOST_CHECK(t1 - t0 - ms(250) < ms(250+100)); + BOOST_CHECK(test2 == 0); + BOOST_CHECK(!r); + } + ++runs; + m.unlock(); +} + +void fn4( boost::fibers::mutex & m, boost::fibers::condition_variable_any & cv) { + m.lock(); + BOOST_CHECK(test2 == 0); + test1 = 1; + cv.notify_one(); + std::chrono::steady_clock::time_point t0 = std::chrono::steady_clock::now(); + int count=0; + while (test2 == 0 && cv.wait_for(m, ms(250)) == boost::fibers::cv_status::no_timeout) + count++; + std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now(); + if (runs == 0) { + BOOST_CHECK(t1 - t0 < ms(250)); + BOOST_CHECK(test2 != 0); + } else { + BOOST_CHECK(t1 - t0 - ms(250) < ms(count*250+100+1000)); + BOOST_CHECK(test2 == 0); + } + ++runs; + m.unlock(); +} + +void fn5( boost::fibers::mutex & m, boost::fibers::condition_variable_any & cv) { + m.lock(); + BOOST_CHECK(test2 == 0); + test1 = 1; + cv.notify_one(); + std::chrono::steady_clock::time_point t0 = std::chrono::steady_clock::now(); + int count=0; + cv.wait_for(m, ms(250), Pred(test2)); + count++; + std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now(); + if (runs == 0) { + BOOST_CHECK(t1 - t0 < ms(250+1000)); + BOOST_CHECK(test2 != 0); + } else { + BOOST_CHECK(t1 - t0 - ms(250) < ms(count*250+100)); + BOOST_CHECK(test2 == 0); + } + ++runs; + m.unlock(); +} + +void do_test_condition_wait() { + test1 = 0; + test2 = 0; + runs = 0; + + boost::fibers::mutex m; + boost::fibers::condition_variable_any cv; + m.lock(); + boost::fibers::fiber f( boost::fibers::launch::post, & fn1, std::ref( m), std::ref( cv) ); + BOOST_CHECK(test1 == 0); + while (test1 == 0) + cv.wait(m); + BOOST_CHECK(test1 != 0); + test2 = 1; + m.unlock(); + cv.notify_one(); + f.join(); +} + +void test_condition_wait() { + boost::fibers::fiber( boost::fibers::launch::post, & do_test_condition_wait).join(); + do_test_condition_wait(); +} + +void do_test_condition_wait_until() { + test1 = 0; + test2 = 0; + runs = 0; + + boost::fibers::mutex m; + boost::fibers::condition_variable_any cv; + { + m.lock(); + boost::fibers::fiber f( boost::fibers::launch::post, & fn2, std::ref( m), std::ref( cv) ); + BOOST_CHECK(test1 == 0); + while (test1 == 0) + cv.wait(m); + BOOST_CHECK(test1 != 0); + test2 = 1; + m.unlock(); + cv.notify_one(); + f.join(); + } + test1 = 0; + test2 = 0; + { + m.lock(); + boost::fibers::fiber f( boost::fibers::launch::post, & fn2, std::ref( m), std::ref( cv) ); + BOOST_CHECK(test1 == 0); + while (test1 == 0) + cv.wait(m); + BOOST_CHECK(test1 != 0); + m.unlock(); + f.join(); + } +} + +void test_condition_wait_until() { + boost::fibers::fiber( boost::fibers::launch::post, & do_test_condition_wait_until).join(); + do_test_condition_wait_until(); +} + +void do_test_condition_wait_until_pred() { + test1 = 0; + test2 = 0; + runs = 0; + + boost::fibers::mutex m; + boost::fibers::condition_variable_any cv; + { + m.lock(); + boost::fibers::fiber f( boost::fibers::launch::post, & fn3, std::ref( m), std::ref( cv) ); + BOOST_CHECK(test1 == 0); + while (test1 == 0) + cv.wait(m); + BOOST_CHECK(test1 != 0); + test2 = 1; + m.unlock(); + cv.notify_one(); + f.join(); + } + test1 = 0; + test2 = 0; + { + m.lock(); + boost::fibers::fiber f( boost::fibers::launch::post, & fn3, std::ref( m), std::ref( cv) ); + BOOST_CHECK(test1 == 0); + while (test1 == 0) + cv.wait(m); + BOOST_CHECK(test1 != 0); + m.unlock(); + f.join(); + } +} + +void test_condition_wait_until_pred() { + boost::fibers::fiber( boost::fibers::launch::post, & do_test_condition_wait_until_pred).join(); + do_test_condition_wait_until_pred(); +} + +void do_test_condition_wait_for() { + test1 = 0; + test2 = 0; + runs = 0; + + boost::fibers::mutex m; + boost::fibers::condition_variable_any cv; + { + m.lock(); + boost::fibers::fiber f( boost::fibers::launch::post, & fn4, std::ref( m), std::ref( cv) ); + BOOST_CHECK(test1 == 0); + while (test1 == 0) + cv.wait(m); + BOOST_CHECK(test1 != 0); + test2 = 1; + m.unlock(); + cv.notify_one(); + f.join(); + } + test1 = 0; + test2 = 0; + { + m.lock(); + boost::fibers::fiber f( boost::fibers::launch::post, & fn4, std::ref( m), std::ref( cv) ); + BOOST_CHECK(test1 == 0); + while (test1 == 0) + cv.wait(m); + BOOST_CHECK(test1 != 0); + m.unlock(); + f.join(); + } +} + +void test_condition_wait_for() { + boost::fibers::fiber( boost::fibers::launch::post, & do_test_condition_wait_for).join(); + do_test_condition_wait_for(); +} + +void do_test_condition_wait_for_pred() { + test1 = 0; + test2 = 0; + runs = 0; + + boost::fibers::mutex m; + boost::fibers::condition_variable_any cv; + { + m.lock(); + boost::fibers::fiber f( boost::fibers::launch::post, & fn5, std::ref( m), std::ref( cv) ); + BOOST_CHECK(test1 == 0); + while (test1 == 0) + cv.wait(m); + BOOST_CHECK(test1 != 0); + test2 = 1; + m.unlock(); + cv.notify_one(); + f.join(); + } + test1 = 0; + test2 = 0; + { + m.lock(); + boost::fibers::fiber f( boost::fibers::launch::post, & fn5, std::ref( m), std::ref( cv) ); + BOOST_CHECK(test1 == 0); + while (test1 == 0) + cv.wait(m); + BOOST_CHECK(test1 != 0); + m.unlock(); + f.join(); + } +} + +void test_condition_wait_for_pred() { + boost::fibers::fiber( boost::fibers::launch::post, & do_test_condition_wait_for_pred).join(); + do_test_condition_wait_for_pred(); +} + +boost::unit_test::test_suite * init_unit_test_suite( int, char* []) { + boost::unit_test::test_suite * test = + BOOST_TEST_SUITE("Boost.Fiber: condition_variable_any test suite"); + + test->add( BOOST_TEST_CASE( & test_one_waiter_notify_one) ); + test->add( BOOST_TEST_CASE( & test_two_waiter_notify_one) ); + test->add( BOOST_TEST_CASE( & test_two_waiter_notify_all) ); + test->add( BOOST_TEST_CASE( & test_condition_wait) ); + test->add( BOOST_TEST_CASE( & test_condition_wait_until) ); + test->add( BOOST_TEST_CASE( & test_condition_wait_until_pred) ); + test->add( BOOST_TEST_CASE( & test_condition_wait_for) ); + test->add( BOOST_TEST_CASE( & test_condition_wait_for_pred) ); + + return test; +} diff --git a/src/boost/libs/fiber/test/test_condition_variable_dispatch.cpp b/src/boost/libs/fiber/test/test_condition_variable_dispatch.cpp new file mode 100644 index 00000000..dc5e00fe --- /dev/null +++ b/src/boost/libs/fiber/test/test_condition_variable_dispatch.cpp @@ -0,0 +1,495 @@ + +// Copyright Oliver Kowalke 2013. +// 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) +// +// This test is based on the tests of Boost.Thread + +#include <chrono> +#include <cstdio> +#include <cstdlib> +#include <iostream> +#include <map> +#include <mutex> +#include <stdexcept> +#include <vector> + +#include <boost/test/unit_test.hpp> + +#include <boost/fiber/all.hpp> + +typedef std::chrono::nanoseconds ns; +typedef std::chrono::milliseconds ms; + +int value1 = 0; + +inline +std::chrono::system_clock::time_point delay(int secs, int msecs = 0, int /*nsecs*/ = 0) { + std::chrono::system_clock::time_point t = std::chrono::system_clock::now(); + t += std::chrono::seconds( secs); + t += std::chrono::milliseconds( msecs); + //t += std::chrono::nanoseconds( nsecs); + + return t; +} + +struct condition_test_data { + condition_test_data() : notified(0), awoken(0) { } + + boost::fibers::mutex mutex; + boost::fibers::condition_variable cond; + int notified; + int awoken; +}; + +void condition_test_fiber(condition_test_data* data) { + std::unique_lock<boost::fibers::mutex> lock(data->mutex); + BOOST_CHECK(lock ? true : false); + while (!(data->notified > 0)) + data->cond.wait(lock); + BOOST_CHECK(lock ? true : false); + data->awoken++; +} + +struct cond_predicate { + cond_predicate(int& var, int val) : _var(var), _val(val) { } + + bool operator()() { return _var == _val; } + + int& _var; + int _val; +private: + void operator=(cond_predicate&); + +}; + +void notify_one_fn( boost::fibers::condition_variable & cond) { + cond.notify_one(); +} + +void notify_all_fn( boost::fibers::condition_variable & cond) { + cond.notify_all(); +} + +void wait_fn( + boost::fibers::mutex & mtx, + boost::fibers::condition_variable & cond) { + std::unique_lock< boost::fibers::mutex > lk( mtx); + cond.wait( lk); + ++value1; +} + +void test_one_waiter_notify_one() { + value1 = 0; + boost::fibers::mutex mtx; + boost::fibers::condition_variable cond; + + boost::fibers::fiber f1( + boost::fibers::launch::dispatch, + wait_fn, + std::ref( mtx), + std::ref( cond) ); + BOOST_CHECK_EQUAL( 0, value1); + + boost::fibers::fiber f2( + boost::fibers::launch::dispatch, + notify_one_fn, + std::ref( cond) ); + + BOOST_CHECK_EQUAL( 0, value1); + + f1.join(); + f2.join(); + + BOOST_CHECK_EQUAL( 1, value1); +} + +void test_two_waiter_notify_one() { + value1 = 0; + boost::fibers::mutex mtx; + boost::fibers::condition_variable cond; + + boost::fibers::fiber f1( + boost::fibers::launch::dispatch, + wait_fn, + std::ref( mtx), + std::ref( cond) ); + BOOST_CHECK_EQUAL( 0, value1); + + boost::fibers::fiber f2( + boost::fibers::launch::dispatch, + wait_fn, + std::ref( mtx), + std::ref( cond) ); + BOOST_CHECK_EQUAL( 0, value1); + + boost::fibers::fiber f3( + boost::fibers::launch::dispatch, + notify_one_fn, + std::ref( cond) ); + BOOST_CHECK_EQUAL( 0, value1); + + boost::fibers::fiber f4( + boost::fibers::launch::dispatch, + notify_one_fn, + std::ref( cond) ); + BOOST_CHECK_EQUAL( 1, value1); + + f1.join(); + f2.join(); + f3.join(); + f4.join(); + + BOOST_CHECK_EQUAL( 2, value1); +} + +void test_two_waiter_notify_all() { + value1 = 0; + boost::fibers::mutex mtx; + boost::fibers::condition_variable cond; + + boost::fibers::fiber f1( + boost::fibers::launch::dispatch, + wait_fn, + std::ref( mtx), + std::ref( cond) ); + BOOST_CHECK_EQUAL( 0, value1); + + boost::fibers::fiber f2( + boost::fibers::launch::dispatch, + wait_fn, + std::ref( mtx), + std::ref( cond) ); + BOOST_CHECK_EQUAL( 0, value1); + + boost::fibers::fiber f3( + boost::fibers::launch::dispatch, + notify_all_fn, + std::ref( cond) ); + BOOST_CHECK_EQUAL( 0, value1); + + boost::fibers::fiber f4( + boost::fibers::launch::dispatch, + wait_fn, + std::ref( mtx), + std::ref( cond) ); + BOOST_CHECK_EQUAL( 2, value1); + + boost::fibers::fiber f5( + boost::fibers::launch::dispatch, + notify_all_fn, + std::ref( cond) ); + BOOST_CHECK_EQUAL( 2, value1); + + f1.join(); + f2.join(); + f3.join(); + f4.join(); + f5.join(); + + BOOST_CHECK_EQUAL( 3, value1); +} + +int test1 = 0; +int test2 = 0; + +int runs = 0; + +void fn1( boost::fibers::mutex & m, boost::fibers::condition_variable & cv) { + std::unique_lock< boost::fibers::mutex > lk( m); + BOOST_CHECK(test2 == 0); + test1 = 1; + cv.notify_one(); + while (test2 == 0) { + cv.wait(lk); + } + BOOST_CHECK(test2 != 0); +} + +void fn2( boost::fibers::mutex & m, boost::fibers::condition_variable & cv) { + std::unique_lock< boost::fibers::mutex > lk( m); + BOOST_CHECK(test2 == 0); + test1 = 1; + cv.notify_one(); + std::chrono::system_clock::time_point t0 = std::chrono::system_clock::now(); + std::chrono::system_clock::time_point t = t0 + ms(250); + int count=0; + while (test2 == 0 && cv.wait_until(lk, t) == boost::fibers::cv_status::no_timeout) + count++; + std::chrono::system_clock::time_point t1 = std::chrono::system_clock::now(); + if (runs == 0) { + BOOST_CHECK(t1 - t0 < ms(250)); + BOOST_CHECK(test2 != 0); + } else { + BOOST_CHECK(t1 - t0 - ms(250) < ms(count*250+100+1000)); + BOOST_CHECK(test2 == 0); + } + ++runs; +} + +class Pred { + int & i_; + +public: + explicit Pred(int& i) : + i_(i) + {} + + bool operator()() + { return i_ != 0; } +}; + +void fn3( boost::fibers::mutex & m, boost::fibers::condition_variable & cv) { + std::unique_lock< boost::fibers::mutex > lk( m); + BOOST_CHECK(test2 == 0); + test1 = 1; + cv.notify_one(); + std::chrono::steady_clock::time_point t0 = std::chrono::steady_clock::now(); + std::chrono::steady_clock::time_point t = t0 + ms(250); + bool r = cv.wait_until(lk, t, Pred(test2)); + std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now(); + if (runs == 0) { + BOOST_CHECK(t1 - t0 < ms(250)); + BOOST_CHECK(test2 != 0); + BOOST_CHECK(r); + } else { + BOOST_CHECK(t1 - t0 - ms(250) < ms(250+100)); + BOOST_CHECK(test2 == 0); + BOOST_CHECK(!r); + } + ++runs; +} + +void fn4( boost::fibers::mutex & m, boost::fibers::condition_variable & cv) { + std::unique_lock< boost::fibers::mutex > lk( m); + BOOST_CHECK(test2 == 0); + test1 = 1; + cv.notify_one(); + std::chrono::steady_clock::time_point t0 = std::chrono::steady_clock::now(); + int count=0; + while (test2 == 0 && cv.wait_for(lk, ms(250)) == boost::fibers::cv_status::no_timeout) + count++; + std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now(); + if (runs == 0) { + BOOST_CHECK(t1 - t0 < ms(250)); + BOOST_CHECK(test2 != 0); + } else { + BOOST_CHECK(t1 - t0 - ms(250) < ms(count*250+100+1000)); + BOOST_CHECK(test2 == 0); + } + ++runs; +} + +void fn5( boost::fibers::mutex & m, boost::fibers::condition_variable & cv) { + std::unique_lock< boost::fibers::mutex > lk( m); + BOOST_CHECK(test2 == 0); + test1 = 1; + cv.notify_one(); + std::chrono::steady_clock::time_point t0 = std::chrono::steady_clock::now(); + int count=0; + cv.wait_for(lk, ms(250), Pred(test2)); + count++; + std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now(); + if (runs == 0) { + BOOST_CHECK(t1 - t0 < ms(250+1000)); + BOOST_CHECK(test2 != 0); + } else { + BOOST_CHECK(t1 - t0 - ms(250) < ms(count*250+100)); + BOOST_CHECK(test2 == 0); + } + ++runs; +} + +void do_test_condition_wait() { + test1 = 0; + test2 = 0; + runs = 0; + + boost::fibers::mutex m; + boost::fibers::condition_variable cv; + std::unique_lock< boost::fibers::mutex > lk( m); + boost::fibers::fiber f( boost::fibers::launch::dispatch, & fn1, std::ref( m), std::ref( cv) ); + BOOST_CHECK(test1 == 0); + while (test1 == 0) + cv.wait(lk); + BOOST_CHECK(test1 != 0); + test2 = 1; + lk.unlock(); + cv.notify_one(); + f.join(); +} + +void test_condition_wait() { + boost::fibers::fiber( boost::fibers::launch::dispatch, & do_test_condition_wait).join(); + do_test_condition_wait(); +} + +void do_test_condition_wait_until() { + test1 = 0; + test2 = 0; + runs = 0; + + boost::fibers::mutex m; + boost::fibers::condition_variable cv; + { + std::unique_lock< boost::fibers::mutex > lk( m); + boost::fibers::fiber f( boost::fibers::launch::dispatch, & fn2, std::ref( m), std::ref( cv) ); + BOOST_CHECK(test1 == 0); + while (test1 == 0) + cv.wait(lk); + BOOST_CHECK(test1 != 0); + test2 = 1; + lk.unlock(); + cv.notify_one(); + f.join(); + } + test1 = 0; + test2 = 0; + { + std::unique_lock< boost::fibers::mutex > lk( m); + boost::fibers::fiber f( boost::fibers::launch::dispatch, & fn2, std::ref( m), std::ref( cv) ); + BOOST_CHECK(test1 == 0); + while (test1 == 0) + cv.wait(lk); + BOOST_CHECK(test1 != 0); + lk.unlock(); + f.join(); + } +} + +void test_condition_wait_until() { + boost::fibers::fiber( boost::fibers::launch::dispatch, & do_test_condition_wait_until).join(); + do_test_condition_wait_until(); +} + +void do_test_condition_wait_until_pred() { + test1 = 0; + test2 = 0; + runs = 0; + + boost::fibers::mutex m; + boost::fibers::condition_variable cv; + { + std::unique_lock< boost::fibers::mutex > lk( m); + boost::fibers::fiber f( boost::fibers::launch::dispatch, & fn3, std::ref( m), std::ref( cv) ); + BOOST_CHECK(test1 == 0); + while (test1 == 0) + cv.wait(lk); + BOOST_CHECK(test1 != 0); + test2 = 1; + lk.unlock(); + cv.notify_one(); + f.join(); + } + test1 = 0; + test2 = 0; + { + std::unique_lock< boost::fibers::mutex > lk( m); + boost::fibers::fiber f( boost::fibers::launch::dispatch, & fn3, std::ref( m), std::ref( cv) ); + BOOST_CHECK(test1 == 0); + while (test1 == 0) + cv.wait(lk); + BOOST_CHECK(test1 != 0); + lk.unlock(); + f.join(); + } +} + +void test_condition_wait_until_pred() { + boost::fibers::fiber( boost::fibers::launch::dispatch, & do_test_condition_wait_until_pred).join(); + do_test_condition_wait_until_pred(); +} + +void do_test_condition_wait_for() { + test1 = 0; + test2 = 0; + runs = 0; + + boost::fibers::mutex m; + boost::fibers::condition_variable cv; + { + std::unique_lock< boost::fibers::mutex > lk( m); + boost::fibers::fiber f( boost::fibers::launch::dispatch, & fn4, std::ref( m), std::ref( cv) ); + BOOST_CHECK(test1 == 0); + while (test1 == 0) + cv.wait(lk); + BOOST_CHECK(test1 != 0); + test2 = 1; + lk.unlock(); + cv.notify_one(); + f.join(); + } + test1 = 0; + test2 = 0; + { + std::unique_lock< boost::fibers::mutex > lk( m); + boost::fibers::fiber f( boost::fibers::launch::dispatch, & fn4, std::ref( m), std::ref( cv) ); + BOOST_CHECK(test1 == 0); + while (test1 == 0) + cv.wait(lk); + BOOST_CHECK(test1 != 0); + lk.unlock(); + f.join(); + } +} + +void test_condition_wait_for() { + boost::fibers::fiber( boost::fibers::launch::dispatch, & do_test_condition_wait_for).join(); + do_test_condition_wait_for(); +} + +void do_test_condition_wait_for_pred() { + test1 = 0; + test2 = 0; + runs = 0; + + boost::fibers::mutex m; + boost::fibers::condition_variable cv; + { + std::unique_lock< boost::fibers::mutex > lk( m); + boost::fibers::fiber f( boost::fibers::launch::dispatch, & fn5, std::ref( m), std::ref( cv) ); + BOOST_CHECK(test1 == 0); + while (test1 == 0) + cv.wait(lk); + BOOST_CHECK(test1 != 0); + test2 = 1; + lk.unlock(); + cv.notify_one(); + f.join(); + } + test1 = 0; + test2 = 0; + { + std::unique_lock< boost::fibers::mutex > lk( m); + boost::fibers::fiber f( boost::fibers::launch::dispatch, & fn5, std::ref( m), std::ref( cv) ); + BOOST_CHECK(test1 == 0); + while (test1 == 0) + cv.wait(lk); + BOOST_CHECK(test1 != 0); + lk.unlock(); + f.join(); + } +} + +void test_condition_wait_for_pred() { + boost::fibers::fiber( boost::fibers::launch::dispatch, & do_test_condition_wait_for_pred).join(); + do_test_condition_wait_for_pred(); +} + +boost::unit_test::test_suite * init_unit_test_suite( int, char* []) +{ + boost::unit_test::test_suite * test = + BOOST_TEST_SUITE("Boost.Fiber: condition_variable test suite"); + + test->add( BOOST_TEST_CASE( & test_one_waiter_notify_one) ); + test->add( BOOST_TEST_CASE( & test_two_waiter_notify_one) ); + test->add( BOOST_TEST_CASE( & test_two_waiter_notify_all) ); + test->add( BOOST_TEST_CASE( & test_condition_wait) ); + test->add( BOOST_TEST_CASE( & test_condition_wait_until) ); + test->add( BOOST_TEST_CASE( & test_condition_wait_until_pred) ); + test->add( BOOST_TEST_CASE( & test_condition_wait_for) ); + test->add( BOOST_TEST_CASE( & test_condition_wait_for_pred) ); + + return test; +} diff --git a/src/boost/libs/fiber/test/test_condition_variable_post.cpp b/src/boost/libs/fiber/test/test_condition_variable_post.cpp new file mode 100644 index 00000000..3f043a7b --- /dev/null +++ b/src/boost/libs/fiber/test/test_condition_variable_post.cpp @@ -0,0 +1,495 @@ + +// Copyright Oliver Kowalke 2013. +// 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) +// +// This test is based on the tests of Boost.Thread + +#include <chrono> +#include <cstdio> +#include <cstdlib> +#include <iostream> +#include <map> +#include <mutex> +#include <stdexcept> +#include <vector> + +#include <boost/test/unit_test.hpp> + +#include <boost/fiber/all.hpp> + +typedef std::chrono::nanoseconds ns; +typedef std::chrono::milliseconds ms; + +int value1 = 0; + +inline +std::chrono::system_clock::time_point delay(int secs, int msecs = 0, int /*nsecs*/ = 0) { + std::chrono::system_clock::time_point t = std::chrono::system_clock::now(); + t += std::chrono::seconds( secs); + t += std::chrono::milliseconds( msecs); + //t += std::chrono::nanoseconds( nsecs); + + return t; +} + +struct condition_test_data { + condition_test_data() : notified(0), awoken(0) { } + + boost::fibers::mutex mutex; + boost::fibers::condition_variable cond; + int notified; + int awoken; +}; + +void condition_test_fiber(condition_test_data* data) { + std::unique_lock<boost::fibers::mutex> lock(data->mutex); + BOOST_CHECK(lock ? true : false); + while (!(data->notified > 0)) + data->cond.wait(lock); + BOOST_CHECK(lock ? true : false); + data->awoken++; +} + +struct cond_predicate { + cond_predicate(int& var, int val) : _var(var), _val(val) { } + + bool operator()() { return _var == _val; } + + int& _var; + int _val; +private: + void operator=(cond_predicate&); + +}; + +void notify_one_fn( boost::fibers::condition_variable & cond) { + cond.notify_one(); +} + +void notify_all_fn( boost::fibers::condition_variable & cond) { + cond.notify_all(); +} + +void wait_fn( + boost::fibers::mutex & mtx, + boost::fibers::condition_variable & cond) { + std::unique_lock< boost::fibers::mutex > lk( mtx); + cond.wait( lk); + ++value1; +} + +void test_one_waiter_notify_one() { + value1 = 0; + boost::fibers::mutex mtx; + boost::fibers::condition_variable cond; + + boost::fibers::fiber f1( + boost::fibers::launch::post, + wait_fn, + std::ref( mtx), + std::ref( cond) ); + BOOST_CHECK_EQUAL( 0, value1); + + boost::fibers::fiber f2( + boost::fibers::launch::post, + notify_one_fn, + std::ref( cond) ); + + BOOST_CHECK_EQUAL( 0, value1); + + f1.join(); + f2.join(); + + BOOST_CHECK_EQUAL( 1, value1); +} + +void test_two_waiter_notify_one() { + value1 = 0; + boost::fibers::mutex mtx; + boost::fibers::condition_variable cond; + + boost::fibers::fiber f1( + boost::fibers::launch::post, + wait_fn, + std::ref( mtx), + std::ref( cond) ); + BOOST_CHECK_EQUAL( 0, value1); + + boost::fibers::fiber f2( + boost::fibers::launch::post, + wait_fn, + std::ref( mtx), + std::ref( cond) ); + BOOST_CHECK_EQUAL( 0, value1); + + boost::fibers::fiber f3( + boost::fibers::launch::post, + notify_one_fn, + std::ref( cond) ); + BOOST_CHECK_EQUAL( 0, value1); + + boost::fibers::fiber f4( + boost::fibers::launch::post, + notify_one_fn, + std::ref( cond) ); + BOOST_CHECK_EQUAL( 0, value1); + + f1.join(); + f2.join(); + f3.join(); + f4.join(); + + BOOST_CHECK_EQUAL( 2, value1); +} + +void test_two_waiter_notify_all() { + value1 = 0; + boost::fibers::mutex mtx; + boost::fibers::condition_variable cond; + + boost::fibers::fiber f1( + boost::fibers::launch::post, + wait_fn, + std::ref( mtx), + std::ref( cond) ); + BOOST_CHECK_EQUAL( 0, value1); + + boost::fibers::fiber f2( + boost::fibers::launch::post, + wait_fn, + std::ref( mtx), + std::ref( cond) ); + BOOST_CHECK_EQUAL( 0, value1); + + boost::fibers::fiber f3( + boost::fibers::launch::post, + notify_all_fn, + std::ref( cond) ); + BOOST_CHECK_EQUAL( 0, value1); + + boost::fibers::fiber f4( + boost::fibers::launch::post, + wait_fn, + std::ref( mtx), + std::ref( cond) ); + BOOST_CHECK_EQUAL( 0, value1); + + boost::fibers::fiber f5( + boost::fibers::launch::post, + notify_all_fn, + std::ref( cond) ); + BOOST_CHECK_EQUAL( 0, value1); + + f1.join(); + f2.join(); + f3.join(); + f4.join(); + f5.join(); + + BOOST_CHECK_EQUAL( 3, value1); +} + +int test1 = 0; +int test2 = 0; + +int runs = 0; + +void fn1( boost::fibers::mutex & m, boost::fibers::condition_variable & cv) { + std::unique_lock< boost::fibers::mutex > lk( m); + BOOST_CHECK(test2 == 0); + test1 = 1; + cv.notify_one(); + while (test2 == 0) { + cv.wait(lk); + } + BOOST_CHECK(test2 != 0); +} + +void fn2( boost::fibers::mutex & m, boost::fibers::condition_variable & cv) { + std::unique_lock< boost::fibers::mutex > lk( m); + BOOST_CHECK(test2 == 0); + test1 = 1; + cv.notify_one(); + std::chrono::system_clock::time_point t0 = std::chrono::system_clock::now(); + std::chrono::system_clock::time_point t = t0 + ms(250); + int count=0; + while (test2 == 0 && cv.wait_until(lk, t) == boost::fibers::cv_status::no_timeout) + count++; + std::chrono::system_clock::time_point t1 = std::chrono::system_clock::now(); + if (runs == 0) { + BOOST_CHECK(t1 - t0 < ms(250)); + BOOST_CHECK(test2 != 0); + } else { + BOOST_CHECK(t1 - t0 - ms(250) < ms(count*250+100+1000)); + BOOST_CHECK(test2 == 0); + } + ++runs; +} + +class Pred { + int & i_; + +public: + explicit Pred(int& i) : + i_(i) + {} + + bool operator()() + { return i_ != 0; } +}; + +void fn3( boost::fibers::mutex & m, boost::fibers::condition_variable & cv) { + std::unique_lock< boost::fibers::mutex > lk( m); + BOOST_CHECK(test2 == 0); + test1 = 1; + cv.notify_one(); + std::chrono::steady_clock::time_point t0 = std::chrono::steady_clock::now(); + std::chrono::steady_clock::time_point t = t0 + ms(250); + bool r = cv.wait_until(lk, t, Pred(test2)); + std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now(); + if (runs == 0) { + BOOST_CHECK(t1 - t0 < ms(250)); + BOOST_CHECK(test2 != 0); + BOOST_CHECK(r); + } else { + BOOST_CHECK(t1 - t0 - ms(250) < ms(250+100)); + BOOST_CHECK(test2 == 0); + BOOST_CHECK(!r); + } + ++runs; +} + +void fn4( boost::fibers::mutex & m, boost::fibers::condition_variable & cv) { + std::unique_lock< boost::fibers::mutex > lk( m); + BOOST_CHECK(test2 == 0); + test1 = 1; + cv.notify_one(); + std::chrono::steady_clock::time_point t0 = std::chrono::steady_clock::now(); + int count=0; + while (test2 == 0 && cv.wait_for(lk, ms(250)) == boost::fibers::cv_status::no_timeout) + count++; + std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now(); + if (runs == 0) { + BOOST_CHECK(t1 - t0 < ms(250)); + BOOST_CHECK(test2 != 0); + } else { + BOOST_CHECK(t1 - t0 - ms(250) < ms(count*250+100+1000)); + BOOST_CHECK(test2 == 0); + } + ++runs; +} + +void fn5( boost::fibers::mutex & m, boost::fibers::condition_variable & cv) { + std::unique_lock< boost::fibers::mutex > lk( m); + BOOST_CHECK(test2 == 0); + test1 = 1; + cv.notify_one(); + std::chrono::steady_clock::time_point t0 = std::chrono::steady_clock::now(); + int count=0; + cv.wait_for(lk, ms(250), Pred(test2)); + count++; + std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now(); + if (runs == 0) { + BOOST_CHECK(t1 - t0 < ms(250+1000)); + BOOST_CHECK(test2 != 0); + } else { + BOOST_CHECK(t1 - t0 - ms(250) < ms(count*250+100)); + BOOST_CHECK(test2 == 0); + } + ++runs; +} + +void do_test_condition_wait() { + test1 = 0; + test2 = 0; + runs = 0; + + boost::fibers::mutex m; + boost::fibers::condition_variable cv; + std::unique_lock< boost::fibers::mutex > lk( m); + boost::fibers::fiber f( boost::fibers::launch::post, & fn1, std::ref( m), std::ref( cv) ); + BOOST_CHECK(test1 == 0); + while (test1 == 0) + cv.wait(lk); + BOOST_CHECK(test1 != 0); + test2 = 1; + lk.unlock(); + cv.notify_one(); + f.join(); +} + +void test_condition_wait() { + boost::fibers::fiber( boost::fibers::launch::post, & do_test_condition_wait).join(); + do_test_condition_wait(); +} + +void do_test_condition_wait_until() { + test1 = 0; + test2 = 0; + runs = 0; + + boost::fibers::mutex m; + boost::fibers::condition_variable cv; + { + std::unique_lock< boost::fibers::mutex > lk( m); + boost::fibers::fiber f( boost::fibers::launch::post, & fn2, std::ref( m), std::ref( cv) ); + BOOST_CHECK(test1 == 0); + while (test1 == 0) + cv.wait(lk); + BOOST_CHECK(test1 != 0); + test2 = 1; + lk.unlock(); + cv.notify_one(); + f.join(); + } + test1 = 0; + test2 = 0; + { + std::unique_lock< boost::fibers::mutex > lk( m); + boost::fibers::fiber f( boost::fibers::launch::post, & fn2, std::ref( m), std::ref( cv) ); + BOOST_CHECK(test1 == 0); + while (test1 == 0) + cv.wait(lk); + BOOST_CHECK(test1 != 0); + lk.unlock(); + f.join(); + } +} + +void test_condition_wait_until() { + boost::fibers::fiber( boost::fibers::launch::post, & do_test_condition_wait_until).join(); + do_test_condition_wait_until(); +} + +void do_test_condition_wait_until_pred() { + test1 = 0; + test2 = 0; + runs = 0; + + boost::fibers::mutex m; + boost::fibers::condition_variable cv; + { + std::unique_lock< boost::fibers::mutex > lk( m); + boost::fibers::fiber f( boost::fibers::launch::post, & fn3, std::ref( m), std::ref( cv) ); + BOOST_CHECK(test1 == 0); + while (test1 == 0) + cv.wait(lk); + BOOST_CHECK(test1 != 0); + test2 = 1; + lk.unlock(); + cv.notify_one(); + f.join(); + } + test1 = 0; + test2 = 0; + { + std::unique_lock< boost::fibers::mutex > lk( m); + boost::fibers::fiber f( boost::fibers::launch::post, & fn3, std::ref( m), std::ref( cv) ); + BOOST_CHECK(test1 == 0); + while (test1 == 0) + cv.wait(lk); + BOOST_CHECK(test1 != 0); + lk.unlock(); + f.join(); + } +} + +void test_condition_wait_until_pred() { + boost::fibers::fiber( boost::fibers::launch::post, & do_test_condition_wait_until_pred).join(); + do_test_condition_wait_until_pred(); +} + +void do_test_condition_wait_for() { + test1 = 0; + test2 = 0; + runs = 0; + + boost::fibers::mutex m; + boost::fibers::condition_variable cv; + { + std::unique_lock< boost::fibers::mutex > lk( m); + boost::fibers::fiber f( boost::fibers::launch::post, & fn4, std::ref( m), std::ref( cv) ); + BOOST_CHECK(test1 == 0); + while (test1 == 0) + cv.wait(lk); + BOOST_CHECK(test1 != 0); + test2 = 1; + lk.unlock(); + cv.notify_one(); + f.join(); + } + test1 = 0; + test2 = 0; + { + std::unique_lock< boost::fibers::mutex > lk( m); + boost::fibers::fiber f( boost::fibers::launch::post, & fn4, std::ref( m), std::ref( cv) ); + BOOST_CHECK(test1 == 0); + while (test1 == 0) + cv.wait(lk); + BOOST_CHECK(test1 != 0); + lk.unlock(); + f.join(); + } +} + +void test_condition_wait_for() { + boost::fibers::fiber( boost::fibers::launch::post, & do_test_condition_wait_for).join(); + do_test_condition_wait_for(); +} + +void do_test_condition_wait_for_pred() { + test1 = 0; + test2 = 0; + runs = 0; + + boost::fibers::mutex m; + boost::fibers::condition_variable cv; + { + std::unique_lock< boost::fibers::mutex > lk( m); + boost::fibers::fiber f( boost::fibers::launch::post, & fn5, std::ref( m), std::ref( cv) ); + BOOST_CHECK(test1 == 0); + while (test1 == 0) + cv.wait(lk); + BOOST_CHECK(test1 != 0); + test2 = 1; + lk.unlock(); + cv.notify_one(); + f.join(); + } + test1 = 0; + test2 = 0; + { + std::unique_lock< boost::fibers::mutex > lk( m); + boost::fibers::fiber f( boost::fibers::launch::post, & fn5, std::ref( m), std::ref( cv) ); + BOOST_CHECK(test1 == 0); + while (test1 == 0) + cv.wait(lk); + BOOST_CHECK(test1 != 0); + lk.unlock(); + f.join(); + } +} + +void test_condition_wait_for_pred() { + boost::fibers::fiber( boost::fibers::launch::post, & do_test_condition_wait_for_pred).join(); + do_test_condition_wait_for_pred(); +} + +boost::unit_test::test_suite * init_unit_test_suite( int, char* []) +{ + boost::unit_test::test_suite * test = + BOOST_TEST_SUITE("Boost.Fiber: condition_variable test suite"); + + test->add( BOOST_TEST_CASE( & test_one_waiter_notify_one) ); + test->add( BOOST_TEST_CASE( & test_two_waiter_notify_one) ); + test->add( BOOST_TEST_CASE( & test_two_waiter_notify_all) ); + test->add( BOOST_TEST_CASE( & test_condition_wait) ); + test->add( BOOST_TEST_CASE( & test_condition_wait_until) ); + test->add( BOOST_TEST_CASE( & test_condition_wait_until_pred) ); + test->add( BOOST_TEST_CASE( & test_condition_wait_for) ); + test->add( BOOST_TEST_CASE( & test_condition_wait_for_pred) ); + + return test; +} diff --git a/src/boost/libs/fiber/test/test_fiber_dispatch.cpp b/src/boost/libs/fiber/test/test_fiber_dispatch.cpp new file mode 100644 index 00000000..1126b001 --- /dev/null +++ b/src/boost/libs/fiber/test/test_fiber_dispatch.cpp @@ -0,0 +1,440 @@ + +// Copyright Oliver Kowalke 2013. +// 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) +// +// This test is based on the tests of Boost.Thread + +#include <chrono> +#include <mutex> +#include <sstream> +#include <string> + +#include <boost/assert.hpp> +#include <boost/test/unit_test.hpp> + +#include <boost/fiber/all.hpp> + +int value1 = 0; +std::string value2 = ""; + +struct X { + int value; + + void foo( int i) { + value = i; + } +}; + +class copyable { +public: + bool state; + int value; + + copyable() : + state( false), + value( -1) { + } + + copyable( int v) : + state( true), + value( v) { + } + + void operator()() { + value1 = value; + } +}; + +class moveable { +public: + bool state; + int value; + + moveable() : + state( false), + value( -1) { + } + + moveable( int v) : + state( true), + value( v) { + } + + moveable( moveable && other) : + state( other.state), + value( other.value) { + other.state = false; + other.value = -1; + } + + moveable & operator=( moveable && other) { + if ( this == & other) return * this; + state = other.state; + value = other.value; + other.state = false; + other.value = -1; + return * this; + } + + moveable( moveable const& other) = delete; + moveable & operator=( moveable const& other) = delete; + + void operator()() { + value1 = value; + } +}; + +class detachable { +private: + int alive_count_; + +public: + static int alive_count; + static bool was_running; + + detachable() : + alive_count_( 1) { + ++alive_count; + } + + detachable( detachable const& g) : + alive_count_( g.alive_count_) { + ++alive_count; + } + + ~detachable() { + alive_count_ = 0; + --alive_count; + } + + void operator()() { + BOOST_CHECK_EQUAL(1, alive_count_); + was_running = true; + } +}; + +int detachable::alive_count = 0; +bool detachable::was_running = false; + +void fn1() { + value1 = 1; +} + +void fn2( int i, std::string const& s) { + value1 = i; + value2 = s; +} + +void fn3( int & i) { + i = 1; + boost::this_fiber::yield(); + i = 1; + boost::this_fiber::yield(); + i = 2; + boost::this_fiber::yield(); + i = 3; + boost::this_fiber::yield(); + i = 5; + boost::this_fiber::yield(); + i = 8; +} + +void fn4() { + boost::this_fiber::yield(); +} + +void fn5() { + boost::fibers::fiber f( boost::fibers::launch::dispatch, fn4); + BOOST_CHECK( f.joinable() ); + f.join(); + BOOST_CHECK( ! f.joinable() ); +} + +void test_scheduler_dtor() { + boost::fibers::context * ctx( + boost::fibers::context::active() ); + (void)ctx; +} + +void test_join_fn() { + { + value1 = 0; + boost::fibers::fiber f( boost::fibers::launch::dispatch, fn1); + f.join(); + BOOST_CHECK_EQUAL( value1, 1); + } + { + value1 = 0; + value2 = ""; + boost::fibers::fiber f( boost::fibers::launch::dispatch, fn2, 3, "abc"); + f.join(); + BOOST_CHECK_EQUAL( value1, 3); + BOOST_CHECK_EQUAL( value2, "abc"); + } +} + +void test_join_memfn() { + X x = {0}; + BOOST_CHECK_EQUAL( x.value, 0); + boost::fibers::fiber( boost::fibers::launch::dispatch, & X::foo, & x, 3).join(); + BOOST_CHECK_EQUAL( x.value, 3); +} + +void test_join_copyable() { + value1 = 0; + copyable cp( 3); + BOOST_CHECK( cp.state); + BOOST_CHECK_EQUAL( value1, 0); + boost::fibers::fiber f( boost::fibers::launch::dispatch, cp); + f.join(); + BOOST_CHECK( cp.state); + BOOST_CHECK_EQUAL( value1, 3); +} + +void test_join_moveable() { + value1 = 0; + moveable mv( 7); + BOOST_CHECK( mv.state); + BOOST_CHECK_EQUAL( value1, 0); + boost::fibers::fiber f( boost::fibers::launch::dispatch, std::move( mv) ); + f.join(); + BOOST_CHECK( ! mv.state); + BOOST_CHECK_EQUAL( value1, 7); +} + +void test_join_lambda() { + { + value1 = 0; + value2 = ""; + int i = 3; + std::string abc("abc"); + boost::fibers::fiber f( + boost::fibers::launch::dispatch, [i,abc]() { + value1 = i; + value2 = abc; + }); + f.join(); + BOOST_CHECK_EQUAL( value1, 3); + BOOST_CHECK_EQUAL( value2, "abc"); + } + { + value1 = 0; + value2 = ""; + int i = 3; + std::string abc("abc"); + boost::fibers::fiber f( + boost::fibers::launch::dispatch, [](int i, std::string const& abc) { + value1 = i; + value2 = abc; + }, + i, abc); + f.join(); + BOOST_CHECK_EQUAL( value1, 3); + BOOST_CHECK_EQUAL( value2, "abc"); + } +} + +void test_join_bind() { + { + value1 = 0; + value2 = ""; + int i = 3; + std::string abc("abc"); + boost::fibers::fiber f( + boost::fibers::launch::dispatch, std::bind( + [i,abc]() { + value1 = i; + value2 = abc; + } + )); + f.join(); + BOOST_CHECK_EQUAL( value1, 3); + BOOST_CHECK_EQUAL( value2, "abc"); + } + { + value1 = 0; + value2 = ""; + std::string abc("abc"); + boost::fibers::fiber f( + boost::fibers::launch::dispatch, std::bind( + [](std::string & str) { + value1 = 3; + value2 = str; + }, + abc + )); + f.join(); + BOOST_CHECK_EQUAL( value1, 3); + BOOST_CHECK_EQUAL( value2, "abc"); + } + { + value1 = 0; + value2 = ""; + std::string abc("abc"); + boost::fibers::fiber f( + boost::fibers::launch::dispatch, std::bind( + []( std::string & str) { + value1 = 3; + value2 = str; + }, + std::placeholders::_1 + ), + std::ref( abc) ); + f.join(); + BOOST_CHECK_EQUAL( value1, 3); + BOOST_CHECK_EQUAL( value2, "abc"); + } +} + +void test_join_in_fiber() { + // spawn fiber f + // f spawns an new fiber f' in its fiber-fn + // f' yields in its fiber-fn + // f joins s' and gets suspended (waiting on s') + boost::fibers::fiber f( boost::fibers::launch::dispatch, fn5); + BOOST_CHECK( f.joinable() ); + // join() resumes f + f' which completes + f.join(); + BOOST_CHECK( ! f.joinable() ); +} + +void test_move_fiber() { + boost::fibers::fiber f1; + BOOST_CHECK( ! f1.joinable() ); + boost::fibers::fiber f2( boost::fibers::launch::dispatch, fn1); + BOOST_CHECK( f2.joinable() ); + f1 = std::move( f2); + BOOST_CHECK( f1.joinable() ); + BOOST_CHECK( ! f2.joinable() ); + f1.join(); + BOOST_CHECK( ! f1.joinable() ); + BOOST_CHECK( ! f2.joinable() ); +} + +void test_id() { + boost::fibers::fiber f1; + boost::fibers::fiber f2( boost::fibers::launch::dispatch, fn1); + BOOST_CHECK( ! f1.joinable() ); + BOOST_CHECK( f2.joinable() ); + + BOOST_CHECK_EQUAL( boost::fibers::fiber::id(), f1.get_id() ); + BOOST_CHECK( boost::fibers::fiber::id() != f2.get_id() ); + + boost::fibers::fiber f3( boost::fibers::launch::dispatch, fn1); + BOOST_CHECK( f2.get_id() != f3.get_id() ); + + f1 = std::move( f2); + BOOST_CHECK( f1.joinable() ); + BOOST_CHECK( ! f2.joinable() ); + + BOOST_CHECK( boost::fibers::fiber::id() != f1.get_id() ); + BOOST_CHECK_EQUAL( boost::fibers::fiber::id(), f2.get_id() ); + + BOOST_CHECK( ! f2.joinable() ); + + f1.join(); + f3.join(); +} + +void test_yield() { + int v1 = 0, v2 = 0; + BOOST_CHECK_EQUAL( 0, v1); + BOOST_CHECK_EQUAL( 0, v2); + boost::fibers::fiber f1( boost::fibers::launch::dispatch, fn3, std::ref( v1) ); + boost::fibers::fiber f2( boost::fibers::launch::dispatch, fn3, std::ref( v2) ); + f1.join(); + f2.join(); + BOOST_CHECK( ! f1.joinable() ); + BOOST_CHECK( ! f2.joinable() ); + BOOST_CHECK_EQUAL( 8, v1); + BOOST_CHECK_EQUAL( 8, v2); +} + +void test_sleep_for() { + typedef std::chrono::system_clock Clock; + typedef Clock::time_point time_point; + std::chrono::milliseconds ms(500); + time_point t0 = Clock::now(); + boost::this_fiber::sleep_for(ms); + time_point t1 = Clock::now(); + std::chrono::nanoseconds ns = (t1 - t0) - ms; + std::chrono::nanoseconds err = ms / 10; + // This test is spurious as it depends on the time the fiber system switches the fiber + BOOST_CHECK((std::max)(ns.count(), -ns.count()) < (err+std::chrono::milliseconds(1000)).count()); +} + +void test_sleep_until() { + { + typedef std::chrono::steady_clock Clock; + typedef Clock::time_point time_point; + std::chrono::milliseconds ms(500); + time_point t0 = Clock::now(); + boost::this_fiber::sleep_until(t0 + ms); + time_point t1 = Clock::now(); + std::chrono::nanoseconds ns = (t1 - t0) - ms; + std::chrono::nanoseconds err = ms / 10; + // This test is spurious as it depends on the time the thread system switches the threads + BOOST_CHECK((std::max)(ns.count(), -ns.count()) < (err+std::chrono::milliseconds(1000)).count()); + } + { + typedef std::chrono::system_clock Clock; + typedef Clock::time_point time_point; + std::chrono::milliseconds ms(500); + time_point t0 = Clock::now(); + boost::this_fiber::sleep_until(t0 + ms); + time_point t1 = Clock::now(); + std::chrono::nanoseconds ns = (t1 - t0) - ms; + std::chrono::nanoseconds err = ms / 10; + // This test is spurious as it depends on the time the thread system switches the threads + BOOST_CHECK((std::max)(ns.count(), -ns.count()) < (err+std::chrono::milliseconds(1000)).count()); + } +} + +void do_wait( boost::fibers::barrier* b) { + b->wait(); +} + +void test_detach() { + { + boost::fibers::fiber f( boost::fibers::launch::dispatch, (detachable()) ); + BOOST_CHECK( f.joinable() ); + f.detach(); + BOOST_CHECK( ! f.joinable() ); + boost::this_fiber::sleep_for( std::chrono::milliseconds(250) ); + BOOST_CHECK( detachable::was_running); + BOOST_CHECK_EQUAL( 0, detachable::alive_count); + } + { + boost::fibers::fiber f( boost::fibers::launch::dispatch, (detachable()) ); + BOOST_CHECK( f.joinable() ); + boost::this_fiber::yield(); + f.detach(); + BOOST_CHECK( ! f.joinable() ); + boost::this_fiber::sleep_for( std::chrono::milliseconds(250) ); + BOOST_CHECK( detachable::was_running); + BOOST_CHECK_EQUAL( 0, detachable::alive_count); + } +} + +boost::unit_test::test_suite * init_unit_test_suite( int, char* []) { + boost::unit_test::test_suite * test = + BOOST_TEST_SUITE("Boost.Fiber: fiber test suite"); + + test->add( BOOST_TEST_CASE( & test_scheduler_dtor) ); + test->add( BOOST_TEST_CASE( & test_join_fn) ); + test->add( BOOST_TEST_CASE( & test_join_memfn) ); + test->add( BOOST_TEST_CASE( & test_join_copyable) ); + test->add( BOOST_TEST_CASE( & test_join_moveable) ); + test->add( BOOST_TEST_CASE( & test_join_lambda) ); + test->add( BOOST_TEST_CASE( & test_join_bind) ); + test->add( BOOST_TEST_CASE( & test_join_in_fiber) ); + test->add( BOOST_TEST_CASE( & test_move_fiber) ); + test->add( BOOST_TEST_CASE( & test_yield) ); + test->add( BOOST_TEST_CASE( & test_sleep_for) ); + test->add( BOOST_TEST_CASE( & test_sleep_until) ); + test->add( BOOST_TEST_CASE( & test_detach) ); + + return test; +} diff --git a/src/boost/libs/fiber/test/test_fiber_post.cpp b/src/boost/libs/fiber/test/test_fiber_post.cpp new file mode 100644 index 00000000..01a7e74c --- /dev/null +++ b/src/boost/libs/fiber/test/test_fiber_post.cpp @@ -0,0 +1,440 @@ + +// Copyright Oliver Kowalke 2013. +// 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) +// +// This test is based on the tests of Boost.Thread + +#include <chrono> +#include <mutex> +#include <sstream> +#include <string> + +#include <boost/assert.hpp> +#include <boost/test/unit_test.hpp> + +#include <boost/fiber/all.hpp> + +int value1 = 0; +std::string value2 = ""; + +struct X { + int value; + + void foo( int i) { + value = i; + } +}; + +class copyable { +public: + bool state; + int value; + + copyable() : + state( false), + value( -1) { + } + + copyable( int v) : + state( true), + value( v) { + } + + void operator()() { + value1 = value; + } +}; + +class moveable { +public: + bool state; + int value; + + moveable() : + state( false), + value( -1) { + } + + moveable( int v) : + state( true), + value( v) { + } + + moveable( moveable && other) : + state( other.state), + value( other.value) { + other.state = false; + other.value = -1; + } + + moveable & operator=( moveable && other) { + if ( this == & other) return * this; + state = other.state; + value = other.value; + other.state = false; + other.value = -1; + return * this; + } + + moveable( moveable const& other) = delete; + moveable & operator=( moveable const& other) = delete; + + void operator()() { + value1 = value; + } +}; + +class detachable { +private: + int alive_count_; + +public: + static int alive_count; + static bool was_running; + + detachable() : + alive_count_( 1) { + ++alive_count; + } + + detachable( detachable const& g) : + alive_count_( g.alive_count_) { + ++alive_count; + } + + ~detachable() { + alive_count_ = 0; + --alive_count; + } + + void operator()() { + BOOST_CHECK_EQUAL(1, alive_count_); + was_running = true; + } +}; + +int detachable::alive_count = 0; +bool detachable::was_running = false; + +void fn1() { + value1 = 1; +} + +void fn2( int i, std::string const& s) { + value1 = i; + value2 = s; +} + +void fn3( int & i) { + i = 1; + boost::this_fiber::yield(); + i = 1; + boost::this_fiber::yield(); + i = 2; + boost::this_fiber::yield(); + i = 3; + boost::this_fiber::yield(); + i = 5; + boost::this_fiber::yield(); + i = 8; +} + +void fn4() { + boost::this_fiber::yield(); +} + +void fn5() { + boost::fibers::fiber f( boost::fibers::launch::post, fn4); + BOOST_CHECK( f.joinable() ); + f.join(); + BOOST_CHECK( ! f.joinable() ); +} + +void test_scheduler_dtor() { + boost::fibers::context * ctx( + boost::fibers::context::active() ); + (void)ctx; +} + +void test_join_fn() { + { + value1 = 0; + boost::fibers::fiber f( boost::fibers::launch::post, fn1); + f.join(); + BOOST_CHECK_EQUAL( value1, 1); + } + { + value1 = 0; + value2 = ""; + boost::fibers::fiber f( boost::fibers::launch::post, fn2, 3, "abc"); + f.join(); + BOOST_CHECK_EQUAL( value1, 3); + BOOST_CHECK_EQUAL( value2, "abc"); + } +} + +void test_join_memfn() { + X x = {0}; + BOOST_CHECK_EQUAL( x.value, 0); + boost::fibers::fiber( boost::fibers::launch::post, & X::foo, & x, 3).join(); + BOOST_CHECK_EQUAL( x.value, 3); +} + +void test_join_copyable() { + value1 = 0; + copyable cp( 3); + BOOST_CHECK( cp.state); + BOOST_CHECK_EQUAL( value1, 0); + boost::fibers::fiber f( boost::fibers::launch::post, cp); + f.join(); + BOOST_CHECK( cp.state); + BOOST_CHECK_EQUAL( value1, 3); +} + +void test_join_moveable() { + value1 = 0; + moveable mv( 7); + BOOST_CHECK( mv.state); + BOOST_CHECK_EQUAL( value1, 0); + boost::fibers::fiber f( boost::fibers::launch::post, std::move( mv) ); + f.join(); + BOOST_CHECK( ! mv.state); + BOOST_CHECK_EQUAL( value1, 7); +} + +void test_join_lambda() { + { + value1 = 0; + value2 = ""; + int i = 3; + std::string abc("abc"); + boost::fibers::fiber f( + boost::fibers::launch::post, [i,abc]() { + value1 = i; + value2 = abc; + }); + f.join(); + BOOST_CHECK_EQUAL( value1, 3); + BOOST_CHECK_EQUAL( value2, "abc"); + } + { + value1 = 0; + value2 = ""; + int i = 3; + std::string abc("abc"); + boost::fibers::fiber f( + boost::fibers::launch::post, [](int i, std::string const& abc) { + value1 = i; + value2 = abc; + }, + i, abc); + f.join(); + BOOST_CHECK_EQUAL( value1, 3); + BOOST_CHECK_EQUAL( value2, "abc"); + } +} + +void test_join_bind() { + { + value1 = 0; + value2 = ""; + int i = 3; + std::string abc("abc"); + boost::fibers::fiber f( + boost::fibers::launch::post, std::bind( + [i,abc]() { + value1 = i; + value2 = abc; + } + )); + f.join(); + BOOST_CHECK_EQUAL( value1, 3); + BOOST_CHECK_EQUAL( value2, "abc"); + } + { + value1 = 0; + value2 = ""; + std::string abc("abc"); + boost::fibers::fiber f( + boost::fibers::launch::post, std::bind( + [](std::string & str) { + value1 = 3; + value2 = str; + }, + abc + )); + f.join(); + BOOST_CHECK_EQUAL( value1, 3); + BOOST_CHECK_EQUAL( value2, "abc"); + } + { + value1 = 0; + value2 = ""; + std::string abc("abc"); + boost::fibers::fiber f( + boost::fibers::launch::post, std::bind( + []( std::string & str) { + value1 = 3; + value2 = str; + }, + std::placeholders::_1 + ), + std::ref( abc) ); + f.join(); + BOOST_CHECK_EQUAL( value1, 3); + BOOST_CHECK_EQUAL( value2, "abc"); + } +} + +void test_join_in_fiber() { + // spawn fiber f + // f spawns an new fiber f' in its fiber-fn + // f' yields in its fiber-fn + // f joins s' and gets suspended (waiting on s') + boost::fibers::fiber f( boost::fibers::launch::post, fn5); + BOOST_CHECK( f.joinable() ); + // join() resumes f + f' which completes + f.join(); + BOOST_CHECK( ! f.joinable() ); +} + +void test_move_fiber() { + boost::fibers::fiber f1; + BOOST_CHECK( ! f1.joinable() ); + boost::fibers::fiber f2( boost::fibers::launch::post, fn1); + BOOST_CHECK( f2.joinable() ); + f1 = std::move( f2); + BOOST_CHECK( f1.joinable() ); + BOOST_CHECK( ! f2.joinable() ); + f1.join(); + BOOST_CHECK( ! f1.joinable() ); + BOOST_CHECK( ! f2.joinable() ); +} + +void test_id() { + boost::fibers::fiber f1; + boost::fibers::fiber f2( boost::fibers::launch::post, fn1); + BOOST_CHECK( ! f1.joinable() ); + BOOST_CHECK( f2.joinable() ); + + BOOST_CHECK_EQUAL( boost::fibers::fiber::id(), f1.get_id() ); + BOOST_CHECK( boost::fibers::fiber::id() != f2.get_id() ); + + boost::fibers::fiber f3( boost::fibers::launch::post, fn1); + BOOST_CHECK( f2.get_id() != f3.get_id() ); + + f1 = std::move( f2); + BOOST_CHECK( f1.joinable() ); + BOOST_CHECK( ! f2.joinable() ); + + BOOST_CHECK( boost::fibers::fiber::id() != f1.get_id() ); + BOOST_CHECK_EQUAL( boost::fibers::fiber::id(), f2.get_id() ); + + BOOST_CHECK( ! f2.joinable() ); + + f1.join(); + f3.join(); +} + +void test_yield() { + int v1 = 0, v2 = 0; + BOOST_CHECK_EQUAL( 0, v1); + BOOST_CHECK_EQUAL( 0, v2); + boost::fibers::fiber f1( boost::fibers::launch::post, fn3, std::ref( v1) ); + boost::fibers::fiber f2( boost::fibers::launch::post, fn3, std::ref( v2) ); + f1.join(); + f2.join(); + BOOST_CHECK( ! f1.joinable() ); + BOOST_CHECK( ! f2.joinable() ); + BOOST_CHECK_EQUAL( 8, v1); + BOOST_CHECK_EQUAL( 8, v2); +} + +void test_sleep_for() { + typedef std::chrono::system_clock Clock; + typedef Clock::time_point time_point; + std::chrono::milliseconds ms(500); + time_point t0 = Clock::now(); + boost::this_fiber::sleep_for(ms); + time_point t1 = Clock::now(); + std::chrono::nanoseconds ns = (t1 - t0) - ms; + std::chrono::nanoseconds err = ms / 10; + // This test is spurious as it depends on the time the fiber system switches the fiber + BOOST_CHECK((std::max)(ns.count(), -ns.count()) < (err+std::chrono::milliseconds(1000)).count()); +} + +void test_sleep_until() { + { + typedef std::chrono::steady_clock Clock; + typedef Clock::time_point time_point; + std::chrono::milliseconds ms(500); + time_point t0 = Clock::now(); + boost::this_fiber::sleep_until(t0 + ms); + time_point t1 = Clock::now(); + std::chrono::nanoseconds ns = (t1 - t0) - ms; + std::chrono::nanoseconds err = ms / 10; + // This test is spurious as it depends on the time the thread system switches the threads + BOOST_CHECK((std::max)(ns.count(), -ns.count()) < (err+std::chrono::milliseconds(1000)).count()); + } + { + typedef std::chrono::system_clock Clock; + typedef Clock::time_point time_point; + std::chrono::milliseconds ms(500); + time_point t0 = Clock::now(); + boost::this_fiber::sleep_until(t0 + ms); + time_point t1 = Clock::now(); + std::chrono::nanoseconds ns = (t1 - t0) - ms; + std::chrono::nanoseconds err = ms / 10; + // This test is spurious as it depends on the time the thread system switches the threads + BOOST_CHECK((std::max)(ns.count(), -ns.count()) < (err+std::chrono::milliseconds(1000)).count()); + } +} + +void do_wait( boost::fibers::barrier* b) { + b->wait(); +} + +void test_detach() { + { + boost::fibers::fiber f( boost::fibers::launch::post, (detachable()) ); + BOOST_CHECK( f.joinable() ); + f.detach(); + BOOST_CHECK( ! f.joinable() ); + boost::this_fiber::sleep_for( std::chrono::milliseconds(250) ); + BOOST_CHECK( detachable::was_running); + BOOST_CHECK_EQUAL( 0, detachable::alive_count); + } + { + boost::fibers::fiber f( boost::fibers::launch::post, (detachable()) ); + BOOST_CHECK( f.joinable() ); + boost::this_fiber::yield(); + f.detach(); + BOOST_CHECK( ! f.joinable() ); + boost::this_fiber::sleep_for( std::chrono::milliseconds(250) ); + BOOST_CHECK( detachable::was_running); + BOOST_CHECK_EQUAL( 0, detachable::alive_count); + } +} + +boost::unit_test::test_suite * init_unit_test_suite( int, char* []) { + boost::unit_test::test_suite * test = + BOOST_TEST_SUITE("Boost.Fiber: fiber test suite"); + + test->add( BOOST_TEST_CASE( & test_scheduler_dtor) ); + test->add( BOOST_TEST_CASE( & test_join_fn) ); + test->add( BOOST_TEST_CASE( & test_join_memfn) ); + test->add( BOOST_TEST_CASE( & test_join_copyable) ); + test->add( BOOST_TEST_CASE( & test_join_moveable) ); + test->add( BOOST_TEST_CASE( & test_join_lambda) ); + test->add( BOOST_TEST_CASE( & test_join_bind) ); + test->add( BOOST_TEST_CASE( & test_join_in_fiber) ); + test->add( BOOST_TEST_CASE( & test_move_fiber) ); + test->add( BOOST_TEST_CASE( & test_yield) ); + test->add( BOOST_TEST_CASE( & test_sleep_for) ); + test->add( BOOST_TEST_CASE( & test_sleep_until) ); + test->add( BOOST_TEST_CASE( & test_detach) ); + + return test; +} diff --git a/src/boost/libs/fiber/test/test_fss_dispatch.cpp b/src/boost/libs/fiber/test/test_fss_dispatch.cpp new file mode 100644 index 00000000..367c6aa1 --- /dev/null +++ b/src/boost/libs/fiber/test/test_fss_dispatch.cpp @@ -0,0 +1,237 @@ +// Copyright (C) 2001-2003 +// William E. Kempf +// Copyright (C) 2007 Anthony Williams +// +// 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) + +#include <iostream> +#include <mutex> + +#include <boost/test/unit_test.hpp> + +#include <boost/fiber/all.hpp> + +boost::fibers::mutex check_mutex; +boost::fibers::mutex fss_mutex; +int fss_instances = 0; +int fss_total = 0; + +struct fss_value_t { + fss_value_t() { + std::unique_lock<boost::fibers::mutex> lock(fss_mutex); + ++fss_instances; + ++fss_total; + value = 0; + } + ~fss_value_t() { + std::unique_lock<boost::fibers::mutex> lock(fss_mutex); + --fss_instances; + } + int value; +}; + +boost::fibers::fiber_specific_ptr<fss_value_t> fss_value; + +void fss_fiber() { + fss_value.reset(new fss_value_t()); + for (int i=0; i<1000; ++i) { + int& n = fss_value->value; + if (n != i) { + std::unique_lock<boost::fibers::mutex> lock(check_mutex); + BOOST_CHECK_EQUAL(n, i); + } + ++n; + } +} + +void fss() { + fss_instances = 0; + fss_total = 0; + + boost::fibers::fiber f1( boost::fibers::launch::dispatch, fss_fiber); + boost::fibers::fiber f2( boost::fibers::launch::dispatch, fss_fiber); + boost::fibers::fiber f3( boost::fibers::launch::dispatch, fss_fiber); + boost::fibers::fiber f4( boost::fibers::launch::dispatch, fss_fiber); + boost::fibers::fiber f5( boost::fibers::launch::dispatch, fss_fiber); + f1.join(); + f2.join(); + f3.join(); + f4.join(); + f5.join(); + + std::cout + << "fss_instances = " << fss_instances + << "; fss_total = " << fss_total + << "\n"; + std::cout.flush(); + + BOOST_CHECK_EQUAL(fss_instances, 0); + BOOST_CHECK_EQUAL(fss_total, 5); +} + +void test_fss() { + boost::fibers::fiber( boost::fibers::launch::dispatch, fss).join(); +} + +bool fss_cleanup_called=false; + +struct Dummy { +}; + +void fss_custom_cleanup(Dummy* d) { + delete d; + fss_cleanup_called=true; +} + +boost::fibers::fiber_specific_ptr<Dummy> fss_with_cleanup(fss_custom_cleanup); + +void fss_fiber_with_custom_cleanup() { + fss_with_cleanup.reset(new Dummy); +} + +void fss_with_custom_cleanup() { + boost::fibers::fiber f( boost::fibers::launch::dispatch, fss_fiber_with_custom_cleanup); + try { + f.join(); + } catch(...) { + f.join(); + throw; + } + + BOOST_CHECK(fss_cleanup_called); +} + +void test_fss_with_custom_cleanup() { + boost::fibers::fiber( boost::fibers::launch::dispatch, fss_with_custom_cleanup).join(); +} + +Dummy* fss_object=new Dummy; + +void fss_fiber_with_custom_cleanup_and_release() { + fss_with_cleanup.reset(fss_object); + fss_with_cleanup.release(); +} + +void do_test_fss_does_no_cleanup_after_release() { + fss_cleanup_called=false; + boost::fibers::fiber f( boost::fibers::launch::dispatch, fss_fiber_with_custom_cleanup_and_release); + try { + f.join(); + } catch(...) { + f.join(); + throw; + } + + BOOST_CHECK(!fss_cleanup_called); + if(!fss_cleanup_called) { + delete fss_object; + } +} + +struct dummy_class_tracks_deletions { + static unsigned deletions; + + ~dummy_class_tracks_deletions() { + ++deletions; + } +}; + +unsigned dummy_class_tracks_deletions::deletions=0; + +boost::fibers::fiber_specific_ptr<dummy_class_tracks_deletions> fss_with_null_cleanup(NULL); + +void fss_fiber_with_null_cleanup(dummy_class_tracks_deletions* delete_tracker) { + fss_with_null_cleanup.reset(delete_tracker); +} + +void do_test_fss_does_no_cleanup_with_null_cleanup_function() { + dummy_class_tracks_deletions* delete_tracker=new dummy_class_tracks_deletions; + boost::fibers::fiber f( boost::fibers::launch::dispatch, [&delete_tracker](){ + fss_fiber_with_null_cleanup( delete_tracker); }); + try { + f.join(); + } catch(...) { + f.join(); + throw; + } + + BOOST_CHECK(!dummy_class_tracks_deletions::deletions); + if(!dummy_class_tracks_deletions::deletions) { + delete delete_tracker; + } +} + +void test_fss_does_no_cleanup_after_release() { + boost::fibers::fiber( boost::fibers::launch::dispatch, do_test_fss_does_no_cleanup_after_release).join(); +} + +void test_fss_does_no_cleanup_with_null_cleanup_function() { + boost::fibers::fiber( boost::fibers::launch::dispatch, do_test_fss_does_no_cleanup_with_null_cleanup_function).join(); +} + + +void fiber_with_local_fss_ptr() { + { + boost::fibers::fiber_specific_ptr<Dummy> local_fss(fss_custom_cleanup); + + local_fss.reset(new Dummy); + } + BOOST_CHECK(fss_cleanup_called); + fss_cleanup_called=false; +} + +void fss_does_not_call_cleanup_after_ptr_destroyed() { + boost::fibers::fiber( boost::fibers::launch::dispatch, fiber_with_local_fss_ptr).join(); + BOOST_CHECK(!fss_cleanup_called); +} + +void test_fss_does_not_call_cleanup_after_ptr_destroyed() { + boost::fibers::fiber( boost::fibers::launch::dispatch, fss_does_not_call_cleanup_after_ptr_destroyed).join(); +} + + +void fss_cleanup_not_called_for_null_pointer() { + boost::fibers::fiber_specific_ptr<Dummy> local_fss(fss_custom_cleanup); + local_fss.reset(new Dummy); + fss_cleanup_called=false; + local_fss.reset(0); + BOOST_CHECK(fss_cleanup_called); + fss_cleanup_called=false; + local_fss.reset(new Dummy); + BOOST_CHECK(!fss_cleanup_called); +} + +void test_fss_cleanup_not_called_for_null_pointer() { + boost::fibers::fiber( boost::fibers::launch::dispatch, fss_cleanup_not_called_for_null_pointer).join(); +} + + +void fss_at_the_same_adress() { + for(int i=0; i<2; i++) { + boost::fibers::fiber_specific_ptr<Dummy> local_fss(fss_custom_cleanup); + local_fss.reset(new Dummy); + fss_cleanup_called=false; + BOOST_CHECK(fss_cleanup_called); + fss_cleanup_called=false; + BOOST_CHECK(!fss_cleanup_called); + } +} + +void test_fss_at_the_same_adress() { + boost::fibers::fiber( boost::fibers::launch::dispatch, fss_at_the_same_adress).join(); +} + +boost::unit_test::test_suite* init_unit_test_suite(int, char*[]) { + boost::unit_test::test_suite* test = + BOOST_TEST_SUITE("Boost.Fiber: fss test suite"); + + test->add(BOOST_TEST_CASE(test_fss)); + test->add(BOOST_TEST_CASE(test_fss_with_custom_cleanup)); + test->add(BOOST_TEST_CASE(test_fss_does_no_cleanup_after_release)); + test->add(BOOST_TEST_CASE(test_fss_does_no_cleanup_with_null_cleanup_function)); + test->add(BOOST_TEST_CASE(test_fss_does_not_call_cleanup_after_ptr_destroyed)); + test->add(BOOST_TEST_CASE(test_fss_cleanup_not_called_for_null_pointer)); + + return test; +} diff --git a/src/boost/libs/fiber/test/test_fss_post.cpp b/src/boost/libs/fiber/test/test_fss_post.cpp new file mode 100644 index 00000000..166c4ea1 --- /dev/null +++ b/src/boost/libs/fiber/test/test_fss_post.cpp @@ -0,0 +1,237 @@ +// Copyright (C) 2001-2003 +// William E. Kempf +// Copyright (C) 2007 Anthony Williams +// +// 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) + +#include <iostream> +#include <mutex> + +#include <boost/test/unit_test.hpp> + +#include <boost/fiber/all.hpp> + +boost::fibers::mutex check_mutex; +boost::fibers::mutex fss_mutex; +int fss_instances = 0; +int fss_total = 0; + +struct fss_value_t { + fss_value_t() { + std::unique_lock<boost::fibers::mutex> lock(fss_mutex); + ++fss_instances; + ++fss_total; + value = 0; + } + ~fss_value_t() { + std::unique_lock<boost::fibers::mutex> lock(fss_mutex); + --fss_instances; + } + int value; +}; + +boost::fibers::fiber_specific_ptr<fss_value_t> fss_value; + +void fss_fiber() { + fss_value.reset(new fss_value_t()); + for (int i=0; i<1000; ++i) { + int& n = fss_value->value; + if (n != i) { + std::unique_lock<boost::fibers::mutex> lock(check_mutex); + BOOST_CHECK_EQUAL(n, i); + } + ++n; + } +} + +void fss() { + fss_instances = 0; + fss_total = 0; + + boost::fibers::fiber f1( boost::fibers::launch::post, fss_fiber); + boost::fibers::fiber f2( boost::fibers::launch::post, fss_fiber); + boost::fibers::fiber f3( boost::fibers::launch::post, fss_fiber); + boost::fibers::fiber f4( boost::fibers::launch::post, fss_fiber); + boost::fibers::fiber f5( boost::fibers::launch::post, fss_fiber); + f1.join(); + f2.join(); + f3.join(); + f4.join(); + f5.join(); + + std::cout + << "fss_instances = " << fss_instances + << "; fss_total = " << fss_total + << "\n"; + std::cout.flush(); + + BOOST_CHECK_EQUAL(fss_instances, 0); + BOOST_CHECK_EQUAL(fss_total, 5); +} + +void test_fss() { + boost::fibers::fiber( boost::fibers::launch::post, fss).join(); +} + +bool fss_cleanup_called=false; + +struct Dummy { +}; + +void fss_custom_cleanup(Dummy* d) { + delete d; + fss_cleanup_called=true; +} + +boost::fibers::fiber_specific_ptr<Dummy> fss_with_cleanup(fss_custom_cleanup); + +void fss_fiber_with_custom_cleanup() { + fss_with_cleanup.reset(new Dummy); +} + +void fss_with_custom_cleanup() { + boost::fibers::fiber f( boost::fibers::launch::post, fss_fiber_with_custom_cleanup); + try { + f.join(); + } catch(...) { + f.join(); + throw; + } + + BOOST_CHECK(fss_cleanup_called); +} + +void test_fss_with_custom_cleanup() { + boost::fibers::fiber( boost::fibers::launch::post, fss_with_custom_cleanup).join(); +} + +Dummy* fss_object=new Dummy; + +void fss_fiber_with_custom_cleanup_and_release() { + fss_with_cleanup.reset(fss_object); + fss_with_cleanup.release(); +} + +void do_test_fss_does_no_cleanup_after_release() { + fss_cleanup_called=false; + boost::fibers::fiber f( boost::fibers::launch::post, fss_fiber_with_custom_cleanup_and_release); + try { + f.join(); + } catch(...) { + f.join(); + throw; + } + + BOOST_CHECK(!fss_cleanup_called); + if(!fss_cleanup_called) { + delete fss_object; + } +} + +struct dummy_class_tracks_deletions { + static unsigned deletions; + + ~dummy_class_tracks_deletions() { + ++deletions; + } +}; + +unsigned dummy_class_tracks_deletions::deletions=0; + +boost::fibers::fiber_specific_ptr<dummy_class_tracks_deletions> fss_with_null_cleanup(NULL); + +void fss_fiber_with_null_cleanup(dummy_class_tracks_deletions* delete_tracker) { + fss_with_null_cleanup.reset(delete_tracker); +} + +void do_test_fss_does_no_cleanup_with_null_cleanup_function() { + dummy_class_tracks_deletions* delete_tracker=new dummy_class_tracks_deletions; + boost::fibers::fiber f( boost::fibers::launch::post, [&delete_tracker](){ + fss_fiber_with_null_cleanup( delete_tracker); }); + try { + f.join(); + } catch(...) { + f.join(); + throw; + } + + BOOST_CHECK(!dummy_class_tracks_deletions::deletions); + if(!dummy_class_tracks_deletions::deletions) { + delete delete_tracker; + } +} + +void test_fss_does_no_cleanup_after_release() { + boost::fibers::fiber( boost::fibers::launch::post, do_test_fss_does_no_cleanup_after_release).join(); +} + +void test_fss_does_no_cleanup_with_null_cleanup_function() { + boost::fibers::fiber( boost::fibers::launch::post, do_test_fss_does_no_cleanup_with_null_cleanup_function).join(); +} + + +void fiber_with_local_fss_ptr() { + { + boost::fibers::fiber_specific_ptr<Dummy> local_fss(fss_custom_cleanup); + + local_fss.reset(new Dummy); + } + BOOST_CHECK(fss_cleanup_called); + fss_cleanup_called=false; +} + +void fss_does_not_call_cleanup_after_ptr_destroyed() { + boost::fibers::fiber( boost::fibers::launch::post, fiber_with_local_fss_ptr).join(); + BOOST_CHECK(!fss_cleanup_called); +} + +void test_fss_does_not_call_cleanup_after_ptr_destroyed() { + boost::fibers::fiber( boost::fibers::launch::post, fss_does_not_call_cleanup_after_ptr_destroyed).join(); +} + + +void fss_cleanup_not_called_for_null_pointer() { + boost::fibers::fiber_specific_ptr<Dummy> local_fss(fss_custom_cleanup); + local_fss.reset(new Dummy); + fss_cleanup_called=false; + local_fss.reset(0); + BOOST_CHECK(fss_cleanup_called); + fss_cleanup_called=false; + local_fss.reset(new Dummy); + BOOST_CHECK(!fss_cleanup_called); +} + +void test_fss_cleanup_not_called_for_null_pointer() { + boost::fibers::fiber( boost::fibers::launch::post, fss_cleanup_not_called_for_null_pointer).join(); +} + + +void fss_at_the_same_adress() { + for(int i=0; i<2; i++) { + boost::fibers::fiber_specific_ptr<Dummy> local_fss(fss_custom_cleanup); + local_fss.reset(new Dummy); + fss_cleanup_called=false; + BOOST_CHECK(fss_cleanup_called); + fss_cleanup_called=false; + BOOST_CHECK(!fss_cleanup_called); + } +} + +void test_fss_at_the_same_adress() { + boost::fibers::fiber( boost::fibers::launch::post, fss_at_the_same_adress).join(); +} + +boost::unit_test::test_suite* init_unit_test_suite(int, char*[]) { + boost::unit_test::test_suite* test = + BOOST_TEST_SUITE("Boost.Fiber: fss test suite"); + + test->add(BOOST_TEST_CASE(test_fss)); + test->add(BOOST_TEST_CASE(test_fss_with_custom_cleanup)); + test->add(BOOST_TEST_CASE(test_fss_does_no_cleanup_after_release)); + test->add(BOOST_TEST_CASE(test_fss_does_no_cleanup_with_null_cleanup_function)); + test->add(BOOST_TEST_CASE(test_fss_does_not_call_cleanup_after_ptr_destroyed)); + test->add(BOOST_TEST_CASE(test_fss_cleanup_not_called_for_null_pointer)); + + return test; +} diff --git a/src/boost/libs/fiber/test/test_future_dispatch.cpp b/src/boost/libs/fiber/test/test_future_dispatch.cpp new file mode 100644 index 00000000..2990ec41 --- /dev/null +++ b/src/boost/libs/fiber/test/test_future_dispatch.cpp @@ -0,0 +1,569 @@ +// (C) Copyright 2008-10 Anthony Williams +// 2015 Oliver Kowalke +// +// 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) + +#include <chrono> +#include <memory> +#include <stdexcept> +#include <string> +#include <utility> + +#include <boost/test/unit_test.hpp> + +#include <boost/fiber/all.hpp> + +typedef std::chrono::milliseconds ms; +typedef std::chrono::high_resolution_clock Clock; + +int gi = 7; + +struct my_exception : public std::runtime_error { + my_exception() : + std::runtime_error("my_exception") { + } +}; + +struct A { + A() = default; + + A( A const&) = delete; + A( A &&) = default; + + A & operator=( A const&) = delete; + A & operator=( A &&) = default; + + int value; +}; + +void fn1( boost::fibers::promise< int > * p, int i) { + boost::this_fiber::yield(); + p->set_value( i); +} + +void fn2() { + boost::fibers::promise< int > p; + boost::fibers::future< int > f( p.get_future() ); + boost::this_fiber::yield(); + boost::fibers::fiber( boost::fibers::launch::dispatch, fn1, & p, 7).detach(); + boost::this_fiber::yield(); + BOOST_CHECK( 7 == f.get() ); +} + +int fn3() { + return 3; +} + +void fn4() { +} + +int fn5() { + boost::throw_exception( my_exception() ); + return 3; +} + +void fn6() { + boost::throw_exception( my_exception() ); +} + +int & fn7() { + return gi; +} + +int fn8( int i) { + return i; +} + +A fn9() { + A a; + a.value = 3; + return a; +} + +A fn10() { + boost::throw_exception( my_exception() ); + return A(); +} + +void fn11( boost::fibers::promise< int > p) { + boost::this_fiber::sleep_for( ms(500) ); + p.set_value(3); +} + +void fn12( boost::fibers::promise< int& > p) { + boost::this_fiber::sleep_for( ms(500) ); + gi = 5; + p.set_value( gi); +} + +void fn13( boost::fibers::promise< void > p) { + boost::this_fiber::sleep_for( ms(400) ); + p.set_value(); +} + +// future +void test_future_create() { + // default constructed future is not valid + boost::fibers::future< int > f1; + BOOST_CHECK( ! f1.valid() ); + + // future retrieved from promise is valid (if it is the first) + boost::fibers::promise< int > p2; + boost::fibers::future< int > f2 = p2.get_future(); + BOOST_CHECK( f2.valid() ); +} + +void test_future_create_ref() { + // default constructed future is not valid + boost::fibers::future< int& > f1; + BOOST_CHECK( ! f1.valid() ); + + // future retrieved from promise is valid (if it is the first) + boost::fibers::promise< int& > p2; + boost::fibers::future< int& > f2 = p2.get_future(); + BOOST_CHECK( f2.valid() ); +} + +void test_future_create_void() { + // default constructed future is not valid + boost::fibers::future< void > f1; + BOOST_CHECK( ! f1.valid() ); + + // future retrieved from promise is valid (if it is the first) + boost::fibers::promise< void > p2; + boost::fibers::future< void > f2 = p2.get_future(); + BOOST_CHECK( f2.valid() ); +} + +void test_future_move() { + // future retrieved from promise is valid (if it is the first) + boost::fibers::promise< int > p1; + boost::fibers::future< int > f1 = p1.get_future(); + BOOST_CHECK( f1.valid() ); + + // move construction + boost::fibers::future< int > f2( std::move( f1) ); + BOOST_CHECK( ! f1.valid() ); + BOOST_CHECK( f2.valid() ); + + // move assignment + f1 = std::move( f2); + BOOST_CHECK( f1.valid() ); + BOOST_CHECK( ! f2.valid() ); +} + +void test_future_move_ref() { + // future retrieved from promise is valid (if it is the first) + boost::fibers::promise< int& > p1; + boost::fibers::future< int& > f1 = p1.get_future(); + BOOST_CHECK( f1.valid() ); + + // move construction + boost::fibers::future< int& > f2( std::move( f1) ); + BOOST_CHECK( ! f1.valid() ); + BOOST_CHECK( f2.valid() ); + + // move assignment + f1 = std::move( f2); + BOOST_CHECK( f1.valid() ); + BOOST_CHECK( ! f2.valid() ); +} + +void test_future_move_void() { + // future retrieved from promise is valid (if it is the first) + boost::fibers::promise< void > p1; + boost::fibers::future< void > f1 = p1.get_future(); + BOOST_CHECK( f1.valid() ); + + // move construction + boost::fibers::future< void > f2( std::move( f1) ); + BOOST_CHECK( ! f1.valid() ); + BOOST_CHECK( f2.valid() ); + + // move assignment + f1 = std::move( f2); + BOOST_CHECK( f1.valid() ); + BOOST_CHECK( ! f2.valid() ); +} + +void test_future_get() { + // future retrieved from promise is valid (if it is the first) + boost::fibers::promise< int > p1; + p1.set_value( 7); + + boost::fibers::future< int > f1 = p1.get_future(); + BOOST_CHECK( f1.valid() ); + + // get + BOOST_CHECK( ! f1.get_exception_ptr() ); + BOOST_CHECK( 7 == f1.get() ); + BOOST_CHECK( ! f1.valid() ); + + // throw broken_promise if promise is destroyed without set + { + boost::fibers::promise< int > p2; + f1 = p2.get_future(); + } + bool thrown = false; + try { + f1.get(); + } catch ( boost::fibers::broken_promise const&) { + thrown = true; + } + BOOST_CHECK( ! f1.valid() ); + BOOST_CHECK( thrown); +} + +void test_future_get_move() { + // future retrieved from promise is valid (if it is the first) + boost::fibers::promise< A > p1; + A a; a.value = 7; + p1.set_value( std::move( a) ); + + boost::fibers::future< A > f1 = p1.get_future(); + BOOST_CHECK( f1.valid() ); + + // get + BOOST_CHECK( ! f1.get_exception_ptr() ); + BOOST_CHECK( 7 == f1.get().value); + BOOST_CHECK( ! f1.valid() ); + + // throw broken_promise if promise is destroyed without set + { + boost::fibers::promise< A > p2; + f1 = p2.get_future(); + } + bool thrown = false; + try { + f1.get(); + } catch ( boost::fibers::broken_promise const&) { + thrown = true; + } + BOOST_CHECK( ! f1.valid() ); + BOOST_CHECK( thrown); +} + +void test_future_get_ref() { + // future retrieved from promise is valid (if it is the first) + boost::fibers::promise< int& > p1; + int i = 7; + p1.set_value( i); + + boost::fibers::future< int& > f1 = p1.get_future(); + BOOST_CHECK( f1.valid() ); + + // get + BOOST_CHECK( ! f1.get_exception_ptr() ); + int & j = f1.get(); + BOOST_CHECK( &i == &j); + BOOST_CHECK( ! f1.valid() ); + + // throw broken_promise if promise is destroyed without set + { + boost::fibers::promise< int& > p2; + f1 = p2.get_future(); + } + bool thrown = false; + try { + f1.get(); + } catch ( boost::fibers::broken_promise const&) { + thrown = true; + } + BOOST_CHECK( ! f1.valid() ); + BOOST_CHECK( thrown); +} + + +void test_future_get_void() { + // future retrieved from promise is valid (if it is the first) + boost::fibers::promise< void > p1; + p1.set_value(); + + boost::fibers::future< void > f1 = p1.get_future(); + BOOST_CHECK( f1.valid() ); + + // get + BOOST_CHECK( ! f1.get_exception_ptr() ); + f1.get(); + BOOST_CHECK( ! f1.valid() ); + + // throw broken_promise if promise is destroyed without set + { + boost::fibers::promise< void > p2; + f1 = p2.get_future(); + } + bool thrown = false; + try { + f1.get(); + } catch ( boost::fibers::broken_promise const&) { + thrown = true; + } + BOOST_CHECK( ! f1.valid() ); + BOOST_CHECK( thrown); +} + +void test_future_share() { + // future retrieved from promise is valid (if it is the first) + boost::fibers::promise< int > p1; + int i = 7; + p1.set_value( i); + + boost::fibers::future< int > f1 = p1.get_future(); + BOOST_CHECK( f1.valid() ); + + // share + boost::fibers::shared_future< int > sf1 = f1.share(); + BOOST_CHECK( sf1.valid() ); + BOOST_CHECK( ! f1.valid() ); + + // get + BOOST_CHECK( ! sf1.get_exception_ptr() ); + int j = sf1.get(); + BOOST_CHECK_EQUAL( i, j); + BOOST_CHECK( sf1.valid() ); +} + +void test_future_share_ref() { + // future retrieved from promise is valid (if it is the first) + boost::fibers::promise< int& > p1; + int i = 7; + p1.set_value( i); + + boost::fibers::future< int& > f1 = p1.get_future(); + BOOST_CHECK( f1.valid() ); + + // share + boost::fibers::shared_future< int& > sf1 = f1.share(); + BOOST_CHECK( sf1.valid() ); + BOOST_CHECK( ! f1.valid() ); + + // get + BOOST_CHECK( ! sf1.get_exception_ptr() ); + int & j = sf1.get(); + BOOST_CHECK( &i == &j); + BOOST_CHECK( sf1.valid() ); +} + +void test_future_share_void() { + // future retrieved from promise is valid (if it is the first) + boost::fibers::promise< void > p1; + p1.set_value(); + + boost::fibers::future< void > f1 = p1.get_future(); + BOOST_CHECK( f1.valid() ); + + // share + boost::fibers::shared_future< void > sf1 = f1.share(); + BOOST_CHECK( sf1.valid() ); + BOOST_CHECK( ! f1.valid() ); + + // get + BOOST_CHECK( ! sf1.get_exception_ptr() ); + sf1.get(); + BOOST_CHECK( sf1.valid() ); +} + +void test_future_wait() { + // future retrieved from promise is valid (if it is the first) + boost::fibers::promise< int > p1; + boost::fibers::future< int > f1 = p1.get_future(); + + // wait on future + p1.set_value( 7); + f1.wait(); + BOOST_CHECK( 7 == f1.get() ); +} + +void test_future_wait_ref() { + // future retrieved from promise is valid (if it is the first) + boost::fibers::promise< int& > p1; + boost::fibers::future< int& > f1 = p1.get_future(); + + // wait on future + int i = 7; + p1.set_value( i); + f1.wait(); + int & j = f1.get(); + BOOST_CHECK( &i == &j); +} + +void test_future_wait_void() { + // future retrieved from promise is valid (if it is the first) + boost::fibers::promise< void > p1; + boost::fibers::future< void > f1 = p1.get_future(); + + // wait on future + p1.set_value(); + f1.wait(); + f1.get(); + BOOST_CHECK( ! f1.valid() ); +} + +void test_future_wait_for() { + // future retrieved from promise is valid (if it is the first) + boost::fibers::promise< int > p1; + boost::fibers::future< int > f1 = p1.get_future(); + + boost::fibers::fiber( boost::fibers::launch::dispatch, fn11, std::move( p1) ).detach(); + + // wait on future + BOOST_CHECK( f1.valid() ); + boost::fibers::future_status status = f1.wait_for( ms(300) ); + BOOST_CHECK( boost::fibers::future_status::timeout == status); + + BOOST_CHECK( f1.valid() ); + status = f1.wait_for( ms(400) ); + BOOST_CHECK( boost::fibers::future_status::ready == status); + + BOOST_CHECK( f1.valid() ); + f1.wait(); +} + +void test_future_wait_for_ref() { + // future retrieved from promise is valid (if it is the first) + boost::fibers::promise< int& > p1; + boost::fibers::future< int& > f1 = p1.get_future(); + + boost::fibers::fiber( boost::fibers::launch::dispatch, fn12, std::move( p1) ).detach(); + + // wait on future + BOOST_CHECK( f1.valid() ); + boost::fibers::future_status status = f1.wait_for( ms(300) ); + BOOST_CHECK( boost::fibers::future_status::timeout == status); + + BOOST_CHECK( f1.valid() ); + status = f1.wait_for( ms(400) ); + BOOST_CHECK( boost::fibers::future_status::ready == status); + + BOOST_CHECK( f1.valid() ); + f1.wait(); +} + +void test_future_wait_for_void() { + // future retrieved from promise is valid (if it is the first) + boost::fibers::promise< void > p1; + boost::fibers::future< void > f1 = p1.get_future(); + + boost::fibers::fiber( boost::fibers::launch::dispatch, fn13, std::move( p1) ).detach(); + + // wait on future + BOOST_CHECK( f1.valid() ); + boost::fibers::future_status status = f1.wait_for( ms(300) ); + BOOST_CHECK( boost::fibers::future_status::timeout == status); + + BOOST_CHECK( f1.valid() ); + status = f1.wait_for( ms(400) ); + BOOST_CHECK( boost::fibers::future_status::ready == status); + + BOOST_CHECK( f1.valid() ); + f1.wait(); +} + +void test_future_wait_until() { + // future retrieved from promise is valid (if it is the first) + boost::fibers::promise< int > p1; + boost::fibers::future< int > f1 = p1.get_future(); + + boost::fibers::fiber( boost::fibers::launch::dispatch, fn11, std::move( p1) ).detach(); + + // wait on future + BOOST_CHECK( f1.valid() ); + boost::fibers::future_status status = f1.wait_until( Clock::now() + ms(300) ); + BOOST_CHECK( boost::fibers::future_status::timeout == status); + + BOOST_CHECK( f1.valid() ); + status = f1.wait_until( Clock::now() + ms(400) ); + BOOST_CHECK( boost::fibers::future_status::ready == status); + + BOOST_CHECK( f1.valid() ); + f1.wait(); +} + +void test_future_wait_until_ref() { + // future retrieved from promise is valid (if it is the first) + boost::fibers::promise< int& > p1; + boost::fibers::future< int& > f1 = p1.get_future(); + + boost::fibers::fiber( boost::fibers::launch::dispatch, fn12, std::move( p1) ).detach(); + + // wait on future + BOOST_CHECK( f1.valid() ); + boost::fibers::future_status status = f1.wait_until( Clock::now() + ms(300) ); + BOOST_CHECK( boost::fibers::future_status::timeout == status); + + BOOST_CHECK( f1.valid() ); + status = f1.wait_until( Clock::now() + ms(400) ); + BOOST_CHECK( boost::fibers::future_status::ready == status); + + BOOST_CHECK( f1.valid() ); + f1.wait(); +} + +void test_future_wait_until_void() { + // future retrieved from promise is valid (if it is the first) + boost::fibers::promise< void > p1; + boost::fibers::future< void > f1 = p1.get_future(); + + boost::fibers::fiber( boost::fibers::launch::dispatch, fn13, std::move( p1) ).detach(); + + // wait on future + BOOST_CHECK( f1.valid() ); + boost::fibers::future_status status = f1.wait_until( Clock::now() + ms(300) ); + BOOST_CHECK( boost::fibers::future_status::timeout == status); + + BOOST_CHECK( f1.valid() ); + status = f1.wait_until( Clock::now() + ms(400) ); + BOOST_CHECK( boost::fibers::future_status::ready == status); + + BOOST_CHECK( f1.valid() ); + f1.wait(); +} + +void test_future_wait_with_fiber_1() { + boost::fibers::promise< int > p1; + boost::fibers::fiber( boost::fibers::launch::dispatch, fn1, & p1, 7).detach(); + + boost::fibers::future< int > f1 = p1.get_future(); + + // wait on future + BOOST_CHECK( 7 == f1.get() ); +} + +void test_future_wait_with_fiber_2() { + boost::fibers::fiber( boost::fibers::launch::dispatch, fn2).join(); +} + + +boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[]) { + boost::unit_test_framework::test_suite* test = + BOOST_TEST_SUITE("Boost.Fiber: future test suite"); + + test->add(BOOST_TEST_CASE(test_future_create)); + test->add(BOOST_TEST_CASE(test_future_create_ref)); + test->add(BOOST_TEST_CASE(test_future_create_void)); + test->add(BOOST_TEST_CASE(test_future_move)); + test->add(BOOST_TEST_CASE(test_future_move_ref)); + test->add(BOOST_TEST_CASE(test_future_move_void)); + test->add(BOOST_TEST_CASE(test_future_get)); + test->add(BOOST_TEST_CASE(test_future_get_move)); + test->add(BOOST_TEST_CASE(test_future_get_ref)); + test->add(BOOST_TEST_CASE(test_future_get_void)); + test->add(BOOST_TEST_CASE(test_future_share)); + test->add(BOOST_TEST_CASE(test_future_share_ref)); + test->add(BOOST_TEST_CASE(test_future_share_void)); + test->add(BOOST_TEST_CASE(test_future_wait)); + test->add(BOOST_TEST_CASE(test_future_wait_ref)); + test->add(BOOST_TEST_CASE(test_future_wait_void)); + test->add(BOOST_TEST_CASE(test_future_wait_for)); + test->add(BOOST_TEST_CASE(test_future_wait_for_ref)); + test->add(BOOST_TEST_CASE(test_future_wait_for_void)); + test->add(BOOST_TEST_CASE(test_future_wait_until)); + test->add(BOOST_TEST_CASE(test_future_wait_until_ref)); + test->add(BOOST_TEST_CASE(test_future_wait_until_void)); + test->add(BOOST_TEST_CASE(test_future_wait_with_fiber_1)); + test->add(BOOST_TEST_CASE(test_future_wait_with_fiber_2)); + + return test; +} diff --git a/src/boost/libs/fiber/test/test_future_mt_dispatch.cpp b/src/boost/libs/fiber/test/test_future_mt_dispatch.cpp new file mode 100644 index 00000000..16585bb0 --- /dev/null +++ b/src/boost/libs/fiber/test/test_future_mt_dispatch.cpp @@ -0,0 +1,50 @@ +// (C) Copyright 2008-10 Anthony Williams +// +// 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) + +#include <utility> +#include <memory> +#include <stdexcept> +#include <string> +#include <thread> + +#include <boost/fiber/all.hpp> +#include <boost/test/unit_test.hpp> + +int fn( int i) { + return i; +} + +void test_async() { + for ( int i = 0; i < 10; ++i) { + int n = 3; + boost::fibers::packaged_task< int( int) > pt( fn); + boost::fibers::future< int > f( pt.get_future() ); + std::thread t( + std::bind( + [n](boost::fibers::packaged_task< int( int) > & pt) mutable -> void { + boost::fibers::fiber( boost::fibers::launch::dispatch, std::move( pt), n).join(); + }, + std::move( pt) ) ); + int result = f.get(); + BOOST_CHECK_EQUAL( n, result); + t.join(); + } +} + +void test_dummy() {} + +boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[]) { + boost::unit_test_framework::test_suite* test = + BOOST_TEST_SUITE("Boost.Fiber: futures-mt test suite"); + +#if ! defined(BOOST_FIBERS_NO_ATOMICS) + test->add(BOOST_TEST_CASE(test_async)); +#else + test->add(BOOST_TEST_CASE(test_dummy)); +#endif + + return test; +} diff --git a/src/boost/libs/fiber/test/test_future_mt_post.cpp b/src/boost/libs/fiber/test/test_future_mt_post.cpp new file mode 100644 index 00000000..ff708a3b --- /dev/null +++ b/src/boost/libs/fiber/test/test_future_mt_post.cpp @@ -0,0 +1,50 @@ +// (C) Copyright 2008-10 Anthony Williams +// +// 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) + +#include <utility> +#include <memory> +#include <stdexcept> +#include <string> +#include <thread> + +#include <boost/fiber/all.hpp> +#include <boost/test/unit_test.hpp> + +int fn( int i) { + return i; +} + +void test_async() { + for ( int i = 0; i < 10; ++i) { + int n = 3; + boost::fibers::packaged_task< int( int) > pt( fn); + boost::fibers::future< int > f( pt.get_future() ); + std::thread t( + std::bind( + [n](boost::fibers::packaged_task< int( int) > & pt) mutable -> void { + boost::fibers::fiber( boost::fibers::launch::post, std::move( pt), n).join(); + }, + std::move( pt) ) ); + int result = f.get(); + BOOST_CHECK_EQUAL( n, result); + t.join(); + } +} + +void test_dummy() {} + +boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[]) { + boost::unit_test_framework::test_suite* test = + BOOST_TEST_SUITE("Boost.Fiber: futures-mt test suite"); + +#if ! defined(BOOST_FIBERS_NO_ATOMICS) + test->add(BOOST_TEST_CASE(test_async)); +#else + test->add(BOOST_TEST_CASE(test_dummy)); +#endif + + return test; +} diff --git a/src/boost/libs/fiber/test/test_future_post.cpp b/src/boost/libs/fiber/test/test_future_post.cpp new file mode 100644 index 00000000..01deb26f --- /dev/null +++ b/src/boost/libs/fiber/test/test_future_post.cpp @@ -0,0 +1,569 @@ +// (C) Copyright 2008-10 Anthony Williams +// 2015 Oliver Kowalke +// +// 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) + +#include <chrono> +#include <memory> +#include <stdexcept> +#include <string> +#include <utility> + +#include <boost/test/unit_test.hpp> + +#include <boost/fiber/all.hpp> + +typedef std::chrono::milliseconds ms; +typedef std::chrono::high_resolution_clock Clock; + +int gi = 7; + +struct my_exception : public std::runtime_error { + my_exception() : + std::runtime_error("my_exception") { + } +}; + +struct A { + A() = default; + + A( A const&) = delete; + A( A &&) = default; + + A & operator=( A const&) = delete; + A & operator=( A &&) = default; + + int value; +}; + +void fn1( boost::fibers::promise< int > * p, int i) { + boost::this_fiber::yield(); + p->set_value( i); +} + +void fn2() { + boost::fibers::promise< int > p; + boost::fibers::future< int > f( p.get_future() ); + boost::this_fiber::yield(); + boost::fibers::fiber( boost::fibers::launch::post, fn1, & p, 7).detach(); + boost::this_fiber::yield(); + BOOST_CHECK( 7 == f.get() ); +} + +int fn3() { + return 3; +} + +void fn4() { +} + +int fn5() { + boost::throw_exception( my_exception() ); + return 3; +} + +void fn6() { + boost::throw_exception( my_exception() ); +} + +int & fn7() { + return gi; +} + +int fn8( int i) { + return i; +} + +A fn9() { + A a; + a.value = 3; + return a; +} + +A fn10() { + boost::throw_exception( my_exception() ); + return A(); +} + +void fn11( boost::fibers::promise< int > p) { + boost::this_fiber::sleep_for( ms(500) ); + p.set_value(3); +} + +void fn12( boost::fibers::promise< int& > p) { + boost::this_fiber::sleep_for( ms(500) ); + gi = 5; + p.set_value( gi); +} + +void fn13( boost::fibers::promise< void > p) { + boost::this_fiber::sleep_for( ms(400) ); + p.set_value(); +} + +// future +void test_future_create() { + // default constructed future is not valid + boost::fibers::future< int > f1; + BOOST_CHECK( ! f1.valid() ); + + // future retrieved from promise is valid (if it is the first) + boost::fibers::promise< int > p2; + boost::fibers::future< int > f2 = p2.get_future(); + BOOST_CHECK( f2.valid() ); +} + +void test_future_create_ref() { + // default constructed future is not valid + boost::fibers::future< int& > f1; + BOOST_CHECK( ! f1.valid() ); + + // future retrieved from promise is valid (if it is the first) + boost::fibers::promise< int& > p2; + boost::fibers::future< int& > f2 = p2.get_future(); + BOOST_CHECK( f2.valid() ); +} + +void test_future_create_void() { + // default constructed future is not valid + boost::fibers::future< void > f1; + BOOST_CHECK( ! f1.valid() ); + + // future retrieved from promise is valid (if it is the first) + boost::fibers::promise< void > p2; + boost::fibers::future< void > f2 = p2.get_future(); + BOOST_CHECK( f2.valid() ); +} + +void test_future_move() { + // future retrieved from promise is valid (if it is the first) + boost::fibers::promise< int > p1; + boost::fibers::future< int > f1 = p1.get_future(); + BOOST_CHECK( f1.valid() ); + + // move construction + boost::fibers::future< int > f2( std::move( f1) ); + BOOST_CHECK( ! f1.valid() ); + BOOST_CHECK( f2.valid() ); + + // move assignment + f1 = std::move( f2); + BOOST_CHECK( f1.valid() ); + BOOST_CHECK( ! f2.valid() ); +} + +void test_future_move_ref() { + // future retrieved from promise is valid (if it is the first) + boost::fibers::promise< int& > p1; + boost::fibers::future< int& > f1 = p1.get_future(); + BOOST_CHECK( f1.valid() ); + + // move construction + boost::fibers::future< int& > f2( std::move( f1) ); + BOOST_CHECK( ! f1.valid() ); + BOOST_CHECK( f2.valid() ); + + // move assignment + f1 = std::move( f2); + BOOST_CHECK( f1.valid() ); + BOOST_CHECK( ! f2.valid() ); +} + +void test_future_move_void() { + // future retrieved from promise is valid (if it is the first) + boost::fibers::promise< void > p1; + boost::fibers::future< void > f1 = p1.get_future(); + BOOST_CHECK( f1.valid() ); + + // move construction + boost::fibers::future< void > f2( std::move( f1) ); + BOOST_CHECK( ! f1.valid() ); + BOOST_CHECK( f2.valid() ); + + // move assignment + f1 = std::move( f2); + BOOST_CHECK( f1.valid() ); + BOOST_CHECK( ! f2.valid() ); +} + +void test_future_get() { + // future retrieved from promise is valid (if it is the first) + boost::fibers::promise< int > p1; + p1.set_value( 7); + + boost::fibers::future< int > f1 = p1.get_future(); + BOOST_CHECK( f1.valid() ); + + // get + BOOST_CHECK( ! f1.get_exception_ptr() ); + BOOST_CHECK( 7 == f1.get() ); + BOOST_CHECK( ! f1.valid() ); + + // throw broken_promise if promise is destroyed without set + { + boost::fibers::promise< int > p2; + f1 = p2.get_future(); + } + bool thrown = false; + try { + f1.get(); + } catch ( boost::fibers::broken_promise const&) { + thrown = true; + } + BOOST_CHECK( ! f1.valid() ); + BOOST_CHECK( thrown); +} + +void test_future_get_move() { + // future retrieved from promise is valid (if it is the first) + boost::fibers::promise< A > p1; + A a; a.value = 7; + p1.set_value( std::move( a) ); + + boost::fibers::future< A > f1 = p1.get_future(); + BOOST_CHECK( f1.valid() ); + + // get + BOOST_CHECK( ! f1.get_exception_ptr() ); + BOOST_CHECK( 7 == f1.get().value); + BOOST_CHECK( ! f1.valid() ); + + // throw broken_promise if promise is destroyed without set + { + boost::fibers::promise< A > p2; + f1 = p2.get_future(); + } + bool thrown = false; + try { + f1.get(); + } catch ( boost::fibers::broken_promise const&) { + thrown = true; + } + BOOST_CHECK( ! f1.valid() ); + BOOST_CHECK( thrown); +} + +void test_future_get_ref() { + // future retrieved from promise is valid (if it is the first) + boost::fibers::promise< int& > p1; + int i = 7; + p1.set_value( i); + + boost::fibers::future< int& > f1 = p1.get_future(); + BOOST_CHECK( f1.valid() ); + + // get + BOOST_CHECK( ! f1.get_exception_ptr() ); + int & j = f1.get(); + BOOST_CHECK( &i == &j); + BOOST_CHECK( ! f1.valid() ); + + // throw broken_promise if promise is destroyed without set + { + boost::fibers::promise< int& > p2; + f1 = p2.get_future(); + } + bool thrown = false; + try { + f1.get(); + } catch ( boost::fibers::broken_promise const&) { + thrown = true; + } + BOOST_CHECK( ! f1.valid() ); + BOOST_CHECK( thrown); +} + + +void test_future_get_void() { + // future retrieved from promise is valid (if it is the first) + boost::fibers::promise< void > p1; + p1.set_value(); + + boost::fibers::future< void > f1 = p1.get_future(); + BOOST_CHECK( f1.valid() ); + + // get + BOOST_CHECK( ! f1.get_exception_ptr() ); + f1.get(); + BOOST_CHECK( ! f1.valid() ); + + // throw broken_promise if promise is destroyed without set + { + boost::fibers::promise< void > p2; + f1 = p2.get_future(); + } + bool thrown = false; + try { + f1.get(); + } catch ( boost::fibers::broken_promise const&) { + thrown = true; + } + BOOST_CHECK( ! f1.valid() ); + BOOST_CHECK( thrown); +} + +void test_future_share() { + // future retrieved from promise is valid (if it is the first) + boost::fibers::promise< int > p1; + int i = 7; + p1.set_value( i); + + boost::fibers::future< int > f1 = p1.get_future(); + BOOST_CHECK( f1.valid() ); + + // share + boost::fibers::shared_future< int > sf1 = f1.share(); + BOOST_CHECK( sf1.valid() ); + BOOST_CHECK( ! f1.valid() ); + + // get + BOOST_CHECK( ! sf1.get_exception_ptr() ); + int j = sf1.get(); + BOOST_CHECK_EQUAL( i, j); + BOOST_CHECK( sf1.valid() ); +} + +void test_future_share_ref() { + // future retrieved from promise is valid (if it is the first) + boost::fibers::promise< int& > p1; + int i = 7; + p1.set_value( i); + + boost::fibers::future< int& > f1 = p1.get_future(); + BOOST_CHECK( f1.valid() ); + + // share + boost::fibers::shared_future< int& > sf1 = f1.share(); + BOOST_CHECK( sf1.valid() ); + BOOST_CHECK( ! f1.valid() ); + + // get + BOOST_CHECK( ! sf1.get_exception_ptr() ); + int & j = sf1.get(); + BOOST_CHECK( &i == &j); + BOOST_CHECK( sf1.valid() ); +} + +void test_future_share_void() { + // future retrieved from promise is valid (if it is the first) + boost::fibers::promise< void > p1; + p1.set_value(); + + boost::fibers::future< void > f1 = p1.get_future(); + BOOST_CHECK( f1.valid() ); + + // share + boost::fibers::shared_future< void > sf1 = f1.share(); + BOOST_CHECK( sf1.valid() ); + BOOST_CHECK( ! f1.valid() ); + + // get + BOOST_CHECK( ! sf1.get_exception_ptr() ); + sf1.get(); + BOOST_CHECK( sf1.valid() ); +} + +void test_future_wait() { + // future retrieved from promise is valid (if it is the first) + boost::fibers::promise< int > p1; + boost::fibers::future< int > f1 = p1.get_future(); + + // wait on future + p1.set_value( 7); + f1.wait(); + BOOST_CHECK( 7 == f1.get() ); +} + +void test_future_wait_ref() { + // future retrieved from promise is valid (if it is the first) + boost::fibers::promise< int& > p1; + boost::fibers::future< int& > f1 = p1.get_future(); + + // wait on future + int i = 7; + p1.set_value( i); + f1.wait(); + int & j = f1.get(); + BOOST_CHECK( &i == &j); +} + +void test_future_wait_void() { + // future retrieved from promise is valid (if it is the first) + boost::fibers::promise< void > p1; + boost::fibers::future< void > f1 = p1.get_future(); + + // wait on future + p1.set_value(); + f1.wait(); + f1.get(); + BOOST_CHECK( ! f1.valid() ); +} + +void test_future_wait_for() { + // future retrieved from promise is valid (if it is the first) + boost::fibers::promise< int > p1; + boost::fibers::future< int > f1 = p1.get_future(); + + boost::fibers::fiber( boost::fibers::launch::post, fn11, std::move( p1) ).detach(); + + // wait on future + BOOST_CHECK( f1.valid() ); + boost::fibers::future_status status = f1.wait_for( ms(300) ); + BOOST_CHECK( boost::fibers::future_status::timeout == status); + + BOOST_CHECK( f1.valid() ); + status = f1.wait_for( ms(400) ); + BOOST_CHECK( boost::fibers::future_status::ready == status); + + BOOST_CHECK( f1.valid() ); + f1.wait(); +} + +void test_future_wait_for_ref() { + // future retrieved from promise is valid (if it is the first) + boost::fibers::promise< int& > p1; + boost::fibers::future< int& > f1 = p1.get_future(); + + boost::fibers::fiber( boost::fibers::launch::post, fn12, std::move( p1) ).detach(); + + // wait on future + BOOST_CHECK( f1.valid() ); + boost::fibers::future_status status = f1.wait_for( ms(300) ); + BOOST_CHECK( boost::fibers::future_status::timeout == status); + + BOOST_CHECK( f1.valid() ); + status = f1.wait_for( ms(400) ); + BOOST_CHECK( boost::fibers::future_status::ready == status); + + BOOST_CHECK( f1.valid() ); + f1.wait(); +} + +void test_future_wait_for_void() { + // future retrieved from promise is valid (if it is the first) + boost::fibers::promise< void > p1; + boost::fibers::future< void > f1 = p1.get_future(); + + boost::fibers::fiber( boost::fibers::launch::post, fn13, std::move( p1) ).detach(); + + // wait on future + BOOST_CHECK( f1.valid() ); + boost::fibers::future_status status = f1.wait_for( ms(300) ); + BOOST_CHECK( boost::fibers::future_status::timeout == status); + + BOOST_CHECK( f1.valid() ); + status = f1.wait_for( ms(400) ); + BOOST_CHECK( boost::fibers::future_status::ready == status); + + BOOST_CHECK( f1.valid() ); + f1.wait(); +} + +void test_future_wait_until() { + // future retrieved from promise is valid (if it is the first) + boost::fibers::promise< int > p1; + boost::fibers::future< int > f1 = p1.get_future(); + + boost::fibers::fiber( boost::fibers::launch::post, fn11, std::move( p1) ).detach(); + + // wait on future + BOOST_CHECK( f1.valid() ); + boost::fibers::future_status status = f1.wait_until( Clock::now() + ms(300) ); + BOOST_CHECK( boost::fibers::future_status::timeout == status); + + BOOST_CHECK( f1.valid() ); + status = f1.wait_until( Clock::now() + ms(400) ); + BOOST_CHECK( boost::fibers::future_status::ready == status); + + BOOST_CHECK( f1.valid() ); + f1.wait(); +} + +void test_future_wait_until_ref() { + // future retrieved from promise is valid (if it is the first) + boost::fibers::promise< int& > p1; + boost::fibers::future< int& > f1 = p1.get_future(); + + boost::fibers::fiber( boost::fibers::launch::post, fn12, std::move( p1) ).detach(); + + // wait on future + BOOST_CHECK( f1.valid() ); + boost::fibers::future_status status = f1.wait_until( Clock::now() + ms(300) ); + BOOST_CHECK( boost::fibers::future_status::timeout == status); + + BOOST_CHECK( f1.valid() ); + status = f1.wait_until( Clock::now() + ms(400) ); + BOOST_CHECK( boost::fibers::future_status::ready == status); + + BOOST_CHECK( f1.valid() ); + f1.wait(); +} + +void test_future_wait_until_void() { + // future retrieved from promise is valid (if it is the first) + boost::fibers::promise< void > p1; + boost::fibers::future< void > f1 = p1.get_future(); + + boost::fibers::fiber( boost::fibers::launch::post, fn13, std::move( p1) ).detach(); + + // wait on future + BOOST_CHECK( f1.valid() ); + boost::fibers::future_status status = f1.wait_until( Clock::now() + ms(300) ); + BOOST_CHECK( boost::fibers::future_status::timeout == status); + + BOOST_CHECK( f1.valid() ); + status = f1.wait_until( Clock::now() + ms(400) ); + BOOST_CHECK( boost::fibers::future_status::ready == status); + + BOOST_CHECK( f1.valid() ); + f1.wait(); +} + +void test_future_wait_with_fiber_1() { + boost::fibers::promise< int > p1; + boost::fibers::fiber( boost::fibers::launch::post, fn1, & p1, 7).detach(); + + boost::fibers::future< int > f1 = p1.get_future(); + + // wait on future + BOOST_CHECK( 7 == f1.get() ); +} + +void test_future_wait_with_fiber_2() { + boost::fibers::fiber( boost::fibers::launch::post, fn2).join(); +} + + +boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[]) { + boost::unit_test_framework::test_suite* test = + BOOST_TEST_SUITE("Boost.Fiber: future test suite"); + + test->add(BOOST_TEST_CASE(test_future_create)); + test->add(BOOST_TEST_CASE(test_future_create_ref)); + test->add(BOOST_TEST_CASE(test_future_create_void)); + test->add(BOOST_TEST_CASE(test_future_move)); + test->add(BOOST_TEST_CASE(test_future_move_ref)); + test->add(BOOST_TEST_CASE(test_future_move_void)); + test->add(BOOST_TEST_CASE(test_future_get)); + test->add(BOOST_TEST_CASE(test_future_get_move)); + test->add(BOOST_TEST_CASE(test_future_get_ref)); + test->add(BOOST_TEST_CASE(test_future_get_void)); + test->add(BOOST_TEST_CASE(test_future_share)); + test->add(BOOST_TEST_CASE(test_future_share_ref)); + test->add(BOOST_TEST_CASE(test_future_share_void)); + test->add(BOOST_TEST_CASE(test_future_wait)); + test->add(BOOST_TEST_CASE(test_future_wait_ref)); + test->add(BOOST_TEST_CASE(test_future_wait_void)); + test->add(BOOST_TEST_CASE(test_future_wait_for)); + test->add(BOOST_TEST_CASE(test_future_wait_for_ref)); + test->add(BOOST_TEST_CASE(test_future_wait_for_void)); + test->add(BOOST_TEST_CASE(test_future_wait_until)); + test->add(BOOST_TEST_CASE(test_future_wait_until_ref)); + test->add(BOOST_TEST_CASE(test_future_wait_until_void)); + test->add(BOOST_TEST_CASE(test_future_wait_with_fiber_1)); + test->add(BOOST_TEST_CASE(test_future_wait_with_fiber_2)); + + return test; +} diff --git a/src/boost/libs/fiber/test/test_mutex_dispatch.cpp b/src/boost/libs/fiber/test/test_mutex_dispatch.cpp new file mode 100644 index 00000000..dec8ed4d --- /dev/null +++ b/src/boost/libs/fiber/test/test_mutex_dispatch.cpp @@ -0,0 +1,447 @@ + +// Copyright Oliver Kowalke 2013. +// 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) +// +// This test is based on the tests of Boost.Thread + +#include <chrono> +#include <cstdlib> +#include <iostream> +#include <map> +#include <mutex> +#include <stdexcept> +#include <vector> + +#include <boost/test/unit_test.hpp> + +#include <boost/fiber/all.hpp> + +typedef std::chrono::nanoseconds ns; +typedef std::chrono::milliseconds ms; + +int value1 = 0; +int value2 = 0; + +template< typename M > +void fn1( M & mtx) { + typedef M mutex_type; + typename std::unique_lock< mutex_type > lk( mtx); + ++value1; + for ( int i = 0; i < 3; ++i) + boost::this_fiber::yield(); +} + +template< typename M > +void fn2( M & mtx) { + typedef M mutex_type; + ++value2; + typename std::unique_lock< mutex_type > lk( mtx); + ++value2; +} + +void fn3( boost::fibers::timed_mutex & m) { + std::chrono::steady_clock::time_point t0 = std::chrono::steady_clock::now(); + m.lock(); + std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now(); + m.unlock(); + ns d = t1 - t0 - ms(250); + BOOST_CHECK(d < ns(2500000)+ms(2000)); // within 2.5 ms +} + +void fn4( boost::fibers::timed_mutex & m) { + std::chrono::steady_clock::time_point t0 = std::chrono::steady_clock::now(); + while ( ! m.try_lock() ); + std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now(); + m.unlock(); + ns d = t1 - t0 - ms(250); + BOOST_CHECK(d < ns(50000000)+ms(2000)); // within 50 ms +} + +void fn5( boost::fibers::timed_mutex & m) { + std::chrono::steady_clock::time_point t0 = std::chrono::steady_clock::now(); + BOOST_CHECK( m.try_lock_for(ms(300)+ms(2000)) == true); + std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now(); + m.unlock(); + ns d = t1 - t0 - ms(250); + BOOST_CHECK(d < ns(5000000)+ms(2000)); // within 5 ms +} + +void fn6( boost::fibers::timed_mutex & m) { + std::chrono::steady_clock::time_point t0 = std::chrono::steady_clock::now(); + BOOST_CHECK(m.try_lock_for(ms(250)) == false); + std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now(); + ns d = t1 - t0 - ms(250); + BOOST_CHECK(d < ns(5000000)+ms(2000)); // within 5 ms +} + +void fn7( boost::fibers::timed_mutex & m) { + std::chrono::steady_clock::time_point t0 = std::chrono::steady_clock::now(); + BOOST_CHECK(m.try_lock_until(std::chrono::steady_clock::now() + ms(300) + ms(1000)) == true); + std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now(); + m.unlock(); + ns d = t1 - t0 - ms(250); + BOOST_CHECK(d < ns(5000000)+ms(2000)); // within 5ms +} + +void fn8( boost::fibers::timed_mutex & m) { + std::chrono::steady_clock::time_point t0 = std::chrono::steady_clock::now(); + BOOST_CHECK(m.try_lock_until(std::chrono::steady_clock::now() + ms(250)) == false); + std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now(); + ns d = t1 - t0 - ms(250); + ns r = ns(5000000)+ms(2000); // within 6ms + BOOST_CHECK(d < r); // within 6ms +} + +void fn9( boost::fibers::recursive_timed_mutex & m) { + std::chrono::steady_clock::time_point t0 = std::chrono::steady_clock::now(); + m.lock(); + std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now(); + m.lock(); + m.unlock(); + m.unlock(); + ns d = t1 - t0 - ms(250); + BOOST_CHECK(d < ms(2500)+ms(2000)); // within 2.5 ms +} + +void fn10( boost::fibers::recursive_timed_mutex & m) { + std::chrono::steady_clock::time_point t0 = std::chrono::steady_clock::now(); + while (!m.try_lock()) ; + std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now(); + BOOST_CHECK(m.try_lock()); + m.unlock(); + m.unlock(); + ns d = t1 - t0 - ms(250); + BOOST_CHECK(d < ms(50000)+ms(2000)); // within 50 ms +} + +void fn11( boost::fibers::recursive_timed_mutex & m) { + std::chrono::steady_clock::time_point t0 = std::chrono::steady_clock::now(); + BOOST_CHECK(m.try_lock_for(ms(300)+ms(1000)) == true); + std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now(); + BOOST_CHECK(m.try_lock()); + m.unlock(); + m.unlock(); + ns d = t1 - t0 - ms(250); + BOOST_CHECK(d < ns(5000000)+ms(2000)); // within 5 ms +} + +void fn12( boost::fibers::recursive_timed_mutex & m) { + std::chrono::steady_clock::time_point t0 = std::chrono::steady_clock::now(); + BOOST_CHECK(m.try_lock_for(ms(250)) == false); + std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now(); + ns d = t1 - t0 - ms(250); + BOOST_CHECK(d < ms(5000)+ms(2000)); // within 5 ms +} + +void fn13( boost::fibers::recursive_timed_mutex & m) { + std::chrono::steady_clock::time_point t0 = std::chrono::steady_clock::now(); + BOOST_CHECK(m.try_lock_until(std::chrono::steady_clock::now() + ms(300) + ms(1000)) == true); + std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now(); + m.unlock(); + ns d = t1 - t0 - ms(250); + BOOST_CHECK(d < ns(5000000)+ms(2000)); // within 5 ms +} + +void fn14( boost::fibers::recursive_timed_mutex & m) { + std::chrono::steady_clock::time_point t0 = std::chrono::steady_clock::now(); + BOOST_CHECK(m.try_lock_until(std::chrono::steady_clock::now() + ms(250)) == false); + std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now(); + ns d = t1 - t0 - ms(250); + BOOST_CHECK(d < ns(5000000)+ms(2000)); // within 5 ms +} + +void fn15( boost::fibers::recursive_mutex & m) { + std::chrono::steady_clock::time_point t0 = std::chrono::steady_clock::now(); + m.lock(); + std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now(); + m.lock(); + m.unlock(); + m.unlock(); + ns d = t1 - t0 - ms(250); + BOOST_CHECK(d < ns(2500000)+ms(2000)); // within 2.5 ms +} + +void fn16( boost::fibers::recursive_mutex & m) { + std::chrono::steady_clock::time_point t0 = std::chrono::steady_clock::now(); + while (!m.try_lock()); + std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now(); + BOOST_CHECK(m.try_lock()); + m.unlock(); + m.unlock(); + ns d = t1 - t0 - ms(250); + BOOST_CHECK(d < ns(50000000)+ms(2000)); // within 50 ms +} + +void fn17( boost::fibers::mutex & m) { + std::chrono::steady_clock::time_point t0 = std::chrono::steady_clock::now(); + m.lock(); + std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now(); + m.unlock(); + ns d = t1 - t0 - ms(250); + BOOST_CHECK(d < ms(2500)+ms(2000)); // within 2.5 ms +} + +void fn18( boost::fibers::mutex & m) { + std::chrono::steady_clock::time_point t0 = std::chrono::steady_clock::now(); + while (!m.try_lock()) ; + std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now(); + m.unlock(); + ns d = t1 - t0 - ms(250); + BOOST_CHECK(d < ns(50000000)+ms(2000)); // within 50 ms +} + +template< typename M > +struct test_lock { + typedef M mutex_type; + typedef typename std::unique_lock< M > lock_type; + + void operator()() { + mutex_type mtx; + + // Test the lock's constructors. + { + lock_type lk(mtx, std::defer_lock); + BOOST_CHECK(!lk); + } + lock_type lk(mtx); + BOOST_CHECK(lk ? true : false); + + // Test the lock and unlock methods. + lk.unlock(); + BOOST_CHECK(!lk); + lk.lock(); + BOOST_CHECK(lk ? true : false); + } +}; + +template< typename M > +struct test_exclusive { + typedef M mutex_type; + typedef typename std::unique_lock< M > lock_type; + + void operator()() { + value1 = 0; + value2 = 0; + BOOST_CHECK_EQUAL( 0, value1); + BOOST_CHECK_EQUAL( 0, value2); + + mutex_type mtx; + boost::fibers::fiber f1( boost::fibers::launch::dispatch, & fn1< mutex_type >, std::ref( mtx) ); + boost::fibers::fiber f2( boost::fibers::launch::dispatch, & fn2< mutex_type >, std::ref( mtx) ); + BOOST_ASSERT( f1.joinable() ); + BOOST_ASSERT( f2.joinable() ); + + f1.join(); + f2.join(); + BOOST_CHECK_EQUAL( 1, value1); + BOOST_CHECK_EQUAL( 2, value2); + } +}; + +template< typename M > +struct test_recursive_lock { + typedef M mutex_type; + typedef typename std::unique_lock< M > lock_type; + + void operator()() { + mutex_type mx; + lock_type lock1(mx); + lock_type lock2(mx); + } +}; + +void do_test_mutex() { + test_lock< boost::fibers::mutex >()(); + test_exclusive< boost::fibers::mutex >()(); + + { + boost::fibers::mutex mtx; + mtx.lock(); + boost::fibers::fiber f( boost::fibers::launch::dispatch, & fn17, std::ref( mtx) ); + boost::this_fiber::sleep_for( ms(250) ); + mtx.unlock(); + f.join(); + } + + { + boost::fibers::mutex mtx; + mtx.lock(); + boost::fibers::fiber f( boost::fibers::launch::dispatch, & fn18, std::ref( mtx) ); + boost::this_fiber::sleep_for( ms(250) ); + mtx.unlock(); + f.join(); + } +} + +void test_mutex() { + boost::fibers::fiber( boost::fibers::launch::dispatch, & do_test_mutex).join(); +} + +void do_test_recursive_mutex() { + test_lock< boost::fibers::recursive_mutex >()(); + test_exclusive< boost::fibers::recursive_mutex >()(); + test_recursive_lock< boost::fibers::recursive_mutex >()(); + + { + boost::fibers::recursive_mutex mtx; + mtx.lock(); + boost::fibers::fiber f( boost::fibers::launch::dispatch, & fn15, std::ref( mtx) ); + boost::this_fiber::sleep_for( ms(250) ); + mtx.unlock(); + f.join(); + } + + { + boost::fibers::recursive_mutex mtx; + mtx.lock(); + boost::fibers::fiber f( boost::fibers::launch::dispatch, & fn16, std::ref( mtx) ); + boost::this_fiber::sleep_for( ms(250) ); + mtx.unlock(); + f.join(); + } +} + +void test_recursive_mutex() { + boost::fibers::fiber( boost::fibers::launch::dispatch, do_test_recursive_mutex).join(); +} + +void do_test_timed_mutex() { + test_lock< boost::fibers::timed_mutex >()(); + test_exclusive< boost::fibers::timed_mutex >()(); + + { + boost::fibers::timed_mutex timed_mtx; + timed_mtx.lock(); + boost::fibers::fiber f( boost::fibers::launch::dispatch, & fn3, std::ref( timed_mtx) ); + boost::this_fiber::sleep_for( ms(250) ); + timed_mtx.unlock(); + f.join(); + } + + { + boost::fibers::timed_mutex timed_mtx; + timed_mtx.lock(); + boost::fibers::fiber f( boost::fibers::launch::dispatch, & fn4, std::ref( timed_mtx) ); + boost::this_fiber::sleep_for( ms(250) ); + timed_mtx.unlock(); + f.join(); + } + + { + boost::fibers::timed_mutex timed_mtx; + timed_mtx.lock(); + boost::fibers::fiber f( boost::fibers::launch::dispatch, & fn5, std::ref( timed_mtx) ); + boost::this_fiber::sleep_for( ms(250) ); + timed_mtx.unlock(); + f.join(); + } + + { + boost::fibers::timed_mutex timed_mtx; + timed_mtx.lock(); + boost::fibers::fiber f( boost::fibers::launch::dispatch, & fn6, std::ref( timed_mtx) ); + boost::this_fiber::sleep_for( ms(300) ); + timed_mtx.unlock(); + f.join(); + } + + { + boost::fibers::timed_mutex timed_mtx; + timed_mtx.lock(); + boost::fibers::fiber f( boost::fibers::launch::dispatch, & fn7, std::ref( timed_mtx) ); + boost::this_fiber::sleep_for( ms(250) ); + timed_mtx.unlock(); + f.join(); + } + + { + boost::fibers::timed_mutex timed_mtx; + timed_mtx.lock(); + boost::fibers::fiber f( boost::fibers::launch::dispatch, & fn8, std::ref( timed_mtx) ); + boost::this_fiber::sleep_for( ms(300) + ms(1000) ); + timed_mtx.unlock(); + f.join(); + } +} + +void test_timed_mutex() { + boost::fibers::fiber( boost::fibers::launch::dispatch, & do_test_timed_mutex).join(); +} + +void do_test_recursive_timed_mutex() { + test_lock< boost::fibers::recursive_timed_mutex >()(); + test_exclusive< boost::fibers::recursive_timed_mutex >()(); + test_recursive_lock< boost::fibers::recursive_timed_mutex >()(); + + { + boost::fibers::recursive_timed_mutex timed_mtx; + timed_mtx.lock(); + boost::fibers::fiber f( boost::fibers::launch::dispatch, & fn9, std::ref( timed_mtx) ); + boost::this_fiber::sleep_for( ms(250) ); + timed_mtx.unlock(); + f.join(); + } + + { + boost::fibers::recursive_timed_mutex timed_mtx; + timed_mtx.lock(); + boost::fibers::fiber f( boost::fibers::launch::dispatch, & fn10, std::ref( timed_mtx) ); + boost::this_fiber::sleep_for( ms(250) ); + timed_mtx.unlock(); + f.join(); + } + + { + boost::fibers::recursive_timed_mutex timed_mtx; + timed_mtx.lock(); + boost::fibers::fiber f( boost::fibers::launch::dispatch, & fn11, std::ref( timed_mtx) ); + boost::this_fiber::sleep_for( ms(250) ); + timed_mtx.unlock(); + f.join(); + } + + { + boost::fibers::recursive_timed_mutex timed_mtx; + timed_mtx.lock(); + boost::fibers::fiber f( boost::fibers::launch::dispatch, & fn12, std::ref( timed_mtx) ); + boost::this_fiber::sleep_for( ms(400) ); + timed_mtx.unlock(); + f.join(); + } + + { + boost::fibers::recursive_timed_mutex timed_mtx; + timed_mtx.lock(); + boost::fibers::fiber f( boost::fibers::launch::dispatch, & fn13, std::ref( timed_mtx) ); + boost::this_fiber::sleep_for( ms(250) ); + timed_mtx.unlock(); + f.join(); + } + + { + boost::fibers::recursive_timed_mutex timed_mtx; + timed_mtx.lock(); + boost::fibers::fiber f( boost::fibers::launch::dispatch, & fn14, std::ref( timed_mtx) ); + boost::this_fiber::sleep_for( ms(300) ); + timed_mtx.unlock(); + f.join(); + } +} + +void test_recursive_timed_mutex() { + boost::fibers::fiber( boost::fibers::launch::dispatch, & do_test_recursive_timed_mutex).join(); +} + +boost::unit_test::test_suite * init_unit_test_suite( int, char* []) { + boost::unit_test::test_suite * test = + BOOST_TEST_SUITE("Boost.Fiber: mutex test suite"); + + test->add( BOOST_TEST_CASE( & test_mutex) ); + test->add( BOOST_TEST_CASE( & test_recursive_mutex) ); + test->add( BOOST_TEST_CASE( & test_timed_mutex) ); + test->add( BOOST_TEST_CASE( & test_recursive_timed_mutex) ); + + return test; +} diff --git a/src/boost/libs/fiber/test/test_mutex_mt_dispatch.cpp b/src/boost/libs/fiber/test/test_mutex_mt_dispatch.cpp new file mode 100644 index 00000000..2087d17c --- /dev/null +++ b/src/boost/libs/fiber/test/test_mutex_mt_dispatch.cpp @@ -0,0 +1,139 @@ + +// Copyright Oliver Kowalke 2013. +// 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) +// +// This test is based on the tests of Boost.Thread + +#include <cstdlib> +#include <iostream> +#include <map> +#include <stdexcept> +#include <vector> + +#include <boost/chrono.hpp> +#include <boost/test/unit_test.hpp> +#include <boost/thread/barrier.hpp> +#include <boost/thread/thread.hpp> + +#include <boost/fiber/all.hpp> + +typedef boost::chrono::nanoseconds ns; +typedef boost::chrono::milliseconds ms; + +int value1 = 0; +int value2 = 0; + +template< typename Mtx > +void g( boost::barrier & b, Mtx & m) { + b.wait(); + m.lock(); + value1 = 3; + m.unlock(); +} + +template< typename Mtx > +void f( boost::barrier & b, Mtx & m) { + b.wait(); + m.lock(); + value2 = 7; + m.unlock(); +} + +template< typename Mtx > +void fn1( boost::barrier & b, Mtx & m) { + boost::fibers::fiber( boost::fibers::launch::dispatch, g< Mtx >, std::ref( b), std::ref( m) ).join(); +} + +template< typename Mtx > +void fn2( boost::barrier & b, Mtx & m) { + boost::fibers::fiber( boost::fibers::launch::dispatch, f< Mtx >, std::ref( b), std::ref( m) ).join(); +} + +void test_mutex() { + for ( int i = 0; i < 10; ++i) { + boost::fibers::mutex mtx; + mtx.lock(); + boost::barrier b( 3); + boost::thread t1( fn1< boost::fibers::mutex >, std::ref( b), std::ref( mtx) ); + boost::thread t2( fn2< boost::fibers::mutex >, std::ref( b), std::ref( mtx) ); + b.wait(); + boost::this_thread::sleep_for( ms( 250) ); + mtx.unlock(); + t1.join(); + t2.join(); + BOOST_CHECK( 3 == value1); + BOOST_CHECK( 7 == value2); + } +} + +void test_recursive_mutex() { + for ( int i = 0; i < 10; ++i) { + boost::fibers::recursive_mutex mtx; + mtx.lock(); + boost::barrier b( 3); + boost::thread t1( fn1< boost::fibers::recursive_mutex >, std::ref( b), std::ref( mtx) ); + boost::thread t2( fn2< boost::fibers::recursive_mutex >, std::ref( b), std::ref( mtx) ); + b.wait(); + boost::this_thread::sleep_for( ms( 250) ); + mtx.unlock(); + t1.join(); + t2.join(); + BOOST_CHECK( 3 == value1); + BOOST_CHECK( 7 == value2); + } +} + +void test_timed_mutex() { + for ( int i = 0; i < 10; ++i) { + boost::fibers::timed_mutex mtx; + mtx.lock(); + boost::barrier b( 3); + boost::thread t1( fn1< boost::fibers::timed_mutex >, std::ref( b), std::ref( mtx) ); + boost::thread t2( fn2< boost::fibers::timed_mutex >, std::ref( b), std::ref( mtx) ); + b.wait(); + boost::this_thread::sleep_for( ms( 250) ); + mtx.unlock(); + t1.join(); + t2.join(); + BOOST_CHECK( 3 == value1); + BOOST_CHECK( 7 == value2); + } +} + +void test_recursive_timed_mutex() { + for ( int i = 0; i < 10; ++i) { + boost::fibers::recursive_timed_mutex mtx; + mtx.lock(); + boost::barrier b( 3); + boost::thread t1( fn1< boost::fibers::recursive_timed_mutex >, std::ref( b), std::ref( mtx) ); + boost::thread t2( fn2< boost::fibers::recursive_timed_mutex >, std::ref( b), std::ref( mtx) ); + b.wait(); + boost::this_thread::sleep_for( ms( 250) ); + mtx.unlock(); + t1.join(); + t2.join(); + BOOST_CHECK( 3 == value1); + BOOST_CHECK( 7 == value2); + } +} + +void test_dummy() { +} + +boost::unit_test::test_suite * init_unit_test_suite( int, char* []) { + boost::unit_test::test_suite * test = + BOOST_TEST_SUITE("Boost.Fiber: multithreaded mutex test suite"); + +#if ! defined(BOOST_FIBERS_NO_ATOMICS) + test->add( BOOST_TEST_CASE( & test_mutex) ); + test->add( BOOST_TEST_CASE( & test_recursive_mutex) ); + test->add( BOOST_TEST_CASE( & test_timed_mutex) ); + test->add( BOOST_TEST_CASE( & test_recursive_timed_mutex) ); +#else + test->add( BOOST_TEST_CASE( & test_dummy) ); +#endif + + return test; +} diff --git a/src/boost/libs/fiber/test/test_mutex_mt_post.cpp b/src/boost/libs/fiber/test/test_mutex_mt_post.cpp new file mode 100644 index 00000000..758acf9d --- /dev/null +++ b/src/boost/libs/fiber/test/test_mutex_mt_post.cpp @@ -0,0 +1,139 @@ + +// Copyright Oliver Kowalke 2013. +// 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) +// +// This test is based on the tests of Boost.Thread + +#include <cstdlib> +#include <iostream> +#include <map> +#include <stdexcept> +#include <vector> + +#include <boost/chrono.hpp> +#include <boost/test/unit_test.hpp> +#include <boost/thread/barrier.hpp> +#include <boost/thread/thread.hpp> + +#include <boost/fiber/all.hpp> + +typedef boost::chrono::nanoseconds ns; +typedef boost::chrono::milliseconds ms; + +int value1 = 0; +int value2 = 0; + +template< typename Mtx > +void g( boost::barrier & b, Mtx & m) { + b.wait(); + m.lock(); + value1 = 3; + m.unlock(); +} + +template< typename Mtx > +void f( boost::barrier & b, Mtx & m) { + b.wait(); + m.lock(); + value2 = 7; + m.unlock(); +} + +template< typename Mtx > +void fn1( boost::barrier & b, Mtx & m) { + boost::fibers::fiber( boost::fibers::launch::post, g< Mtx >, std::ref( b), std::ref( m) ).join(); +} + +template< typename Mtx > +void fn2( boost::barrier & b, Mtx & m) { + boost::fibers::fiber( boost::fibers::launch::post, f< Mtx >, std::ref( b), std::ref( m) ).join(); +} + +void test_mutex() { + for ( int i = 0; i < 10; ++i) { + boost::fibers::mutex mtx; + mtx.lock(); + boost::barrier b( 3); + boost::thread t1( fn1< boost::fibers::mutex >, std::ref( b), std::ref( mtx) ); + boost::thread t2( fn2< boost::fibers::mutex >, std::ref( b), std::ref( mtx) ); + b.wait(); + boost::this_thread::sleep_for( ms( 250) ); + mtx.unlock(); + t1.join(); + t2.join(); + BOOST_CHECK( 3 == value1); + BOOST_CHECK( 7 == value2); + } +} + +void test_recursive_mutex() { + for ( int i = 0; i < 10; ++i) { + boost::fibers::recursive_mutex mtx; + mtx.lock(); + boost::barrier b( 3); + boost::thread t1( fn1< boost::fibers::recursive_mutex >, std::ref( b), std::ref( mtx) ); + boost::thread t2( fn2< boost::fibers::recursive_mutex >, std::ref( b), std::ref( mtx) ); + b.wait(); + boost::this_thread::sleep_for( ms( 250) ); + mtx.unlock(); + t1.join(); + t2.join(); + BOOST_CHECK( 3 == value1); + BOOST_CHECK( 7 == value2); + } +} + +void test_timed_mutex() { + for ( int i = 0; i < 10; ++i) { + boost::fibers::timed_mutex mtx; + mtx.lock(); + boost::barrier b( 3); + boost::thread t1( fn1< boost::fibers::timed_mutex >, std::ref( b), std::ref( mtx) ); + boost::thread t2( fn2< boost::fibers::timed_mutex >, std::ref( b), std::ref( mtx) ); + b.wait(); + boost::this_thread::sleep_for( ms( 250) ); + mtx.unlock(); + t1.join(); + t2.join(); + BOOST_CHECK( 3 == value1); + BOOST_CHECK( 7 == value2); + } +} + +void test_recursive_timed_mutex() { + for ( int i = 0; i < 10; ++i) { + boost::fibers::recursive_timed_mutex mtx; + mtx.lock(); + boost::barrier b( 3); + boost::thread t1( fn1< boost::fibers::recursive_timed_mutex >, std::ref( b), std::ref( mtx) ); + boost::thread t2( fn2< boost::fibers::recursive_timed_mutex >, std::ref( b), std::ref( mtx) ); + b.wait(); + boost::this_thread::sleep_for( ms( 250) ); + mtx.unlock(); + t1.join(); + t2.join(); + BOOST_CHECK( 3 == value1); + BOOST_CHECK( 7 == value2); + } +} + +void test_dummy() { +} + +boost::unit_test::test_suite * init_unit_test_suite( int, char* []) { + boost::unit_test::test_suite * test = + BOOST_TEST_SUITE("Boost.Fiber: multithreaded mutex test suite"); + +#if ! defined(BOOST_FIBERS_NO_ATOMICS) + test->add( BOOST_TEST_CASE( & test_mutex) ); + test->add( BOOST_TEST_CASE( & test_recursive_mutex) ); + test->add( BOOST_TEST_CASE( & test_timed_mutex) ); + test->add( BOOST_TEST_CASE( & test_recursive_timed_mutex) ); +#else + test->add( BOOST_TEST_CASE( & test_dummy) ); +#endif + + return test; +} diff --git a/src/boost/libs/fiber/test/test_mutex_post.cpp b/src/boost/libs/fiber/test/test_mutex_post.cpp new file mode 100644 index 00000000..f88a571f --- /dev/null +++ b/src/boost/libs/fiber/test/test_mutex_post.cpp @@ -0,0 +1,447 @@ + +// Copyright Oliver Kowalke 2013. +// 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) +// +// This test is based on the tests of Boost.Thread + +#include <chrono> +#include <cstdlib> +#include <iostream> +#include <map> +#include <mutex> +#include <stdexcept> +#include <vector> + +#include <boost/test/unit_test.hpp> + +#include <boost/fiber/all.hpp> + +typedef std::chrono::nanoseconds ns; +typedef std::chrono::milliseconds ms; + +int value1 = 0; +int value2 = 0; + +template< typename M > +void fn1( M & mtx) { + typedef M mutex_type; + typename std::unique_lock< mutex_type > lk( mtx); + ++value1; + for ( int i = 0; i < 3; ++i) + boost::this_fiber::yield(); +} + +template< typename M > +void fn2( M & mtx) { + typedef M mutex_type; + ++value2; + typename std::unique_lock< mutex_type > lk( mtx); + ++value2; +} + +void fn3( boost::fibers::timed_mutex & m) { + std::chrono::steady_clock::time_point t0 = std::chrono::steady_clock::now(); + m.lock(); + std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now(); + m.unlock(); + ns d = t1 - t0 - ms(250); + BOOST_CHECK(d < ns(2500000)+ms(2000)); // within 2.5 ms +} + +void fn4( boost::fibers::timed_mutex & m) { + std::chrono::steady_clock::time_point t0 = std::chrono::steady_clock::now(); + while ( ! m.try_lock() ); + std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now(); + m.unlock(); + ns d = t1 - t0 - ms(250); + BOOST_CHECK(d < ns(50000000)+ms(2000)); // within 50 ms +} + +void fn5( boost::fibers::timed_mutex & m) { + std::chrono::steady_clock::time_point t0 = std::chrono::steady_clock::now(); + BOOST_CHECK( m.try_lock_for(ms(300)+ms(2000)) == true); + std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now(); + m.unlock(); + ns d = t1 - t0 - ms(250); + BOOST_CHECK(d < ns(5000000)+ms(2000)); // within 5 ms +} + +void fn6( boost::fibers::timed_mutex & m) { + std::chrono::steady_clock::time_point t0 = std::chrono::steady_clock::now(); + BOOST_CHECK(m.try_lock_for(ms(250)) == false); + std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now(); + ns d = t1 - t0 - ms(250); + BOOST_CHECK(d < ns(5000000)+ms(2000)); // within 5 ms +} + +void fn7( boost::fibers::timed_mutex & m) { + std::chrono::steady_clock::time_point t0 = std::chrono::steady_clock::now(); + BOOST_CHECK(m.try_lock_until(std::chrono::steady_clock::now() + ms(300) + ms(1000)) == true); + std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now(); + m.unlock(); + ns d = t1 - t0 - ms(250); + BOOST_CHECK(d < ns(5000000)+ms(2000)); // within 5ms +} + +void fn8( boost::fibers::timed_mutex & m) { + std::chrono::steady_clock::time_point t0 = std::chrono::steady_clock::now(); + BOOST_CHECK(m.try_lock_until(std::chrono::steady_clock::now() + ms(250)) == false); + std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now(); + ns d = t1 - t0 - ms(250); + ns r = ns(5000000)+ms(2000); // within 6ms + BOOST_CHECK(d < r); // within 6ms +} + +void fn9( boost::fibers::recursive_timed_mutex & m) { + std::chrono::steady_clock::time_point t0 = std::chrono::steady_clock::now(); + m.lock(); + std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now(); + m.lock(); + m.unlock(); + m.unlock(); + ns d = t1 - t0 - ms(250); + BOOST_CHECK(d < ms(2500)+ms(2000)); // within 2.5 ms +} + +void fn10( boost::fibers::recursive_timed_mutex & m) { + std::chrono::steady_clock::time_point t0 = std::chrono::steady_clock::now(); + while (!m.try_lock()) ; + std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now(); + BOOST_CHECK(m.try_lock()); + m.unlock(); + m.unlock(); + ns d = t1 - t0 - ms(250); + BOOST_CHECK(d < ns(50000000)+ms(2000)); // within 50 ms +} + +void fn11( boost::fibers::recursive_timed_mutex & m) { + std::chrono::steady_clock::time_point t0 = std::chrono::steady_clock::now(); + BOOST_CHECK(m.try_lock_for(ms(300)+ms(1000)) == true); + std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now(); + BOOST_CHECK(m.try_lock()); + m.unlock(); + m.unlock(); + ns d = t1 - t0 - ms(250); + BOOST_CHECK(d < ns(5000000)+ms(2000)); // within 5 ms +} + +void fn12( boost::fibers::recursive_timed_mutex & m) { + std::chrono::steady_clock::time_point t0 = std::chrono::steady_clock::now(); + BOOST_CHECK(m.try_lock_for(ms(250)) == false); + std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now(); + ns d = t1 - t0 - ms(250); + BOOST_CHECK(d < ms(5000)+ms(2000)); // within 5 ms +} + +void fn13( boost::fibers::recursive_timed_mutex & m) { + std::chrono::steady_clock::time_point t0 = std::chrono::steady_clock::now(); + BOOST_CHECK(m.try_lock_until(std::chrono::steady_clock::now() + ms(300) + ms(1000)) == true); + std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now(); + m.unlock(); + ns d = t1 - t0 - ms(250); + BOOST_CHECK(d < ns(5000000)+ms(2000)); // within 5 ms +} + +void fn14( boost::fibers::recursive_timed_mutex & m) { + std::chrono::steady_clock::time_point t0 = std::chrono::steady_clock::now(); + BOOST_CHECK(m.try_lock_until(std::chrono::steady_clock::now() + ms(250)) == false); + std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now(); + ns d = t1 - t0 - ms(250); + BOOST_CHECK(d < ns(5000000)+ms(2000)); // within 5 ms +} + +void fn15( boost::fibers::recursive_mutex & m) { + std::chrono::steady_clock::time_point t0 = std::chrono::steady_clock::now(); + m.lock(); + std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now(); + m.lock(); + m.unlock(); + m.unlock(); + ns d = t1 - t0 - ms(250); + BOOST_CHECK(d < ns(2500000)+ms(2000)); // within 2.5 ms +} + +void fn16( boost::fibers::recursive_mutex & m) { + std::chrono::steady_clock::time_point t0 = std::chrono::steady_clock::now(); + while (!m.try_lock()); + std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now(); + BOOST_CHECK(m.try_lock()); + m.unlock(); + m.unlock(); + ns d = t1 - t0 - ms(250); + BOOST_CHECK(d < ns(50000000)+ms(2000)); // within 50 ms +} + +void fn17( boost::fibers::mutex & m) { + std::chrono::steady_clock::time_point t0 = std::chrono::steady_clock::now(); + m.lock(); + std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now(); + m.unlock(); + ns d = t1 - t0 - ms(250); + BOOST_CHECK(d < ns(2500000)+ms(2000)); // within 2.5 ms +} + +void fn18( boost::fibers::mutex & m) { + std::chrono::steady_clock::time_point t0 = std::chrono::steady_clock::now(); + while (!m.try_lock()) ; + std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now(); + m.unlock(); + ns d = t1 - t0 - ms(250); + BOOST_CHECK(d < ns(50000000)+ms(2000)); // within 50 ms +} + +template< typename M > +struct test_lock { + typedef M mutex_type; + typedef typename std::unique_lock< M > lock_type; + + void operator()() { + mutex_type mtx; + + // Test the lock's constructors. + { + lock_type lk(mtx, std::defer_lock); + BOOST_CHECK(!lk); + } + lock_type lk(mtx); + BOOST_CHECK(lk ? true : false); + + // Test the lock and unlock methods. + lk.unlock(); + BOOST_CHECK(!lk); + lk.lock(); + BOOST_CHECK(lk ? true : false); + } +}; + +template< typename M > +struct test_exclusive { + typedef M mutex_type; + typedef typename std::unique_lock< M > lock_type; + + void operator()() { + value1 = 0; + value2 = 0; + BOOST_CHECK_EQUAL( 0, value1); + BOOST_CHECK_EQUAL( 0, value2); + + mutex_type mtx; + boost::fibers::fiber f1( boost::fibers::launch::post, & fn1< mutex_type >, std::ref( mtx) ); + boost::fibers::fiber f2( boost::fibers::launch::post, & fn2< mutex_type >, std::ref( mtx) ); + BOOST_ASSERT( f1.joinable() ); + BOOST_ASSERT( f2.joinable() ); + + f1.join(); + f2.join(); + BOOST_CHECK_EQUAL( 1, value1); + BOOST_CHECK_EQUAL( 2, value2); + } +}; + +template< typename M > +struct test_recursive_lock { + typedef M mutex_type; + typedef typename std::unique_lock< M > lock_type; + + void operator()() { + mutex_type mx; + lock_type lock1(mx); + lock_type lock2(mx); + } +}; + +void do_test_mutex() { + test_lock< boost::fibers::mutex >()(); + test_exclusive< boost::fibers::mutex >()(); + + { + boost::fibers::mutex mtx; + mtx.lock(); + boost::fibers::fiber f( boost::fibers::launch::post, & fn17, std::ref( mtx) ); + boost::this_fiber::sleep_for( ms(250) ); + mtx.unlock(); + f.join(); + } + + { + boost::fibers::mutex mtx; + mtx.lock(); + boost::fibers::fiber f( boost::fibers::launch::post, & fn18, std::ref( mtx) ); + boost::this_fiber::sleep_for( ms(250) ); + mtx.unlock(); + f.join(); + } +} + +void test_mutex() { + boost::fibers::fiber( boost::fibers::launch::post, & do_test_mutex).join(); +} + +void do_test_recursive_mutex() { + test_lock< boost::fibers::recursive_mutex >()(); + test_exclusive< boost::fibers::recursive_mutex >()(); + test_recursive_lock< boost::fibers::recursive_mutex >()(); + + { + boost::fibers::recursive_mutex mtx; + mtx.lock(); + boost::fibers::fiber f( boost::fibers::launch::post, & fn15, std::ref( mtx) ); + boost::this_fiber::sleep_for( ms(250) ); + mtx.unlock(); + f.join(); + } + + { + boost::fibers::recursive_mutex mtx; + mtx.lock(); + boost::fibers::fiber f( boost::fibers::launch::post, & fn16, std::ref( mtx) ); + boost::this_fiber::sleep_for( ms(250) ); + mtx.unlock(); + f.join(); + } +} + +void test_recursive_mutex() { + boost::fibers::fiber( boost::fibers::launch::post, do_test_recursive_mutex).join(); +} + +void do_test_timed_mutex() { + test_lock< boost::fibers::timed_mutex >()(); + test_exclusive< boost::fibers::timed_mutex >()(); + + { + boost::fibers::timed_mutex timed_mtx; + timed_mtx.lock(); + boost::fibers::fiber f( boost::fibers::launch::post, & fn3, std::ref( timed_mtx) ); + boost::this_fiber::sleep_for( ms(250) ); + timed_mtx.unlock(); + f.join(); + } + + { + boost::fibers::timed_mutex timed_mtx; + timed_mtx.lock(); + boost::fibers::fiber f( boost::fibers::launch::post, & fn4, std::ref( timed_mtx) ); + boost::this_fiber::sleep_for( ms(250) ); + timed_mtx.unlock(); + f.join(); + } + + { + boost::fibers::timed_mutex timed_mtx; + timed_mtx.lock(); + boost::fibers::fiber f( boost::fibers::launch::post, & fn5, std::ref( timed_mtx) ); + boost::this_fiber::sleep_for( ms(250) ); + timed_mtx.unlock(); + f.join(); + } + + { + boost::fibers::timed_mutex timed_mtx; + timed_mtx.lock(); + boost::fibers::fiber f( boost::fibers::launch::post, & fn6, std::ref( timed_mtx) ); + boost::this_fiber::sleep_for( ms(300) ); + timed_mtx.unlock(); + f.join(); + } + + { + boost::fibers::timed_mutex timed_mtx; + timed_mtx.lock(); + boost::fibers::fiber f( boost::fibers::launch::post, & fn7, std::ref( timed_mtx) ); + boost::this_fiber::sleep_for( ms(250) ); + timed_mtx.unlock(); + f.join(); + } + + { + boost::fibers::timed_mutex timed_mtx; + timed_mtx.lock(); + boost::fibers::fiber f( boost::fibers::launch::post, & fn8, std::ref( timed_mtx) ); + boost::this_fiber::sleep_for( ms(300) + ms(1000) ); + timed_mtx.unlock(); + f.join(); + } +} + +void test_timed_mutex() { + boost::fibers::fiber( boost::fibers::launch::post, & do_test_timed_mutex).join(); +} + +void do_test_recursive_timed_mutex() { + test_lock< boost::fibers::recursive_timed_mutex >()(); + test_exclusive< boost::fibers::recursive_timed_mutex >()(); + test_recursive_lock< boost::fibers::recursive_timed_mutex >()(); + + { + boost::fibers::recursive_timed_mutex timed_mtx; + timed_mtx.lock(); + boost::fibers::fiber f( boost::fibers::launch::post, & fn9, std::ref( timed_mtx) ); + boost::this_fiber::sleep_for( ms(250) ); + timed_mtx.unlock(); + f.join(); + } + + { + boost::fibers::recursive_timed_mutex timed_mtx; + timed_mtx.lock(); + boost::fibers::fiber f( boost::fibers::launch::post, & fn10, std::ref( timed_mtx) ); + boost::this_fiber::sleep_for( ms(250) ); + timed_mtx.unlock(); + f.join(); + } + + { + boost::fibers::recursive_timed_mutex timed_mtx; + timed_mtx.lock(); + boost::fibers::fiber f( boost::fibers::launch::post, & fn11, std::ref( timed_mtx) ); + boost::this_fiber::sleep_for( ms(250) ); + timed_mtx.unlock(); + f.join(); + } + + { + boost::fibers::recursive_timed_mutex timed_mtx; + timed_mtx.lock(); + boost::fibers::fiber f( boost::fibers::launch::post, & fn12, std::ref( timed_mtx) ); + boost::this_fiber::sleep_for( ms(400) ); + timed_mtx.unlock(); + f.join(); + } + + { + boost::fibers::recursive_timed_mutex timed_mtx; + timed_mtx.lock(); + boost::fibers::fiber f( boost::fibers::launch::post, & fn13, std::ref( timed_mtx) ); + boost::this_fiber::sleep_for( ms(250) ); + timed_mtx.unlock(); + f.join(); + } + + { + boost::fibers::recursive_timed_mutex timed_mtx; + timed_mtx.lock(); + boost::fibers::fiber f( boost::fibers::launch::post, & fn14, std::ref( timed_mtx) ); + boost::this_fiber::sleep_for( ms(300) ); + timed_mtx.unlock(); + f.join(); + } +} + +void test_recursive_timed_mutex() { + boost::fibers::fiber( boost::fibers::launch::post, & do_test_recursive_timed_mutex).join(); +} + +boost::unit_test::test_suite * init_unit_test_suite( int, char* []) { + boost::unit_test::test_suite * test = + BOOST_TEST_SUITE("Boost.Fiber: mutex test suite"); + + test->add( BOOST_TEST_CASE( & test_mutex) ); + test->add( BOOST_TEST_CASE( & test_recursive_mutex) ); + test->add( BOOST_TEST_CASE( & test_timed_mutex) ); + test->add( BOOST_TEST_CASE( & test_recursive_timed_mutex) ); + + return test; +} diff --git a/src/boost/libs/fiber/test/test_packaged_task_dispatch.cpp b/src/boost/libs/fiber/test/test_packaged_task_dispatch.cpp new file mode 100644 index 00000000..36475583 --- /dev/null +++ b/src/boost/libs/fiber/test/test_packaged_task_dispatch.cpp @@ -0,0 +1,679 @@ +// (C) Copyright 2008-10 Anthony Williams +// +// 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) + +#include <utility> +#include <memory> +#include <stdexcept> +#include <string> + +#include <boost/test/unit_test.hpp> + +#include <boost/fiber/all.hpp> + +int gi = 7; + +struct my_exception : public std::runtime_error { + my_exception() : + std::runtime_error("my_exception") { + } +}; + +struct A { + A() = default; + + A( A const&) = delete; + A( A &&) = default; + + A & operator=( A const&) = delete; + A & operator=( A &&) = default; + + int value; +}; + +struct B { + bool bset{ false }; + + B() = default; + + B( bool set) : + bset{ set } { + gi = 3; + } + + ~B() { + if ( bset) { + gi = -1; + } + } + + B( B && other) : + bset{ other.bset } { + other.bset = false; + } + + B & operator=( B && other) { + if ( this == & other) return * this; + bset = other.bset; + other.bset = false; + return * this; + } + + B( B const&) = delete; + B & operator=( B const&) = delete; +}; + +void fn1( boost::fibers::promise< int > * p, int i) { + boost::this_fiber::yield(); + p->set_value( i); +} + +void fn2() { + boost::fibers::promise< int > p; + boost::fibers::future< int > f( p.get_future() ); + boost::this_fiber::yield(); + boost::fibers::fiber( boost::fibers::launch::dispatch, fn1, & p, 7).detach(); + boost::this_fiber::yield(); + BOOST_CHECK( 7 == f.get() ); +} + +int fn3() { + return 3; +} + +void fn4() { +} + +int fn5() { + boost::throw_exception( my_exception() ); + return 3; +} + +void fn6() { + boost::throw_exception( my_exception() ); +} + +int & fn7() { + return gi; +} + +int fn8( int i) { + return i; +} + +A fn9() { + A a; + a.value = 3; + return a; +} + +A fn10() { + boost::throw_exception( my_exception() ); + return A(); +} + +B fn11( bool set) { + B b( set); + return b; +} + +// packaged_task +void test_packaged_task_create() { + // default constructed packaged_task is not valid + boost::fibers::packaged_task< int() > t1; + BOOST_CHECK( ! t1.valid() ); + + // packaged_task from function + boost::fibers::packaged_task< int() > t2( fn3); + BOOST_CHECK( t2.valid() ); +} + +// packaged_task +void test_packaged_task_create_move() { + // default constructed packaged_task is not valid + boost::fibers::packaged_task< A() > t1; + BOOST_CHECK( ! t1.valid() ); + + // packaged_task from function + boost::fibers::packaged_task< A() > t2( fn9); + BOOST_CHECK( t2.valid() ); +} + +void test_packaged_task_create_void() { + // default constructed packaged_task is not valid + boost::fibers::packaged_task< void() > t1; + BOOST_CHECK( ! t1.valid() ); + + // packaged_task from function + boost::fibers::packaged_task< void() > t2( fn4); + BOOST_CHECK( t2.valid() ); +} + +void test_packaged_task_move() { + boost::fibers::packaged_task< int() > t1( fn3); + BOOST_CHECK( t1.valid() ); + + // move construction + boost::fibers::packaged_task< int() > t2( std::move( t1) ); + BOOST_CHECK( ! t1.valid() ); + BOOST_CHECK( t2.valid() ); + + // move assignment + t1 = std::move( t2); + BOOST_CHECK( t1.valid() ); + BOOST_CHECK( ! t2.valid() ); +} + +void test_packaged_task_move_move() { + boost::fibers::packaged_task< A() > t1( fn9); + BOOST_CHECK( t1.valid() ); + + // move construction + boost::fibers::packaged_task< A() > t2( std::move( t1) ); + BOOST_CHECK( ! t1.valid() ); + BOOST_CHECK( t2.valid() ); + + // move assignment + t1 = std::move( t2); + BOOST_CHECK( t1.valid() ); + BOOST_CHECK( ! t2.valid() ); +} + +void test_packaged_task_move_void() { + boost::fibers::packaged_task< void() > t1( fn4); + BOOST_CHECK( t1.valid() ); + + // move construction + boost::fibers::packaged_task< void() > t2( std::move( t1) ); + BOOST_CHECK( ! t1.valid() ); + BOOST_CHECK( t2.valid() ); + + // move assignment + t1 = std::move( t2); + BOOST_CHECK( t1.valid() ); + BOOST_CHECK( ! t2.valid() ); +} + +void test_packaged_task_swap() { + boost::fibers::packaged_task< int() > t1( fn3); + BOOST_CHECK( t1.valid() ); + + boost::fibers::packaged_task< int() > t2; + BOOST_CHECK( ! t2.valid() ); + + // swap + t1.swap( t2); + BOOST_CHECK( ! t1.valid() ); + BOOST_CHECK( t2.valid() ); +} + +void test_packaged_task_swap_move() { + boost::fibers::packaged_task< A() > t1( fn9); + BOOST_CHECK( t1.valid() ); + + boost::fibers::packaged_task< A() > t2; + BOOST_CHECK( ! t2.valid() ); + + // swap + t1.swap( t2); + BOOST_CHECK( ! t1.valid() ); + BOOST_CHECK( t2.valid() ); +} + +void test_packaged_task_swap_void() { + boost::fibers::packaged_task< void() > t1( fn4); + BOOST_CHECK( t1.valid() ); + + boost::fibers::packaged_task< void() > t2; + BOOST_CHECK( ! t2.valid() ); + + // swap + t1.swap( t2); + BOOST_CHECK( ! t1.valid() ); + BOOST_CHECK( t2.valid() ); +} + +void test_packaged_task_reset() { + { + boost::fibers::packaged_task< int() > p( fn3); + boost::fibers::future< int > f( p.get_future() ); + BOOST_CHECK( p.valid() ); + + p(); + BOOST_CHECK( 3 == f.get() ); + + // reset + p.reset(); + p(); + f = p.get_future(); + BOOST_CHECK( 3 == f.get() ); + } + { + boost::fibers::packaged_task< int() > p; + + bool thrown = false; + try { + p.reset(); + } catch ( boost::fibers::packaged_task_uninitialized const&) { + thrown = true; + } + BOOST_CHECK( thrown); + } +} + +void test_packaged_task_reset_destruction() { + gi = 0; + boost::fibers::packaged_task< B( bool) > p( fn11); + BOOST_CHECK( p.valid() ); + + BOOST_CHECK( 0 == gi); + p( true); + BOOST_CHECK( 3 == gi); + + // reset + p.reset(); + BOOST_CHECK( -1 == gi); + p( false); + BOOST_CHECK( 3 == gi); + + // reset + p.reset(); + BOOST_CHECK( 3 == gi); +} + +void test_packaged_task_reset_move() { + { + boost::fibers::packaged_task< A() > p( fn9); + boost::fibers::future< A > f( p.get_future() ); + BOOST_CHECK( p.valid() ); + + p(); + BOOST_CHECK( 3 == f.get().value); + + // reset + p.reset(); + p(); + f = p.get_future(); + BOOST_CHECK( 3 == f.get().value); + } + { + boost::fibers::packaged_task< A() > p; + + bool thrown = false; + try { + p.reset(); + } catch ( boost::fibers::packaged_task_uninitialized const&) { + thrown = true; + } + BOOST_CHECK( thrown); + } +} + +void test_packaged_task_reset_void() { + { + boost::fibers::packaged_task< void() > p( fn4); + boost::fibers::future< void > f( p.get_future() ); + BOOST_CHECK( p.valid() ); + + p(); + f.get(); + + // reset + p.reset(); + p(); + f = p.get_future(); + f.get(); + } + { + boost::fibers::packaged_task< void() > p; + + bool thrown = false; + try { + p.reset(); + } catch ( boost::fibers::packaged_task_uninitialized const&) { + thrown = true; + } + BOOST_CHECK( thrown); + } +} + +void test_packaged_task_get_future() { + boost::fibers::packaged_task< int() > t1( fn3); + BOOST_CHECK( t1.valid() ); + + // retrieve future + boost::fibers::future< int > f1 = t1.get_future(); + BOOST_CHECK( f1.valid() ); + + // retrieve future a second time + bool thrown = false; + try { + f1 = t1.get_future(); + } catch ( boost::fibers::future_already_retrieved const&) { + thrown = true; + } + BOOST_CHECK( thrown); + + // move construction + boost::fibers::packaged_task< int() > t2( std::move( t1) ); + BOOST_CHECK( ! t1.valid() ); + BOOST_CHECK( t2.valid() ); + + // retrieve future from uninitialized + thrown = false; + try { + f1 = t1.get_future(); + } catch ( boost::fibers::packaged_task_uninitialized const&) { + thrown = true; + } + BOOST_CHECK( thrown); +} + +void test_packaged_task_get_future_move() { + boost::fibers::packaged_task< A() > t1( fn9); + BOOST_CHECK( t1.valid() ); + + // retrieve future + boost::fibers::future< A > f1 = t1.get_future(); + BOOST_CHECK( f1.valid() ); + + // retrieve future a second time + bool thrown = false; + try { + f1 = t1.get_future(); + } catch ( boost::fibers::future_already_retrieved const&) { + thrown = true; + } + BOOST_CHECK( thrown); + + // move construction + boost::fibers::packaged_task< A() > t2( std::move( t1) ); + BOOST_CHECK( ! t1.valid() ); + BOOST_CHECK( t2.valid() ); + + // retrieve future from uninitialized + thrown = false; + try { + f1 = t1.get_future(); + } catch ( boost::fibers::packaged_task_uninitialized const&) { + thrown = true; + } + BOOST_CHECK( thrown); +} + +void test_packaged_task_get_future_void() { + boost::fibers::packaged_task< void() > t1( fn4); + BOOST_CHECK( t1.valid() ); + + // retrieve future + boost::fibers::future< void > f1 = t1.get_future(); + BOOST_CHECK( f1.valid() ); + + // retrieve future a second time + bool thrown = false; + try { + f1 = t1.get_future(); + } catch ( boost::fibers::future_already_retrieved const&) { + thrown = true; + } + BOOST_CHECK( thrown); + + // move construction + boost::fibers::packaged_task< void() > t2( std::move( t1) ); + BOOST_CHECK( ! t1.valid() ); + BOOST_CHECK( t2.valid() ); + + // retrieve future from uninitialized + thrown = false; + try { + f1 = t1.get_future(); + } catch ( boost::fibers::packaged_task_uninitialized const&) { + thrown = true; + } + BOOST_CHECK( thrown); +} + +void test_packaged_task_exec() { + // promise takes a copyable as return type + boost::fibers::packaged_task< int() > t1( fn3); + BOOST_CHECK( t1.valid() ); + boost::fibers::future< int > f1 = t1.get_future(); + BOOST_CHECK( f1.valid() ); + + // exec + t1(); + BOOST_CHECK( 3 == f1.get() ); + + // exec a second time + bool thrown = false; + try { + t1(); + } catch ( boost::fibers::promise_already_satisfied const&) { + thrown = true; + } + BOOST_CHECK( thrown); +} + +void test_packaged_task_exec_move() { + // promise takes a copyable as return type + boost::fibers::packaged_task< A() > t1( fn9); + BOOST_CHECK( t1.valid() ); + boost::fibers::future< A > f1 = t1.get_future(); + BOOST_CHECK( f1.valid() ); + + // exec + t1(); + BOOST_CHECK( 3 == f1.get().value); + + // exec a second time + bool thrown = false; + try { + t1(); + } catch ( boost::fibers::promise_already_satisfied const&) { + thrown = true; + } + BOOST_CHECK( thrown); +} + +void test_packaged_task_exec_param() { + // promise takes a copyable as return type + boost::fibers::packaged_task< int( int) > t1( fn8); + BOOST_CHECK( t1.valid() ); + boost::fibers::future< int > f1 = t1.get_future(); + BOOST_CHECK( f1.valid() ); + + // exec + t1( 3); + BOOST_CHECK( 3 == f1.get() ); + + // exec a second time + bool thrown = false; + try { + t1( 7); + } catch ( boost::fibers::promise_already_satisfied const&) { + thrown = true; + } + BOOST_CHECK( thrown); + + //TODO: packaged_task returns a moveable-only as return type +} + +void test_packaged_task_exec_ref() { + // promise takes a copyable as return type + boost::fibers::packaged_task< int&() > t1( fn7); + BOOST_CHECK( t1.valid() ); + boost::fibers::future< int& > f1 = t1.get_future(); + BOOST_CHECK( f1.valid() ); + + // exec + t1(); + int & i = f1.get(); + BOOST_CHECK( &gi == &i); + + // exec a second time + bool thrown = false; + try { + t1(); + } catch ( boost::fibers::promise_already_satisfied const&) { + thrown = true; + } + BOOST_CHECK( thrown); + + //TODO: packaged_task returns a moveable-only as return type +} + +void test_packaged_task_exec_void() { + // promise takes a copyable as return type + boost::fibers::packaged_task< void() > t1( fn4); + BOOST_CHECK( t1.valid() ); + boost::fibers::future< void > f1 = t1.get_future(); + BOOST_CHECK( f1.valid() ); + + // set void + t1(); + f1.get(); + + // exec a second time + bool thrown = false; + try { + t1(); + } catch ( boost::fibers::promise_already_satisfied const&) { + thrown = true; + } + BOOST_CHECK( thrown); +} + +void test_packaged_task_exception() { + // promise takes a copyable as return type + boost::fibers::packaged_task< int() > t1( fn5); + BOOST_CHECK( t1.valid() ); + boost::fibers::future< int > f1 = t1.get_future(); + BOOST_CHECK( f1.valid() ); + + // exec + t1(); + bool thrown = false; + try { + f1.get(); + } catch ( my_exception const&) { + thrown = true; + } + BOOST_CHECK( thrown); + + boost::fibers::packaged_task< int() > t2( fn5); + BOOST_CHECK( t2.valid() ); + boost::fibers::future< int > f2 = t2.get_future(); + BOOST_CHECK( f2.valid() ); + + // exec + t2(); + BOOST_CHECK( f2.get_exception_ptr() ); + thrown = false; + try + { std::rethrow_exception( f2.get_exception_ptr() ); } + catch ( my_exception const&) + { thrown = true; } + BOOST_CHECK( thrown); +} + +void test_packaged_task_exception_move() { + // promise takes a moveable as return type + boost::fibers::packaged_task< A() > t1( fn10); + BOOST_CHECK( t1.valid() ); + boost::fibers::future< A > f1 = t1.get_future(); + BOOST_CHECK( f1.valid() ); + + // exec + t1(); + bool thrown = false; + try { + f1.get(); + } catch ( my_exception const&) { + thrown = true; + } + BOOST_CHECK( thrown); + + boost::fibers::packaged_task< A() > t2( fn10); + BOOST_CHECK( t2.valid() ); + boost::fibers::future< A > f2 = t2.get_future(); + BOOST_CHECK( f2.valid() ); + + // exec + t2(); + BOOST_CHECK( f2.get_exception_ptr() ); + thrown = false; + try + { std::rethrow_exception( f2.get_exception_ptr() ); } + catch ( my_exception const&) + { thrown = true; } + BOOST_CHECK( thrown); +} + +void test_packaged_task_exception_void() { + // promise takes a copyable as return type + boost::fibers::packaged_task< void() > t1( fn6); + BOOST_CHECK( t1.valid() ); + boost::fibers::future< void > f1 = t1.get_future(); + BOOST_CHECK( f1.valid() ); + + // set void + t1(); + bool thrown = false; + try { + f1.get(); + } catch ( my_exception const&) { + thrown = true; + } + BOOST_CHECK( thrown); + + boost::fibers::packaged_task< void() > t2( fn6); + BOOST_CHECK( t2.valid() ); + boost::fibers::future< void > f2 = t2.get_future(); + BOOST_CHECK( f2.valid() ); + + // exec + t2(); + BOOST_CHECK( f2.get_exception_ptr() ); + thrown = false; + try { + std::rethrow_exception( f2.get_exception_ptr() ); + } catch ( my_exception const&) { + thrown = true; + } + BOOST_CHECK( thrown); +} + + +boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[]) { + boost::unit_test_framework::test_suite* test = + BOOST_TEST_SUITE("Boost.Fiber: packaged_task test suite"); + + test->add(BOOST_TEST_CASE(test_packaged_task_create)); + test->add(BOOST_TEST_CASE(test_packaged_task_create_move)); + test->add(BOOST_TEST_CASE(test_packaged_task_create_void)); + test->add(BOOST_TEST_CASE(test_packaged_task_move)); + test->add(BOOST_TEST_CASE(test_packaged_task_move_move)); + test->add(BOOST_TEST_CASE(test_packaged_task_move_void)); + test->add(BOOST_TEST_CASE(test_packaged_task_swap)); + test->add(BOOST_TEST_CASE(test_packaged_task_swap_move)); + test->add(BOOST_TEST_CASE(test_packaged_task_swap_void)); + test->add(BOOST_TEST_CASE(test_packaged_task_reset)); + test->add(BOOST_TEST_CASE(test_packaged_task_reset_destruction)); + test->add(BOOST_TEST_CASE(test_packaged_task_reset_move)); + test->add(BOOST_TEST_CASE(test_packaged_task_reset_void)); + test->add(BOOST_TEST_CASE(test_packaged_task_get_future)); + test->add(BOOST_TEST_CASE(test_packaged_task_get_future_move)); + test->add(BOOST_TEST_CASE(test_packaged_task_get_future_void)); + test->add(BOOST_TEST_CASE(test_packaged_task_exec)); + test->add(BOOST_TEST_CASE(test_packaged_task_exec_move)); + test->add(BOOST_TEST_CASE(test_packaged_task_exec_param)); + test->add(BOOST_TEST_CASE(test_packaged_task_exec_ref)); + test->add(BOOST_TEST_CASE(test_packaged_task_exec_void)); + test->add(BOOST_TEST_CASE(test_packaged_task_exception)); + test->add(BOOST_TEST_CASE(test_packaged_task_exception_move)); + test->add(BOOST_TEST_CASE(test_packaged_task_exception_void)); + + return test; +} diff --git a/src/boost/libs/fiber/test/test_packaged_task_post.cpp b/src/boost/libs/fiber/test/test_packaged_task_post.cpp new file mode 100644 index 00000000..53c42d85 --- /dev/null +++ b/src/boost/libs/fiber/test/test_packaged_task_post.cpp @@ -0,0 +1,679 @@ +// (C) Copyright 2008-10 Anthony Williams +// +// 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) + +#include <utility> +#include <memory> +#include <stdexcept> +#include <string> + +#include <boost/test/unit_test.hpp> + +#include <boost/fiber/all.hpp> + +int gi = 7; + +struct my_exception : public std::runtime_error { + my_exception() : + std::runtime_error("my_exception") { + } +}; + +struct A { + A() = default; + + A( A const&) = delete; + A( A &&) = default; + + A & operator=( A const&) = delete; + A & operator=( A &&) = default; + + int value; +}; + +struct B { + bool bset{ false }; + + B() = default; + + B( bool set) : + bset{ set } { + gi = 3; + } + + ~B() { + if ( bset) { + gi = -1; + } + } + + B( B && other) : + bset{ other.bset } { + other.bset = false; + } + + B & operator=( B && other) { + if ( this == & other) return * this; + bset = other.bset; + other.bset = false; + return * this; + } + + B( B const&) = delete; + B & operator=( B const&) = delete; +}; + +void fn1( boost::fibers::promise< int > * p, int i) { + boost::this_fiber::yield(); + p->set_value( i); +} + +void fn2() { + boost::fibers::promise< int > p; + boost::fibers::future< int > f( p.get_future() ); + boost::this_fiber::yield(); + boost::fibers::fiber( boost::fibers::launch::post, fn1, & p, 7).detach(); + boost::this_fiber::yield(); + BOOST_CHECK( 7 == f.get() ); +} + +int fn3() { + return 3; +} + +void fn4() { +} + +int fn5() { + boost::throw_exception( my_exception() ); + return 3; +} + +void fn6() { + boost::throw_exception( my_exception() ); +} + +int & fn7() { + return gi; +} + +int fn8( int i) { + return i; +} + +A fn9() { + A a; + a.value = 3; + return a; +} + +A fn10() { + boost::throw_exception( my_exception() ); + return A(); +} + +B fn11( bool set) { + B b( set); + return b; +} + +// packaged_task +void test_packaged_task_create() { + // default constructed packaged_task is not valid + boost::fibers::packaged_task< int() > t1; + BOOST_CHECK( ! t1.valid() ); + + // packaged_task from function + boost::fibers::packaged_task< int() > t2( fn3); + BOOST_CHECK( t2.valid() ); +} + +// packaged_task +void test_packaged_task_create_move() { + // default constructed packaged_task is not valid + boost::fibers::packaged_task< A() > t1; + BOOST_CHECK( ! t1.valid() ); + + // packaged_task from function + boost::fibers::packaged_task< A() > t2( fn9); + BOOST_CHECK( t2.valid() ); +} + +void test_packaged_task_create_void() { + // default constructed packaged_task is not valid + boost::fibers::packaged_task< void() > t1; + BOOST_CHECK( ! t1.valid() ); + + // packaged_task from function + boost::fibers::packaged_task< void() > t2( fn4); + BOOST_CHECK( t2.valid() ); +} + +void test_packaged_task_move() { + boost::fibers::packaged_task< int() > t1( fn3); + BOOST_CHECK( t1.valid() ); + + // move construction + boost::fibers::packaged_task< int() > t2( std::move( t1) ); + BOOST_CHECK( ! t1.valid() ); + BOOST_CHECK( t2.valid() ); + + // move assignment + t1 = std::move( t2); + BOOST_CHECK( t1.valid() ); + BOOST_CHECK( ! t2.valid() ); +} + +void test_packaged_task_move_move() { + boost::fibers::packaged_task< A() > t1( fn9); + BOOST_CHECK( t1.valid() ); + + // move construction + boost::fibers::packaged_task< A() > t2( std::move( t1) ); + BOOST_CHECK( ! t1.valid() ); + BOOST_CHECK( t2.valid() ); + + // move assignment + t1 = std::move( t2); + BOOST_CHECK( t1.valid() ); + BOOST_CHECK( ! t2.valid() ); +} + +void test_packaged_task_move_void() { + boost::fibers::packaged_task< void() > t1( fn4); + BOOST_CHECK( t1.valid() ); + + // move construction + boost::fibers::packaged_task< void() > t2( std::move( t1) ); + BOOST_CHECK( ! t1.valid() ); + BOOST_CHECK( t2.valid() ); + + // move assignment + t1 = std::move( t2); + BOOST_CHECK( t1.valid() ); + BOOST_CHECK( ! t2.valid() ); +} + +void test_packaged_task_swap() { + boost::fibers::packaged_task< int() > t1( fn3); + BOOST_CHECK( t1.valid() ); + + boost::fibers::packaged_task< int() > t2; + BOOST_CHECK( ! t2.valid() ); + + // swap + t1.swap( t2); + BOOST_CHECK( ! t1.valid() ); + BOOST_CHECK( t2.valid() ); +} + +void test_packaged_task_swap_move() { + boost::fibers::packaged_task< A() > t1( fn9); + BOOST_CHECK( t1.valid() ); + + boost::fibers::packaged_task< A() > t2; + BOOST_CHECK( ! t2.valid() ); + + // swap + t1.swap( t2); + BOOST_CHECK( ! t1.valid() ); + BOOST_CHECK( t2.valid() ); +} + +void test_packaged_task_swap_void() { + boost::fibers::packaged_task< void() > t1( fn4); + BOOST_CHECK( t1.valid() ); + + boost::fibers::packaged_task< void() > t2; + BOOST_CHECK( ! t2.valid() ); + + // swap + t1.swap( t2); + BOOST_CHECK( ! t1.valid() ); + BOOST_CHECK( t2.valid() ); +} + +void test_packaged_task_reset() { + { + boost::fibers::packaged_task< int() > p( fn3); + boost::fibers::future< int > f( p.get_future() ); + BOOST_CHECK( p.valid() ); + + p(); + BOOST_CHECK( 3 == f.get() ); + + // reset + p.reset(); + p(); + f = p.get_future(); + BOOST_CHECK( 3 == f.get() ); + } + { + boost::fibers::packaged_task< int() > p; + + bool thrown = false; + try { + p.reset(); + } catch ( boost::fibers::packaged_task_uninitialized const&) { + thrown = true; + } + BOOST_CHECK( thrown); + } +} + +void test_packaged_task_reset_destruction() { + gi = 0; + boost::fibers::packaged_task< B( bool) > p( fn11); + BOOST_CHECK( p.valid() ); + + BOOST_CHECK( 0 == gi); + p( true); + BOOST_CHECK( 3 == gi); + + // reset + p.reset(); + BOOST_CHECK( -1 == gi); + p( false); + BOOST_CHECK( 3 == gi); + + // reset + p.reset(); + BOOST_CHECK( 3 == gi); +} + +void test_packaged_task_reset_move() { + { + boost::fibers::packaged_task< A() > p( fn9); + boost::fibers::future< A > f( p.get_future() ); + BOOST_CHECK( p.valid() ); + + p(); + BOOST_CHECK( 3 == f.get().value); + + // reset + p.reset(); + p(); + f = p.get_future(); + BOOST_CHECK( 3 == f.get().value); + } + { + boost::fibers::packaged_task< A() > p; + + bool thrown = false; + try { + p.reset(); + } catch ( boost::fibers::packaged_task_uninitialized const&) { + thrown = true; + } + BOOST_CHECK( thrown); + } +} + +void test_packaged_task_reset_void() { + { + boost::fibers::packaged_task< void() > p( fn4); + boost::fibers::future< void > f( p.get_future() ); + BOOST_CHECK( p.valid() ); + + p(); + f.get(); + + // reset + p.reset(); + p(); + f = p.get_future(); + f.get(); + } + { + boost::fibers::packaged_task< void() > p; + + bool thrown = false; + try { + p.reset(); + } catch ( boost::fibers::packaged_task_uninitialized const&) { + thrown = true; + } + BOOST_CHECK( thrown); + } +} + +void test_packaged_task_get_future() { + boost::fibers::packaged_task< int() > t1( fn3); + BOOST_CHECK( t1.valid() ); + + // retrieve future + boost::fibers::future< int > f1 = t1.get_future(); + BOOST_CHECK( f1.valid() ); + + // retrieve future a second time + bool thrown = false; + try { + f1 = t1.get_future(); + } catch ( boost::fibers::future_already_retrieved const&) { + thrown = true; + } + BOOST_CHECK( thrown); + + // move construction + boost::fibers::packaged_task< int() > t2( std::move( t1) ); + BOOST_CHECK( ! t1.valid() ); + BOOST_CHECK( t2.valid() ); + + // retrieve future from uninitialized + thrown = false; + try { + f1 = t1.get_future(); + } catch ( boost::fibers::packaged_task_uninitialized const&) { + thrown = true; + } + BOOST_CHECK( thrown); +} + +void test_packaged_task_get_future_move() { + boost::fibers::packaged_task< A() > t1( fn9); + BOOST_CHECK( t1.valid() ); + + // retrieve future + boost::fibers::future< A > f1 = t1.get_future(); + BOOST_CHECK( f1.valid() ); + + // retrieve future a second time + bool thrown = false; + try { + f1 = t1.get_future(); + } catch ( boost::fibers::future_already_retrieved const&) { + thrown = true; + } + BOOST_CHECK( thrown); + + // move construction + boost::fibers::packaged_task< A() > t2( std::move( t1) ); + BOOST_CHECK( ! t1.valid() ); + BOOST_CHECK( t2.valid() ); + + // retrieve future from uninitialized + thrown = false; + try { + f1 = t1.get_future(); + } catch ( boost::fibers::packaged_task_uninitialized const&) { + thrown = true; + } + BOOST_CHECK( thrown); +} + +void test_packaged_task_get_future_void() { + boost::fibers::packaged_task< void() > t1( fn4); + BOOST_CHECK( t1.valid() ); + + // retrieve future + boost::fibers::future< void > f1 = t1.get_future(); + BOOST_CHECK( f1.valid() ); + + // retrieve future a second time + bool thrown = false; + try { + f1 = t1.get_future(); + } catch ( boost::fibers::future_already_retrieved const&) { + thrown = true; + } + BOOST_CHECK( thrown); + + // move construction + boost::fibers::packaged_task< void() > t2( std::move( t1) ); + BOOST_CHECK( ! t1.valid() ); + BOOST_CHECK( t2.valid() ); + + // retrieve future from uninitialized + thrown = false; + try { + f1 = t1.get_future(); + } catch ( boost::fibers::packaged_task_uninitialized const&) { + thrown = true; + } + BOOST_CHECK( thrown); +} + +void test_packaged_task_exec() { + // promise takes a copyable as return type + boost::fibers::packaged_task< int() > t1( fn3); + BOOST_CHECK( t1.valid() ); + boost::fibers::future< int > f1 = t1.get_future(); + BOOST_CHECK( f1.valid() ); + + // exec + t1(); + BOOST_CHECK( 3 == f1.get() ); + + // exec a second time + bool thrown = false; + try { + t1(); + } catch ( boost::fibers::promise_already_satisfied const&) { + thrown = true; + } + BOOST_CHECK( thrown); +} + +void test_packaged_task_exec_move() { + // promise takes a copyable as return type + boost::fibers::packaged_task< A() > t1( fn9); + BOOST_CHECK( t1.valid() ); + boost::fibers::future< A > f1 = t1.get_future(); + BOOST_CHECK( f1.valid() ); + + // exec + t1(); + BOOST_CHECK( 3 == f1.get().value); + + // exec a second time + bool thrown = false; + try { + t1(); + } catch ( boost::fibers::promise_already_satisfied const&) { + thrown = true; + } + BOOST_CHECK( thrown); +} + +void test_packaged_task_exec_param() { + // promise takes a copyable as return type + boost::fibers::packaged_task< int( int) > t1( fn8); + BOOST_CHECK( t1.valid() ); + boost::fibers::future< int > f1 = t1.get_future(); + BOOST_CHECK( f1.valid() ); + + // exec + t1( 3); + BOOST_CHECK( 3 == f1.get() ); + + // exec a second time + bool thrown = false; + try { + t1( 7); + } catch ( boost::fibers::promise_already_satisfied const&) { + thrown = true; + } + BOOST_CHECK( thrown); + + //TODO: packaged_task returns a moveable-only as return type +} + +void test_packaged_task_exec_ref() { + // promise takes a copyable as return type + boost::fibers::packaged_task< int&() > t1( fn7); + BOOST_CHECK( t1.valid() ); + boost::fibers::future< int& > f1 = t1.get_future(); + BOOST_CHECK( f1.valid() ); + + // exec + t1(); + int & i = f1.get(); + BOOST_CHECK( &gi == &i); + + // exec a second time + bool thrown = false; + try { + t1(); + } catch ( boost::fibers::promise_already_satisfied const&) { + thrown = true; + } + BOOST_CHECK( thrown); + + //TODO: packaged_task returns a moveable-only as return type +} + +void test_packaged_task_exec_void() { + // promise takes a copyable as return type + boost::fibers::packaged_task< void() > t1( fn4); + BOOST_CHECK( t1.valid() ); + boost::fibers::future< void > f1 = t1.get_future(); + BOOST_CHECK( f1.valid() ); + + // set void + t1(); + f1.get(); + + // exec a second time + bool thrown = false; + try { + t1(); + } catch ( boost::fibers::promise_already_satisfied const&) { + thrown = true; + } + BOOST_CHECK( thrown); +} + +void test_packaged_task_exception() { + // promise takes a copyable as return type + boost::fibers::packaged_task< int() > t1( fn5); + BOOST_CHECK( t1.valid() ); + boost::fibers::future< int > f1 = t1.get_future(); + BOOST_CHECK( f1.valid() ); + + // exec + t1(); + bool thrown = false; + try { + f1.get(); + } catch ( my_exception const&) { + thrown = true; + } + BOOST_CHECK( thrown); + + boost::fibers::packaged_task< int() > t2( fn5); + BOOST_CHECK( t2.valid() ); + boost::fibers::future< int > f2 = t2.get_future(); + BOOST_CHECK( f2.valid() ); + + // exec + t2(); + BOOST_CHECK( f2.get_exception_ptr() ); + thrown = false; + try + { std::rethrow_exception( f2.get_exception_ptr() ); } + catch ( my_exception const&) + { thrown = true; } + BOOST_CHECK( thrown); +} + +void test_packaged_task_exception_move() { + // promise takes a moveable as return type + boost::fibers::packaged_task< A() > t1( fn10); + BOOST_CHECK( t1.valid() ); + boost::fibers::future< A > f1 = t1.get_future(); + BOOST_CHECK( f1.valid() ); + + // exec + t1(); + bool thrown = false; + try { + f1.get(); + } catch ( my_exception const&) { + thrown = true; + } + BOOST_CHECK( thrown); + + boost::fibers::packaged_task< A() > t2( fn10); + BOOST_CHECK( t2.valid() ); + boost::fibers::future< A > f2 = t2.get_future(); + BOOST_CHECK( f2.valid() ); + + // exec + t2(); + BOOST_CHECK( f2.get_exception_ptr() ); + thrown = false; + try + { std::rethrow_exception( f2.get_exception_ptr() ); } + catch ( my_exception const&) + { thrown = true; } + BOOST_CHECK( thrown); +} + +void test_packaged_task_exception_void() { + // promise takes a copyable as return type + boost::fibers::packaged_task< void() > t1( fn6); + BOOST_CHECK( t1.valid() ); + boost::fibers::future< void > f1 = t1.get_future(); + BOOST_CHECK( f1.valid() ); + + // set void + t1(); + bool thrown = false; + try { + f1.get(); + } catch ( my_exception const&) { + thrown = true; + } + BOOST_CHECK( thrown); + + boost::fibers::packaged_task< void() > t2( fn6); + BOOST_CHECK( t2.valid() ); + boost::fibers::future< void > f2 = t2.get_future(); + BOOST_CHECK( f2.valid() ); + + // exec + t2(); + BOOST_CHECK( f2.get_exception_ptr() ); + thrown = false; + try { + std::rethrow_exception( f2.get_exception_ptr() ); + } catch ( my_exception const&) { + thrown = true; + } + BOOST_CHECK( thrown); +} + + +boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[]) { + boost::unit_test_framework::test_suite* test = + BOOST_TEST_SUITE("Boost.Fiber: packaged_task test suite"); + + test->add(BOOST_TEST_CASE(test_packaged_task_create)); + test->add(BOOST_TEST_CASE(test_packaged_task_create_move)); + test->add(BOOST_TEST_CASE(test_packaged_task_create_void)); + test->add(BOOST_TEST_CASE(test_packaged_task_move)); + test->add(BOOST_TEST_CASE(test_packaged_task_move_move)); + test->add(BOOST_TEST_CASE(test_packaged_task_move_void)); + test->add(BOOST_TEST_CASE(test_packaged_task_swap)); + test->add(BOOST_TEST_CASE(test_packaged_task_swap_move)); + test->add(BOOST_TEST_CASE(test_packaged_task_swap_void)); + test->add(BOOST_TEST_CASE(test_packaged_task_reset)); + test->add(BOOST_TEST_CASE(test_packaged_task_reset_destruction)); + test->add(BOOST_TEST_CASE(test_packaged_task_reset_move)); + test->add(BOOST_TEST_CASE(test_packaged_task_reset_void)); + test->add(BOOST_TEST_CASE(test_packaged_task_get_future)); + test->add(BOOST_TEST_CASE(test_packaged_task_get_future_move)); + test->add(BOOST_TEST_CASE(test_packaged_task_get_future_void)); + test->add(BOOST_TEST_CASE(test_packaged_task_exec)); + test->add(BOOST_TEST_CASE(test_packaged_task_exec_move)); + test->add(BOOST_TEST_CASE(test_packaged_task_exec_param)); + test->add(BOOST_TEST_CASE(test_packaged_task_exec_ref)); + test->add(BOOST_TEST_CASE(test_packaged_task_exec_void)); + test->add(BOOST_TEST_CASE(test_packaged_task_exception)); + test->add(BOOST_TEST_CASE(test_packaged_task_exception_move)); + test->add(BOOST_TEST_CASE(test_packaged_task_exception_void)); + + return test; +} diff --git a/src/boost/libs/fiber/test/test_promise_dispatch.cpp b/src/boost/libs/fiber/test/test_promise_dispatch.cpp new file mode 100644 index 00000000..d3f90f22 --- /dev/null +++ b/src/boost/libs/fiber/test/test_promise_dispatch.cpp @@ -0,0 +1,445 @@ +// (C) Copyright 2008-10 Anthony Williams +// +// 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) + +#include <utility> +#include <memory> +#include <stdexcept> +#include <string> + +#include <boost/test/unit_test.hpp> + +#include <boost/fiber/all.hpp> + +int gi = 7; + +struct my_exception : public std::runtime_error { + my_exception() : + std::runtime_error("my_exception") { + } +}; + +struct A { + A() = default; + + A( A const&) = delete; + A( A &&) = default; + + A & operator=( A const&) = delete; + A & operator=( A &&) = default; + + int value{ 0 }; +}; + +void fn1( boost::fibers::promise< int > * p, int i) { + boost::this_fiber::yield(); + p->set_value( i); +} + +void fn2() { + boost::fibers::promise< int > p; + boost::fibers::future< int > f( p.get_future() ); + boost::this_fiber::yield(); + boost::fibers::fiber( boost::fibers::launch::dispatch, fn1, & p, 7).detach(); + boost::this_fiber::yield(); + BOOST_CHECK( 7 == f.get() ); +} + +int fn3() { + return 3; +} + +void fn4() { +} + +int fn5() { + boost::throw_exception( my_exception() ); + return 3; +} + +void fn6() { + boost::throw_exception( my_exception() ); +} + +int & fn7() { + return gi; +} + +int fn8( int i) { + return i; +} + +A fn9() { + A a; + a.value = 3; + return a; +} + +A fn10() { + boost::throw_exception( my_exception() ); + return A(); +} + +// promise +void test_promise_create() { + // use std::allocator<> as default + boost::fibers::promise< int > p1; + + // use std::allocator<> as user defined + std::allocator< boost::fibers::promise< int > > alloc; + boost::fibers::promise< int > p2( std::allocator_arg, alloc); +} + +void test_promise_create_ref() { + // use std::allocator<> as default + boost::fibers::promise< int& > p1; + + // use std::allocator<> as user defined + std::allocator< boost::fibers::promise< int& > > alloc; + boost::fibers::promise< int& > p2( std::allocator_arg, alloc); +} + +void test_promise_create_void() { + // use std::allocator<> as default + boost::fibers::promise< void > p1; + + // use std::allocator<> as user defined + std::allocator< boost::fibers::promise< void > > alloc; + boost::fibers::promise< void > p2( std::allocator_arg, alloc); +} + +void test_promise_move() { + boost::fibers::promise< int > p1; + + // move construction + boost::fibers::promise< int > p2( std::move( p1) ); + + // move assigment + p1 = std::move( p2); +} + +void test_promise_move_ref() { + boost::fibers::promise< int& > p1; + + // move construction + boost::fibers::promise< int& > p2( std::move( p1) ); + + // move assigment + p1 = std::move( p2); +} + +void test_promise_move_void() { + boost::fibers::promise< void > p1; + + // move construction + boost::fibers::promise< void > p2( std::move( p1) ); + + // move assigment + p1 = std::move( p2); +} + +void test_promise_swap() { + boost::fibers::promise< int > p1; + + // move construction + boost::fibers::promise< int > p2( std::move( p1) ); + + // swap + p1.swap( p2); +} + +void test_promise_swap_ref() { + boost::fibers::promise< int& > p1; + + // move construction + boost::fibers::promise< int& > p2( std::move( p1) ); + + // swap + p1.swap( p2); +} + +void test_promise_swap_void() { + boost::fibers::promise< void > p1; + + // move construction + boost::fibers::promise< void > p2( std::move( p1) ); + + // swap + p1.swap( p2); +} + +void test_promise_get_future() { + boost::fibers::promise< int > p1; + + // retrieve future + boost::fibers::future< int > f1 = p1.get_future(); + BOOST_CHECK( f1.valid() ); + + // retrieve future a second time + bool thrown = false; + try { + f1 = p1.get_future(); + } catch ( boost::fibers::future_already_retrieved const&) { + thrown = true; + } + BOOST_CHECK( thrown); + + // move construction + boost::fibers::promise< int > p2( std::move( p1) ); + + // retrieve future from uninitialized + thrown = false; + try { + f1 = p1.get_future(); + } catch ( boost::fibers::promise_uninitialized const&) { + thrown = true; + } + BOOST_CHECK( thrown); +} + +void test_promise_get_future_ref() { + boost::fibers::promise< int& > p1; + + // retrieve future + boost::fibers::future< int& > f1 = p1.get_future(); + BOOST_CHECK( f1.valid() ); + + // retrieve future a second time + bool thrown = false; + try { + f1 = p1.get_future(); + } catch ( boost::fibers::future_already_retrieved const&) { + thrown = true; + } + BOOST_CHECK( thrown); + + // move construction + boost::fibers::promise< int& > p2( std::move( p1) ); + + // retrieve future from uninitialized + thrown = false; + try { + f1 = p1.get_future(); + } catch ( boost::fibers::promise_uninitialized const&) { + thrown = true; + } + BOOST_CHECK( thrown); +} + +void test_promise_get_future_void() { + boost::fibers::promise< void > p1; + + // retrieve future + boost::fibers::future< void > f1 = p1.get_future(); + BOOST_CHECK( f1.valid() ); + + // retrieve future a second time + bool thrown = false; + try { + f1 = p1.get_future(); + } catch ( boost::fibers::future_already_retrieved const&) { + thrown = true; + } + BOOST_CHECK( thrown); + + // move construction + boost::fibers::promise< void > p2( std::move( p1) ); + + // retrieve future from uninitialized + thrown = false; + try { + f1 = p1.get_future(); + } catch ( boost::fibers::promise_uninitialized const&) { + thrown = true; + } + BOOST_CHECK( thrown); +} + +void test_promise_set_value() { + // promise takes a copyable as return type + boost::fibers::promise< int > p1; + boost::fibers::future< int > f1 = p1.get_future(); + BOOST_CHECK( f1.valid() ); + + // copy value + p1.set_value( 7); + BOOST_CHECK( 7 == f1.get() ); + + // set value a second time + bool thrown = false; + try { + p1.set_value( 11); + } catch ( boost::fibers::promise_already_satisfied const&) { + thrown = true; + } + BOOST_CHECK( thrown); +} + +void test_promise_set_value_move() { + // promise takes a copyable as return type + boost::fibers::promise< A > p1; + boost::fibers::future< A > f1 = p1.get_future(); + BOOST_CHECK( f1.valid() ); + + // move value + A a1; a1.value = 7; + p1.set_value( std::move( a1) ); + A a2 = f1.get(); + BOOST_CHECK( 7 == a2.value); + + // set value a second time + bool thrown = false; + try { + A a; + p1.set_value( std::move( a) ); + } catch ( boost::fibers::promise_already_satisfied const&) { + thrown = true; + } + BOOST_CHECK( thrown); +} + +void test_promise_set_value_ref() { + // promise takes a reference as return type + boost::fibers::promise< int& > p1; + boost::fibers::future< int& > f1 = p1.get_future(); + BOOST_CHECK( f1.valid() ); + + // copy value + int i = 7; + p1.set_value( i); + int & j = f1.get(); + BOOST_CHECK( &i == &j); + + // set value a second time + bool thrown = false; + try { + p1.set_value( i); + } catch ( boost::fibers::promise_already_satisfied const&) { + thrown = true; + } + BOOST_CHECK( thrown); +} + +void test_promise_set_value_void() { + // promise takes a copyable as return type + boost::fibers::promise< void > p1; + boost::fibers::future< void > f1 = p1.get_future(); + BOOST_CHECK( f1.valid() ); + + // set void + p1.set_value(); + f1.get(); + + // set value a second time + bool thrown = false; + try { + p1.set_value(); + } catch ( boost::fibers::promise_already_satisfied const&) { + thrown = true; + } + BOOST_CHECK( thrown); +} + +void test_promise_set_exception() { + boost::fibers::promise< int > p1; + boost::fibers::future< int > f1 = p1.get_future(); + BOOST_CHECK( f1.valid() ); + p1.set_exception( std::make_exception_ptr( my_exception() ) ); + + // set exception a second time + bool thrown = false; + try { + p1.set_exception( std::make_exception_ptr( my_exception() ) ); + } catch ( boost::fibers::promise_already_satisfied const&) { + thrown = true; + } + BOOST_CHECK( thrown); + + // set value + thrown = false; + try + { p1.set_value( 11); } + catch ( boost::fibers::promise_already_satisfied const&) + { thrown = true; } + BOOST_CHECK( thrown); +} + +void test_promise_set_exception_ref() { + boost::fibers::promise< int& > p1; + boost::fibers::future< int& > f1 = p1.get_future(); + BOOST_CHECK( f1.valid() ); + p1.set_exception( std::make_exception_ptr( my_exception() ) ); + + // set exception a second time + bool thrown = false; + try { + p1.set_exception( std::make_exception_ptr( my_exception() ) ); + } catch ( boost::fibers::promise_already_satisfied const&) { + thrown = true; + } + BOOST_CHECK( thrown); + + // set value + thrown = false; + int i = 11; + try { + p1.set_value( i); + } catch ( boost::fibers::promise_already_satisfied const&) { + thrown = true; + } + BOOST_CHECK( thrown); +} + +void test_promise_set_exception_void() { + boost::fibers::promise< void > p1; + boost::fibers::future< void > f1 = p1.get_future(); + BOOST_CHECK( f1.valid() ); + p1.set_exception( std::make_exception_ptr( my_exception() ) ); + + // set exception a second time + bool thrown = false; + try { + p1.set_exception( std::make_exception_ptr( my_exception() ) ); + } catch ( boost::fibers::promise_already_satisfied const&) { + thrown = true; + } + BOOST_CHECK( thrown); + + // set value + thrown = false; + try { + p1.set_value(); + } catch ( boost::fibers::promise_already_satisfied const&) { + thrown = true; + } + BOOST_CHECK( thrown); +} + +boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[]) { + boost::unit_test_framework::test_suite* test = + BOOST_TEST_SUITE("Boost.Fiber: promise test suite"); + + test->add(BOOST_TEST_CASE(test_promise_create)); + test->add(BOOST_TEST_CASE(test_promise_create_ref)); + test->add(BOOST_TEST_CASE(test_promise_create_void)); + test->add(BOOST_TEST_CASE(test_promise_move)); + test->add(BOOST_TEST_CASE(test_promise_move_ref)); + test->add(BOOST_TEST_CASE(test_promise_move_void)); + test->add(BOOST_TEST_CASE(test_promise_swap)); + test->add(BOOST_TEST_CASE(test_promise_swap_ref)); + test->add(BOOST_TEST_CASE(test_promise_swap_void)); + test->add(BOOST_TEST_CASE(test_promise_get_future)); + test->add(BOOST_TEST_CASE(test_promise_get_future_ref)); + test->add(BOOST_TEST_CASE(test_promise_get_future_void)); + test->add(BOOST_TEST_CASE(test_promise_set_value)); + test->add(BOOST_TEST_CASE(test_promise_set_value_move)); + test->add(BOOST_TEST_CASE(test_promise_set_value_ref)); + test->add(BOOST_TEST_CASE(test_promise_set_value_void)); + test->add(BOOST_TEST_CASE(test_promise_set_exception)); + test->add(BOOST_TEST_CASE(test_promise_set_exception_ref)); + test->add(BOOST_TEST_CASE(test_promise_set_exception_void)); + + return test; +} diff --git a/src/boost/libs/fiber/test/test_promise_post.cpp b/src/boost/libs/fiber/test/test_promise_post.cpp new file mode 100644 index 00000000..f14936f7 --- /dev/null +++ b/src/boost/libs/fiber/test/test_promise_post.cpp @@ -0,0 +1,445 @@ +// (C) Copyright 2008-10 Anthony Williams +// +// 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) + +#include <utility> +#include <memory> +#include <stdexcept> +#include <string> + +#include <boost/test/unit_test.hpp> + +#include <boost/fiber/all.hpp> + +int gi = 7; + +struct my_exception : public std::runtime_error { + my_exception() : + std::runtime_error("my_exception") { + } +}; + +struct A { + A() = default; + + A( A const&) = delete; + A( A &&) = default; + + A & operator=( A const&) = delete; + A & operator=( A &&) = default; + + int value{ 0 }; +}; + +void fn1( boost::fibers::promise< int > * p, int i) { + boost::this_fiber::yield(); + p->set_value( i); +} + +void fn2() { + boost::fibers::promise< int > p; + boost::fibers::future< int > f( p.get_future() ); + boost::this_fiber::yield(); + boost::fibers::fiber( boost::fibers::launch::post, fn1, & p, 7).detach(); + boost::this_fiber::yield(); + BOOST_CHECK( 7 == f.get() ); +} + +int fn3() { + return 3; +} + +void fn4() { +} + +int fn5() { + boost::throw_exception( my_exception() ); + return 3; +} + +void fn6() { + boost::throw_exception( my_exception() ); +} + +int & fn7() { + return gi; +} + +int fn8( int i) { + return i; +} + +A fn9() { + A a; + a.value = 3; + return a; +} + +A fn10() { + boost::throw_exception( my_exception() ); + return A(); +} + +// promise +void test_promise_create() { + // use std::allocator<> as default + boost::fibers::promise< int > p1; + + // use std::allocator<> as user defined + std::allocator< boost::fibers::promise< int > > alloc; + boost::fibers::promise< int > p2( std::allocator_arg, alloc); +} + +void test_promise_create_ref() { + // use std::allocator<> as default + boost::fibers::promise< int& > p1; + + // use std::allocator<> as user defined + std::allocator< boost::fibers::promise< int& > > alloc; + boost::fibers::promise< int& > p2( std::allocator_arg, alloc); +} + +void test_promise_create_void() { + // use std::allocator<> as default + boost::fibers::promise< void > p1; + + // use std::allocator<> as user defined + std::allocator< boost::fibers::promise< void > > alloc; + boost::fibers::promise< void > p2( std::allocator_arg, alloc); +} + +void test_promise_move() { + boost::fibers::promise< int > p1; + + // move construction + boost::fibers::promise< int > p2( std::move( p1) ); + + // move assigment + p1 = std::move( p2); +} + +void test_promise_move_ref() { + boost::fibers::promise< int& > p1; + + // move construction + boost::fibers::promise< int& > p2( std::move( p1) ); + + // move assigment + p1 = std::move( p2); +} + +void test_promise_move_void() { + boost::fibers::promise< void > p1; + + // move construction + boost::fibers::promise< void > p2( std::move( p1) ); + + // move assigment + p1 = std::move( p2); +} + +void test_promise_swap() { + boost::fibers::promise< int > p1; + + // move construction + boost::fibers::promise< int > p2( std::move( p1) ); + + // swap + p1.swap( p2); +} + +void test_promise_swap_ref() { + boost::fibers::promise< int& > p1; + + // move construction + boost::fibers::promise< int& > p2( std::move( p1) ); + + // swap + p1.swap( p2); +} + +void test_promise_swap_void() { + boost::fibers::promise< void > p1; + + // move construction + boost::fibers::promise< void > p2( std::move( p1) ); + + // swap + p1.swap( p2); +} + +void test_promise_get_future() { + boost::fibers::promise< int > p1; + + // retrieve future + boost::fibers::future< int > f1 = p1.get_future(); + BOOST_CHECK( f1.valid() ); + + // retrieve future a second time + bool thrown = false; + try { + f1 = p1.get_future(); + } catch ( boost::fibers::future_already_retrieved const&) { + thrown = true; + } + BOOST_CHECK( thrown); + + // move construction + boost::fibers::promise< int > p2( std::move( p1) ); + + // retrieve future from uninitialized + thrown = false; + try { + f1 = p1.get_future(); + } catch ( boost::fibers::promise_uninitialized const&) { + thrown = true; + } + BOOST_CHECK( thrown); +} + +void test_promise_get_future_ref() { + boost::fibers::promise< int& > p1; + + // retrieve future + boost::fibers::future< int& > f1 = p1.get_future(); + BOOST_CHECK( f1.valid() ); + + // retrieve future a second time + bool thrown = false; + try { + f1 = p1.get_future(); + } catch ( boost::fibers::future_already_retrieved const&) { + thrown = true; + } + BOOST_CHECK( thrown); + + // move construction + boost::fibers::promise< int& > p2( std::move( p1) ); + + // retrieve future from uninitialized + thrown = false; + try { + f1 = p1.get_future(); + } catch ( boost::fibers::promise_uninitialized const&) { + thrown = true; + } + BOOST_CHECK( thrown); +} + +void test_promise_get_future_void() { + boost::fibers::promise< void > p1; + + // retrieve future + boost::fibers::future< void > f1 = p1.get_future(); + BOOST_CHECK( f1.valid() ); + + // retrieve future a second time + bool thrown = false; + try { + f1 = p1.get_future(); + } catch ( boost::fibers::future_already_retrieved const&) { + thrown = true; + } + BOOST_CHECK( thrown); + + // move construction + boost::fibers::promise< void > p2( std::move( p1) ); + + // retrieve future from uninitialized + thrown = false; + try { + f1 = p1.get_future(); + } catch ( boost::fibers::promise_uninitialized const&) { + thrown = true; + } + BOOST_CHECK( thrown); +} + +void test_promise_set_value() { + // promise takes a copyable as return type + boost::fibers::promise< int > p1; + boost::fibers::future< int > f1 = p1.get_future(); + BOOST_CHECK( f1.valid() ); + + // copy value + p1.set_value( 7); + BOOST_CHECK( 7 == f1.get() ); + + // set value a second time + bool thrown = false; + try { + p1.set_value( 11); + } catch ( boost::fibers::promise_already_satisfied const&) { + thrown = true; + } + BOOST_CHECK( thrown); +} + +void test_promise_set_value_move() { + // promise takes a copyable as return type + boost::fibers::promise< A > p1; + boost::fibers::future< A > f1 = p1.get_future(); + BOOST_CHECK( f1.valid() ); + + // move value + A a1; a1.value = 7; + p1.set_value( std::move( a1) ); + A a2 = f1.get(); + BOOST_CHECK( 7 == a2.value); + + // set value a second time + bool thrown = false; + try { + A a; + p1.set_value( std::move( a) ); + } catch ( boost::fibers::promise_already_satisfied const&) { + thrown = true; + } + BOOST_CHECK( thrown); +} + +void test_promise_set_value_ref() { + // promise takes a reference as return type + boost::fibers::promise< int& > p1; + boost::fibers::future< int& > f1 = p1.get_future(); + BOOST_CHECK( f1.valid() ); + + // copy value + int i = 7; + p1.set_value( i); + int & j = f1.get(); + BOOST_CHECK( &i == &j); + + // set value a second time + bool thrown = false; + try { + p1.set_value( i); + } catch ( boost::fibers::promise_already_satisfied const&) { + thrown = true; + } + BOOST_CHECK( thrown); +} + +void test_promise_set_value_void() { + // promise takes a copyable as return type + boost::fibers::promise< void > p1; + boost::fibers::future< void > f1 = p1.get_future(); + BOOST_CHECK( f1.valid() ); + + // set void + p1.set_value(); + f1.get(); + + // set value a second time + bool thrown = false; + try { + p1.set_value(); + } catch ( boost::fibers::promise_already_satisfied const&) { + thrown = true; + } + BOOST_CHECK( thrown); +} + +void test_promise_set_exception() { + boost::fibers::promise< int > p1; + boost::fibers::future< int > f1 = p1.get_future(); + BOOST_CHECK( f1.valid() ); + p1.set_exception( std::make_exception_ptr( my_exception() ) ); + + // set exception a second time + bool thrown = false; + try { + p1.set_exception( std::make_exception_ptr( my_exception() ) ); + } catch ( boost::fibers::promise_already_satisfied const&) { + thrown = true; + } + BOOST_CHECK( thrown); + + // set value + thrown = false; + try + { p1.set_value( 11); } + catch ( boost::fibers::promise_already_satisfied const&) + { thrown = true; } + BOOST_CHECK( thrown); +} + +void test_promise_set_exception_ref() { + boost::fibers::promise< int& > p1; + boost::fibers::future< int& > f1 = p1.get_future(); + BOOST_CHECK( f1.valid() ); + p1.set_exception( std::make_exception_ptr( my_exception() ) ); + + // set exception a second time + bool thrown = false; + try { + p1.set_exception( std::make_exception_ptr( my_exception() ) ); + } catch ( boost::fibers::promise_already_satisfied const&) { + thrown = true; + } + BOOST_CHECK( thrown); + + // set value + thrown = false; + int i = 11; + try { + p1.set_value( i); + } catch ( boost::fibers::promise_already_satisfied const&) { + thrown = true; + } + BOOST_CHECK( thrown); +} + +void test_promise_set_exception_void() { + boost::fibers::promise< void > p1; + boost::fibers::future< void > f1 = p1.get_future(); + BOOST_CHECK( f1.valid() ); + p1.set_exception( std::make_exception_ptr( my_exception() ) ); + + // set exception a second time + bool thrown = false; + try { + p1.set_exception( std::make_exception_ptr( my_exception() ) ); + } catch ( boost::fibers::promise_already_satisfied const&) { + thrown = true; + } + BOOST_CHECK( thrown); + + // set value + thrown = false; + try { + p1.set_value(); + } catch ( boost::fibers::promise_already_satisfied const&) { + thrown = true; + } + BOOST_CHECK( thrown); +} + +boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[]) { + boost::unit_test_framework::test_suite* test = + BOOST_TEST_SUITE("Boost.Fiber: promise test suite"); + + test->add(BOOST_TEST_CASE(test_promise_create)); + test->add(BOOST_TEST_CASE(test_promise_create_ref)); + test->add(BOOST_TEST_CASE(test_promise_create_void)); + test->add(BOOST_TEST_CASE(test_promise_move)); + test->add(BOOST_TEST_CASE(test_promise_move_ref)); + test->add(BOOST_TEST_CASE(test_promise_move_void)); + test->add(BOOST_TEST_CASE(test_promise_swap)); + test->add(BOOST_TEST_CASE(test_promise_swap_ref)); + test->add(BOOST_TEST_CASE(test_promise_swap_void)); + test->add(BOOST_TEST_CASE(test_promise_get_future)); + test->add(BOOST_TEST_CASE(test_promise_get_future_ref)); + test->add(BOOST_TEST_CASE(test_promise_get_future_void)); + test->add(BOOST_TEST_CASE(test_promise_set_value)); + test->add(BOOST_TEST_CASE(test_promise_set_value_move)); + test->add(BOOST_TEST_CASE(test_promise_set_value_ref)); + test->add(BOOST_TEST_CASE(test_promise_set_value_void)); + test->add(BOOST_TEST_CASE(test_promise_set_exception)); + test->add(BOOST_TEST_CASE(test_promise_set_exception_ref)); + test->add(BOOST_TEST_CASE(test_promise_set_exception_void)); + + return test; +} diff --git a/src/boost/libs/fiber/test/test_shared_future_dispatch.cpp b/src/boost/libs/fiber/test/test_shared_future_dispatch.cpp new file mode 100644 index 00000000..2dd327ff --- /dev/null +++ b/src/boost/libs/fiber/test/test_shared_future_dispatch.cpp @@ -0,0 +1,608 @@ +// (C) Copyright 2008-10 Anthony Williams +// 2015 Oliver Kowalke +// +// 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) + +#include <chrono> +#include <memory> +#include <stdexcept> +#include <string> +#include <utility> + +#include <boost/test/unit_test.hpp> + +#include <boost/fiber/all.hpp> + +typedef std::chrono::milliseconds ms; +typedef std::chrono::high_resolution_clock Clock; + +int gi = 7; + +struct my_exception : public std::runtime_error { + my_exception() : + std::runtime_error("my_exception") { + } +}; + +struct A { + A() = default; + + A( A const&) = delete; + A( A &&) = default; + + A & operator=( A const&) = delete; + A & operator=( A &&) = default; + + int value; +}; + +void fn1( boost::fibers::promise< int > * p, int i) { + boost::this_fiber::yield(); + p->set_value( i); +} + +void fn2() { + boost::fibers::promise< int > p; + boost::fibers::shared_future< int > f( p.get_future().share() ); + boost::this_fiber::yield(); + boost::fibers::fiber( boost::fibers::launch::dispatch, fn1, & p, 7).detach(); + boost::this_fiber::yield(); + BOOST_CHECK( 7 == f.get() ); +} + +int fn3() { + return 3; +} + +void fn4() { +} + +int fn5() { + boost::throw_exception( my_exception() ); + return 3; +} + +void fn6() { + boost::throw_exception( my_exception() ); +} + +int & fn7() { + return gi; +} + +int fn8( int i) { + return i; +} + +A fn9() { + A a; + a.value = 3; + return a; +} + +A fn10() { + boost::throw_exception( my_exception() ); + return A(); +} + +void fn11( boost::fibers::promise< int > p) { + boost::this_fiber::sleep_for( ms(500) ); + p.set_value(3); +} + +void fn12( boost::fibers::promise< int& > p) { + boost::this_fiber::sleep_for( ms(500) ); + gi = 5; + p.set_value( gi); +} + +void fn13( boost::fibers::promise< void > p) { + boost::this_fiber::sleep_for( ms(500) ); + p.set_value(); +} + +// shared_future +void test_shared_future_create() { + { + // default constructed and assigned shared_future is not valid + boost::fibers::shared_future< int > f1; + boost::fibers::shared_future< int > f2 = f1; + BOOST_CHECK( ! f1.valid() ); + BOOST_CHECK( ! f2.valid() ); + } + + { + // shared_future retrieved from promise is valid + boost::fibers::promise< int > p; + boost::fibers::shared_future< int > f1 = p.get_future(); + boost::fibers::shared_future< int > f2 = f1; + BOOST_CHECK( f1.valid() ); + BOOST_CHECK( f2.valid() ); + } +} + +void test_shared_future_create_ref() { + { + // default constructed and assigned shared_future is not valid + boost::fibers::shared_future< int& > f1; + boost::fibers::shared_future< int& > f2 = f1; + BOOST_CHECK( ! f1.valid() ); + BOOST_CHECK( ! f2.valid() ); + } + + { + // shared_future retrieved from promise is valid + boost::fibers::promise< int& > p; + boost::fibers::shared_future< int& > f1 = p.get_future(); + boost::fibers::shared_future< int& > f2 = f1; + BOOST_CHECK( f1.valid() ); + BOOST_CHECK( f2.valid() ); + } +} + +void test_shared_future_create_void() { + { + // default constructed and assigned shared_future is not valid + boost::fibers::shared_future< void > f1; + boost::fibers::shared_future< void > f2 = f1; + BOOST_CHECK( ! f1.valid() ); + BOOST_CHECK( ! f2.valid() ); + } + + { + // shared_future retrieved from promise is valid + boost::fibers::promise< void > p; + boost::fibers::shared_future< void > f1 = p.get_future(); + boost::fibers::shared_future< void > f2 = f1; + BOOST_CHECK( f1.valid() ); + BOOST_CHECK( f2.valid() ); + } +} + +void test_shared_future_get() { + // future retrieved from promise is valid (if it is the first) + boost::fibers::promise< int > p1; + p1.set_value( 7); + + boost::fibers::shared_future< int > f1 = p1.get_future().share(); + BOOST_CHECK( f1.valid() ); + + // get + BOOST_CHECK( ! f1.get_exception_ptr() ); + BOOST_CHECK( 7 == f1.get() ); + BOOST_CHECK( f1.valid() ); + + // throw broken_promise if promise is destroyed without set + { + boost::fibers::promise< int > p2; + f1 = p2.get_future().share(); + } + bool thrown = false; + try { + f1.get(); + } catch ( boost::fibers::broken_promise const&) { + thrown = true; + } + BOOST_CHECK( f1.valid() ); + BOOST_CHECK( thrown); +} + +void test_shared_future_get_move() { + // future retrieved from promise is valid (if it is the first) + boost::fibers::promise< A > p1; + A a; a.value = 7; + p1.set_value( std::move( a) ); + + boost::fibers::shared_future< A > f1 = p1.get_future().share(); + BOOST_CHECK( f1.valid() ); + + // get + BOOST_CHECK( ! f1.get_exception_ptr() ); + BOOST_CHECK( 7 == f1.get().value); + BOOST_CHECK( f1.valid() ); + + // throw broken_promise if promise is destroyed without set + { + boost::fibers::promise< A > p2; + f1 = p2.get_future().share(); + } + bool thrown = false; + try { + f1.get(); + } catch ( boost::fibers::broken_promise const&) { + thrown = true; + } + BOOST_CHECK( f1.valid() ); + BOOST_CHECK( thrown); +} + +void test_shared_future_get_ref() { + // future retrieved from promise is valid (if it is the first) + boost::fibers::promise< int& > p1; + int i = 7; + p1.set_value( i); + + boost::fibers::shared_future< int& > f1 = p1.get_future().share(); + BOOST_CHECK( f1.valid() ); + + // get + BOOST_CHECK( ! f1.get_exception_ptr() ); + int & j = f1.get(); + BOOST_CHECK( &i == &j); + BOOST_CHECK( f1.valid() ); + + // throw broken_promise if promise is destroyed without set + { + boost::fibers::promise< int& > p2; + f1 = p2.get_future().share(); + } + bool thrown = false; + try { + f1.get(); + } catch ( boost::fibers::broken_promise const&) { + thrown = true; + } + BOOST_CHECK( f1.valid() ); + BOOST_CHECK( thrown); +} + + +void test_shared_future_get_void() { + // future retrieved from promise is valid (if it is the first) + boost::fibers::promise< void > p1; + p1.set_value(); + + boost::fibers::shared_future< void > f1 = p1.get_future().share(); + BOOST_CHECK( f1.valid() ); + + // get + BOOST_CHECK( ! f1.get_exception_ptr() ); + f1.get(); + BOOST_CHECK( f1.valid() ); + + // throw broken_promise if promise is destroyed without set + { + boost::fibers::promise< void > p2; + f1 = p2.get_future().share(); + } + bool thrown = false; + try { + f1.get(); + } catch ( boost::fibers::broken_promise const&) { + thrown = true; + } + BOOST_CHECK( f1.valid() ); + BOOST_CHECK( thrown); +} + +void test_future_share() { + // future retrieved from promise is valid (if it is the first) + boost::fibers::promise< int > p1; + int i = 7; + p1.set_value( i); + + boost::fibers::future< int > f1 = p1.get_future(); + BOOST_CHECK( f1.valid() ); + + // share + boost::fibers::shared_future< int > sf1 = f1.share(); + BOOST_CHECK( sf1.valid() ); + BOOST_CHECK( ! f1.valid() ); + + // get + BOOST_CHECK( ! sf1.get_exception_ptr() ); + int j = sf1.get(); + BOOST_CHECK_EQUAL( i, j); + BOOST_CHECK( sf1.valid() ); +} + +void test_future_share_ref() { + // future retrieved from promise is valid (if it is the first) + boost::fibers::promise< int& > p1; + int i = 7; + p1.set_value( i); + + boost::fibers::future< int& > f1 = p1.get_future(); + BOOST_CHECK( f1.valid() ); + + // share + boost::fibers::shared_future< int& > sf1 = f1.share(); + BOOST_CHECK( sf1.valid() ); + BOOST_CHECK( ! f1.valid() ); + + // get + BOOST_CHECK( ! sf1.get_exception_ptr() ); + int & j = sf1.get(); + BOOST_CHECK( &i == &j); + BOOST_CHECK( sf1.valid() ); +} + +void test_future_share_void() { + // future retrieved from promise is valid (if it is the first) + boost::fibers::promise< void > p1; + p1.set_value(); + + boost::fibers::future< void > f1 = p1.get_future(); + BOOST_CHECK( f1.valid() ); + + // share + boost::fibers::shared_future< void > sf1 = f1.share(); + BOOST_CHECK( sf1.valid() ); + BOOST_CHECK( ! f1.valid() ); + + // get + BOOST_CHECK( ! sf1.get_exception_ptr() ); + sf1.get(); + BOOST_CHECK( sf1.valid() ); +} + +void test_shared_future_wait() { + // future retrieved from promise is valid (if it is the first) + boost::fibers::promise< int > p1; + boost::fibers::shared_future< int > f1 = p1.get_future().share(); + + // wait on future + p1.set_value( 7); + f1.wait(); + BOOST_CHECK( 7 == f1.get() ); +} + +void test_shared_future_wait_ref() { + // future retrieved from promise is valid (if it is the first) + boost::fibers::promise< int& > p1; + boost::fibers::shared_future< int& > f1 = p1.get_future().share(); + + // wait on future + int i = 7; + p1.set_value( i); + f1.wait(); + int & j = f1.get(); + BOOST_CHECK( &i == &j); +} + +void test_shared_future_wait_void() { + // future retrieved from promise is valid (if it is the first) + boost::fibers::promise< void > p1; + boost::fibers::shared_future< void > f1 = p1.get_future().share(); + + // wait on future + p1.set_value(); + f1.wait(); + f1.get(); + BOOST_CHECK( f1.valid() ); +} + +void test_shared_future_wait_for() { + // future retrieved from promise is valid (if it is the first) + boost::fibers::promise< int > p1; + boost::fibers::shared_future< int > f1 = p1.get_future().share(); + + boost::fibers::fiber( boost::fibers::launch::dispatch, fn11, std::move( p1) ).detach(); + + // wait on future + BOOST_CHECK( f1.valid() ); + boost::fibers::future_status status = f1.wait_for( ms(300) ); + BOOST_CHECK( boost::fibers::future_status::timeout == status); + + BOOST_CHECK( f1.valid() ); + status = f1.wait_for( ms(300) ); + BOOST_CHECK( boost::fibers::future_status::ready == status); + + BOOST_CHECK( f1.valid() ); + f1.wait(); +} + +void test_shared_future_wait_for_ref() { + // future retrieved from promise is valid (if it is the first) + boost::fibers::promise< int& > p1; + boost::fibers::shared_future< int& > f1 = p1.get_future().share(); + + boost::fibers::fiber( boost::fibers::launch::dispatch, fn12, std::move( p1) ).detach(); + + // wait on future + BOOST_CHECK( f1.valid() ); + boost::fibers::future_status status = f1.wait_for( ms(300) ); + BOOST_CHECK( boost::fibers::future_status::timeout == status); + + BOOST_CHECK( f1.valid() ); + status = f1.wait_for( ms(300) ); + BOOST_CHECK( boost::fibers::future_status::ready == status); + + BOOST_CHECK( f1.valid() ); + f1.wait(); +} + +void test_shared_future_wait_for_void() { + // future retrieved from promise is valid (if it is the first) + boost::fibers::promise< void > p1; + boost::fibers::shared_future< void > f1 = p1.get_future().share(); + + boost::fibers::fiber( boost::fibers::launch::dispatch, fn13, std::move( p1) ).detach(); + + // wait on future + BOOST_CHECK( f1.valid() ); + boost::fibers::future_status status = f1.wait_for( ms(300) ); + BOOST_CHECK( boost::fibers::future_status::timeout == status); + + BOOST_CHECK( f1.valid() ); + status = f1.wait_for( ms(300) ); + BOOST_CHECK( boost::fibers::future_status::ready == status); + + BOOST_CHECK( f1.valid() ); + f1.wait(); +} + +void test_shared_future_wait_until() { + // future retrieved from promise is valid (if it is the first) + boost::fibers::promise< int > p1; + boost::fibers::shared_future< int > f1 = p1.get_future().share(); + + boost::fibers::fiber( boost::fibers::launch::dispatch, fn11, std::move( p1) ).detach(); + + // wait on future + BOOST_CHECK( f1.valid() ); + boost::fibers::future_status status = f1.wait_until( Clock::now() + ms(300) ); + BOOST_CHECK( boost::fibers::future_status::timeout == status); + + BOOST_CHECK( f1.valid() ); + status = f1.wait_until( Clock::now() + ms(300) ); + BOOST_CHECK( boost::fibers::future_status::ready == status); + + BOOST_CHECK( f1.valid() ); + f1.wait(); +} + +void test_shared_future_wait_until_ref() { + // future retrieved from promise is valid (if it is the first) + boost::fibers::promise< int& > p1; + boost::fibers::shared_future< int& > f1 = p1.get_future().share(); + + boost::fibers::fiber( boost::fibers::launch::dispatch, fn12, std::move( p1) ).detach(); + + // wait on future + BOOST_CHECK( f1.valid() ); + boost::fibers::future_status status = f1.wait_until( Clock::now() + ms(300) ); + BOOST_CHECK( boost::fibers::future_status::timeout == status); + + BOOST_CHECK( f1.valid() ); + status = f1.wait_until( Clock::now() + ms(300) ); + BOOST_CHECK( boost::fibers::future_status::ready == status); + + BOOST_CHECK( f1.valid() ); + f1.wait(); +} + +void test_shared_future_wait_until_void() { + // future retrieved from promise is valid (if it is the first) + boost::fibers::promise< void > p1; + boost::fibers::shared_future< void > f1 = p1.get_future().share(); + + boost::fibers::fiber( boost::fibers::launch::dispatch, fn13, std::move( p1) ).detach(); + + // wait on future + BOOST_CHECK( f1.valid() ); + boost::fibers::future_status status = f1.wait_until( Clock::now() + ms(300) ); + BOOST_CHECK( boost::fibers::future_status::timeout == status); + + BOOST_CHECK( f1.valid() ); + status = f1.wait_until( Clock::now() + ms(300) ); + BOOST_CHECK( boost::fibers::future_status::ready == status); + + BOOST_CHECK( f1.valid() ); + f1.wait(); +} + +void test_shared_future_wait_with_fiber_1() { + boost::fibers::promise< int > p1; + boost::fibers::fiber( boost::fibers::launch::dispatch, fn1, & p1, 7).detach(); + + boost::fibers::shared_future< int > f1 = p1.get_future().share(); + + // wait on future + BOOST_CHECK( 7 == f1.get() ); +} + +void test_shared_future_wait_with_fiber_2() { + boost::fibers::fiber( boost::fibers::launch::dispatch, fn2).join(); +} + +void test_shared_future_move() { + // future retrieved from promise is valid (if it is the first) + boost::fibers::promise< int > p1; + boost::fibers::shared_future< int > f1 = p1.get_future().share(); + BOOST_CHECK( f1.valid() ); + + // move construction + boost::fibers::shared_future< int > f2( std::move( f1) ); + BOOST_CHECK( ! f1.valid() ); + BOOST_CHECK( f2.valid() ); + + // move assignment + f1 = std::move( f2); + BOOST_CHECK( f1.valid() ); + BOOST_CHECK( ! f2.valid() ); +} + +void test_shared_future_move_move() { + // future retrieved from promise is valid (if it is the first) + boost::fibers::promise< A > p1; + boost::fibers::shared_future< A > f1 = p1.get_future().share(); + BOOST_CHECK( f1.valid() ); + + // move construction + boost::fibers::shared_future< A > f2( std::move( f1) ); + BOOST_CHECK( ! f1.valid() ); + BOOST_CHECK( f2.valid() ); + + // move assignment + f1 = std::move( f2); + BOOST_CHECK( f1.valid() ); + BOOST_CHECK( ! f2.valid() ); +} + +void test_shared_future_move_ref() { + // future retrieved from promise is valid (if it is the first) + boost::fibers::promise< int& > p1; + boost::fibers::shared_future< int& > f1 = p1.get_future().share(); + BOOST_CHECK( f1.valid() ); + + // move construction + boost::fibers::shared_future< int& > f2( std::move( f1) ); + BOOST_CHECK( ! f1.valid() ); + BOOST_CHECK( f2.valid() ); + + // move assignment + f1 = std::move( f2); + BOOST_CHECK( f1.valid() ); + BOOST_CHECK( ! f2.valid() ); +} + +void test_shared_future_move_void() { + // future retrieved from promise is valid (if it is the first) + boost::fibers::promise< void > p1; + boost::fibers::shared_future< void > f1 = p1.get_future().share(); + BOOST_CHECK( f1.valid() ); + + // move construction + boost::fibers::shared_future< void > f2( std::move( f1) ); + BOOST_CHECK( ! f1.valid() ); + BOOST_CHECK( f2.valid() ); + + // move assignment + f1 = std::move( f2); + BOOST_CHECK( f1.valid() ); + BOOST_CHECK( ! f2.valid() ); +} + + +boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[]) { + boost::unit_test_framework::test_suite* test = + BOOST_TEST_SUITE("Boost.Fiber: shared_future test suite"); + + test->add(BOOST_TEST_CASE(test_shared_future_create)); + test->add(BOOST_TEST_CASE(test_shared_future_create_ref)); + test->add(BOOST_TEST_CASE(test_shared_future_create_void)); + test->add(BOOST_TEST_CASE(test_shared_future_move)); + test->add(BOOST_TEST_CASE(test_shared_future_move_move)); + test->add(BOOST_TEST_CASE(test_shared_future_move_ref)); + test->add(BOOST_TEST_CASE(test_shared_future_move_void)); + test->add(BOOST_TEST_CASE(test_shared_future_get)); + test->add(BOOST_TEST_CASE(test_shared_future_get_move)); + test->add(BOOST_TEST_CASE(test_shared_future_get_ref)); + test->add(BOOST_TEST_CASE(test_shared_future_get_void)); + test->add(BOOST_TEST_CASE(test_shared_future_wait)); + test->add(BOOST_TEST_CASE(test_shared_future_wait_ref)); + test->add(BOOST_TEST_CASE(test_shared_future_wait_void)); + test->add(BOOST_TEST_CASE(test_shared_future_wait_for)); + test->add(BOOST_TEST_CASE(test_shared_future_wait_for_ref)); + test->add(BOOST_TEST_CASE(test_shared_future_wait_for_void)); + test->add(BOOST_TEST_CASE(test_shared_future_wait_until)); + test->add(BOOST_TEST_CASE(test_shared_future_wait_until_ref)); + test->add(BOOST_TEST_CASE(test_shared_future_wait_until_void)); + test->add(BOOST_TEST_CASE(test_shared_future_wait_with_fiber_1)); + test->add(BOOST_TEST_CASE(test_shared_future_wait_with_fiber_2)); + + return test; +} diff --git a/src/boost/libs/fiber/test/test_shared_future_post.cpp b/src/boost/libs/fiber/test/test_shared_future_post.cpp new file mode 100644 index 00000000..2e429f31 --- /dev/null +++ b/src/boost/libs/fiber/test/test_shared_future_post.cpp @@ -0,0 +1,608 @@ +// (C) Copyright 2008-10 Anthony Williams +// 2015 Oliver Kowalke +// +// 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) + +#include <chrono> +#include <memory> +#include <stdexcept> +#include <string> +#include <utility> + +#include <boost/test/unit_test.hpp> + +#include <boost/fiber/all.hpp> + +typedef std::chrono::milliseconds ms; +typedef std::chrono::high_resolution_clock Clock; + +int gi = 7; + +struct my_exception : public std::runtime_error { + my_exception() : + std::runtime_error("my_exception") { + } +}; + +struct A { + A() = default; + + A( A const&) = delete; + A( A &&) = default; + + A & operator=( A const&) = delete; + A & operator=( A &&) = default; + + int value; +}; + +void fn1( boost::fibers::promise< int > * p, int i) { + boost::this_fiber::yield(); + p->set_value( i); +} + +void fn2() { + boost::fibers::promise< int > p; + boost::fibers::shared_future< int > f( p.get_future().share() ); + boost::this_fiber::yield(); + boost::fibers::fiber( boost::fibers::launch::post, fn1, & p, 7).detach(); + boost::this_fiber::yield(); + BOOST_CHECK( 7 == f.get() ); +} + +int fn3() { + return 3; +} + +void fn4() { +} + +int fn5() { + boost::throw_exception( my_exception() ); + return 3; +} + +void fn6() { + boost::throw_exception( my_exception() ); +} + +int & fn7() { + return gi; +} + +int fn8( int i) { + return i; +} + +A fn9() { + A a; + a.value = 3; + return a; +} + +A fn10() { + boost::throw_exception( my_exception() ); + return A(); +} + +void fn11( boost::fibers::promise< int > p) { + boost::this_fiber::sleep_for( ms(500) ); + p.set_value(3); +} + +void fn12( boost::fibers::promise< int& > p) { + boost::this_fiber::sleep_for( ms(500) ); + gi = 5; + p.set_value( gi); +} + +void fn13( boost::fibers::promise< void > p) { + boost::this_fiber::sleep_for( ms(500) ); + p.set_value(); +} + +// shared_future +void test_shared_future_create() { + { + // default constructed and assigned shared_future is not valid + boost::fibers::shared_future< int > f1; + boost::fibers::shared_future< int > f2 = f1; + BOOST_CHECK( ! f1.valid() ); + BOOST_CHECK( ! f2.valid() ); + } + + { + // shared_future retrieved from promise is valid + boost::fibers::promise< int > p; + boost::fibers::shared_future< int > f1 = p.get_future(); + boost::fibers::shared_future< int > f2 = f1; + BOOST_CHECK( f1.valid() ); + BOOST_CHECK( f2.valid() ); + } +} + +void test_shared_future_create_ref() { + { + // default constructed and assigned shared_future is not valid + boost::fibers::shared_future< int& > f1; + boost::fibers::shared_future< int& > f2 = f1; + BOOST_CHECK( ! f1.valid() ); + BOOST_CHECK( ! f2.valid() ); + } + + { + // shared_future retrieved from promise is valid + boost::fibers::promise< int& > p; + boost::fibers::shared_future< int& > f1 = p.get_future(); + boost::fibers::shared_future< int& > f2 = f1; + BOOST_CHECK( f1.valid() ); + BOOST_CHECK( f2.valid() ); + } +} + +void test_shared_future_create_void() { + { + // default constructed and assigned shared_future is not valid + boost::fibers::shared_future< void > f1; + boost::fibers::shared_future< void > f2 = f1; + BOOST_CHECK( ! f1.valid() ); + BOOST_CHECK( ! f2.valid() ); + } + + { + // shared_future retrieved from promise is valid + boost::fibers::promise< void > p; + boost::fibers::shared_future< void > f1 = p.get_future(); + boost::fibers::shared_future< void > f2 = f1; + BOOST_CHECK( f1.valid() ); + BOOST_CHECK( f2.valid() ); + } +} + +void test_shared_future_get() { + // future retrieved from promise is valid (if it is the first) + boost::fibers::promise< int > p1; + p1.set_value( 7); + + boost::fibers::shared_future< int > f1 = p1.get_future().share(); + BOOST_CHECK( f1.valid() ); + + // get + BOOST_CHECK( ! f1.get_exception_ptr() ); + BOOST_CHECK( 7 == f1.get() ); + BOOST_CHECK( f1.valid() ); + + // throw broken_promise if promise is destroyed without set + { + boost::fibers::promise< int > p2; + f1 = p2.get_future().share(); + } + bool thrown = false; + try { + f1.get(); + } catch ( boost::fibers::broken_promise const&) { + thrown = true; + } + BOOST_CHECK( f1.valid() ); + BOOST_CHECK( thrown); +} + +void test_shared_future_get_move() { + // future retrieved from promise is valid (if it is the first) + boost::fibers::promise< A > p1; + A a; a.value = 7; + p1.set_value( std::move( a) ); + + boost::fibers::shared_future< A > f1 = p1.get_future().share(); + BOOST_CHECK( f1.valid() ); + + // get + BOOST_CHECK( ! f1.get_exception_ptr() ); + BOOST_CHECK( 7 == f1.get().value); + BOOST_CHECK( f1.valid() ); + + // throw broken_promise if promise is destroyed without set + { + boost::fibers::promise< A > p2; + f1 = p2.get_future().share(); + } + bool thrown = false; + try { + f1.get(); + } catch ( boost::fibers::broken_promise const&) { + thrown = true; + } + BOOST_CHECK( f1.valid() ); + BOOST_CHECK( thrown); +} + +void test_shared_future_get_ref() { + // future retrieved from promise is valid (if it is the first) + boost::fibers::promise< int& > p1; + int i = 7; + p1.set_value( i); + + boost::fibers::shared_future< int& > f1 = p1.get_future().share(); + BOOST_CHECK( f1.valid() ); + + // get + BOOST_CHECK( ! f1.get_exception_ptr() ); + int & j = f1.get(); + BOOST_CHECK( &i == &j); + BOOST_CHECK( f1.valid() ); + + // throw broken_promise if promise is destroyed without set + { + boost::fibers::promise< int& > p2; + f1 = p2.get_future().share(); + } + bool thrown = false; + try { + f1.get(); + } catch ( boost::fibers::broken_promise const&) { + thrown = true; + } + BOOST_CHECK( f1.valid() ); + BOOST_CHECK( thrown); +} + + +void test_shared_future_get_void() { + // future retrieved from promise is valid (if it is the first) + boost::fibers::promise< void > p1; + p1.set_value(); + + boost::fibers::shared_future< void > f1 = p1.get_future().share(); + BOOST_CHECK( f1.valid() ); + + // get + BOOST_CHECK( ! f1.get_exception_ptr() ); + f1.get(); + BOOST_CHECK( f1.valid() ); + + // throw broken_promise if promise is destroyed without set + { + boost::fibers::promise< void > p2; + f1 = p2.get_future().share(); + } + bool thrown = false; + try { + f1.get(); + } catch ( boost::fibers::broken_promise const&) { + thrown = true; + } + BOOST_CHECK( f1.valid() ); + BOOST_CHECK( thrown); +} + +void test_future_share() { + // future retrieved from promise is valid (if it is the first) + boost::fibers::promise< int > p1; + int i = 7; + p1.set_value( i); + + boost::fibers::future< int > f1 = p1.get_future(); + BOOST_CHECK( f1.valid() ); + + // share + boost::fibers::shared_future< int > sf1 = f1.share(); + BOOST_CHECK( sf1.valid() ); + BOOST_CHECK( ! f1.valid() ); + + // get + BOOST_CHECK( ! sf1.get_exception_ptr() ); + int j = sf1.get(); + BOOST_CHECK_EQUAL( i, j); + BOOST_CHECK( sf1.valid() ); +} + +void test_future_share_ref() { + // future retrieved from promise is valid (if it is the first) + boost::fibers::promise< int& > p1; + int i = 7; + p1.set_value( i); + + boost::fibers::future< int& > f1 = p1.get_future(); + BOOST_CHECK( f1.valid() ); + + // share + boost::fibers::shared_future< int& > sf1 = f1.share(); + BOOST_CHECK( sf1.valid() ); + BOOST_CHECK( ! f1.valid() ); + + // get + BOOST_CHECK( ! sf1.get_exception_ptr() ); + int & j = sf1.get(); + BOOST_CHECK( &i == &j); + BOOST_CHECK( sf1.valid() ); +} + +void test_future_share_void() { + // future retrieved from promise is valid (if it is the first) + boost::fibers::promise< void > p1; + p1.set_value(); + + boost::fibers::future< void > f1 = p1.get_future(); + BOOST_CHECK( f1.valid() ); + + // share + boost::fibers::shared_future< void > sf1 = f1.share(); + BOOST_CHECK( sf1.valid() ); + BOOST_CHECK( ! f1.valid() ); + + // get + BOOST_CHECK( ! sf1.get_exception_ptr() ); + sf1.get(); + BOOST_CHECK( sf1.valid() ); +} + +void test_shared_future_wait() { + // future retrieved from promise is valid (if it is the first) + boost::fibers::promise< int > p1; + boost::fibers::shared_future< int > f1 = p1.get_future().share(); + + // wait on future + p1.set_value( 7); + f1.wait(); + BOOST_CHECK( 7 == f1.get() ); +} + +void test_shared_future_wait_ref() { + // future retrieved from promise is valid (if it is the first) + boost::fibers::promise< int& > p1; + boost::fibers::shared_future< int& > f1 = p1.get_future().share(); + + // wait on future + int i = 7; + p1.set_value( i); + f1.wait(); + int & j = f1.get(); + BOOST_CHECK( &i == &j); +} + +void test_shared_future_wait_void() { + // future retrieved from promise is valid (if it is the first) + boost::fibers::promise< void > p1; + boost::fibers::shared_future< void > f1 = p1.get_future().share(); + + // wait on future + p1.set_value(); + f1.wait(); + f1.get(); + BOOST_CHECK( f1.valid() ); +} + +void test_shared_future_wait_for() { + // future retrieved from promise is valid (if it is the first) + boost::fibers::promise< int > p1; + boost::fibers::shared_future< int > f1 = p1.get_future().share(); + + boost::fibers::fiber( boost::fibers::launch::post, fn11, std::move( p1) ).detach(); + + // wait on future + BOOST_CHECK( f1.valid() ); + boost::fibers::future_status status = f1.wait_for( ms(300) ); + BOOST_CHECK( boost::fibers::future_status::timeout == status); + + BOOST_CHECK( f1.valid() ); + status = f1.wait_for( ms(300) ); + BOOST_CHECK( boost::fibers::future_status::ready == status); + + BOOST_CHECK( f1.valid() ); + f1.wait(); +} + +void test_shared_future_wait_for_ref() { + // future retrieved from promise is valid (if it is the first) + boost::fibers::promise< int& > p1; + boost::fibers::shared_future< int& > f1 = p1.get_future().share(); + + boost::fibers::fiber( boost::fibers::launch::post, fn12, std::move( p1) ).detach(); + + // wait on future + BOOST_CHECK( f1.valid() ); + boost::fibers::future_status status = f1.wait_for( ms(300) ); + BOOST_CHECK( boost::fibers::future_status::timeout == status); + + BOOST_CHECK( f1.valid() ); + status = f1.wait_for( ms(300) ); + BOOST_CHECK( boost::fibers::future_status::ready == status); + + BOOST_CHECK( f1.valid() ); + f1.wait(); +} + +void test_shared_future_wait_for_void() { + // future retrieved from promise is valid (if it is the first) + boost::fibers::promise< void > p1; + boost::fibers::shared_future< void > f1 = p1.get_future().share(); + + boost::fibers::fiber( boost::fibers::launch::post, fn13, std::move( p1) ).detach(); + + // wait on future + BOOST_CHECK( f1.valid() ); + boost::fibers::future_status status = f1.wait_for( ms(300) ); + BOOST_CHECK( boost::fibers::future_status::timeout == status); + + BOOST_CHECK( f1.valid() ); + status = f1.wait_for( ms(300) ); + BOOST_CHECK( boost::fibers::future_status::ready == status); + + BOOST_CHECK( f1.valid() ); + f1.wait(); +} + +void test_shared_future_wait_until() { + // future retrieved from promise is valid (if it is the first) + boost::fibers::promise< int > p1; + boost::fibers::shared_future< int > f1 = p1.get_future().share(); + + boost::fibers::fiber( boost::fibers::launch::post, fn11, std::move( p1) ).detach(); + + // wait on future + BOOST_CHECK( f1.valid() ); + boost::fibers::future_status status = f1.wait_until( Clock::now() + ms(300) ); + BOOST_CHECK( boost::fibers::future_status::timeout == status); + + BOOST_CHECK( f1.valid() ); + status = f1.wait_until( Clock::now() + ms(300) ); + BOOST_CHECK( boost::fibers::future_status::ready == status); + + BOOST_CHECK( f1.valid() ); + f1.wait(); +} + +void test_shared_future_wait_until_ref() { + // future retrieved from promise is valid (if it is the first) + boost::fibers::promise< int& > p1; + boost::fibers::shared_future< int& > f1 = p1.get_future().share(); + + boost::fibers::fiber( boost::fibers::launch::post, fn12, std::move( p1) ).detach(); + + // wait on future + BOOST_CHECK( f1.valid() ); + boost::fibers::future_status status = f1.wait_until( Clock::now() + ms(300) ); + BOOST_CHECK( boost::fibers::future_status::timeout == status); + + BOOST_CHECK( f1.valid() ); + status = f1.wait_until( Clock::now() + ms(300) ); + BOOST_CHECK( boost::fibers::future_status::ready == status); + + BOOST_CHECK( f1.valid() ); + f1.wait(); +} + +void test_shared_future_wait_until_void() { + // future retrieved from promise is valid (if it is the first) + boost::fibers::promise< void > p1; + boost::fibers::shared_future< void > f1 = p1.get_future().share(); + + boost::fibers::fiber( boost::fibers::launch::post, fn13, std::move( p1) ).detach(); + + // wait on future + BOOST_CHECK( f1.valid() ); + boost::fibers::future_status status = f1.wait_until( Clock::now() + ms(300) ); + BOOST_CHECK( boost::fibers::future_status::timeout == status); + + BOOST_CHECK( f1.valid() ); + status = f1.wait_until( Clock::now() + ms(300) ); + BOOST_CHECK( boost::fibers::future_status::ready == status); + + BOOST_CHECK( f1.valid() ); + f1.wait(); +} + +void test_shared_future_wait_with_fiber_1() { + boost::fibers::promise< int > p1; + boost::fibers::fiber( boost::fibers::launch::post, fn1, & p1, 7).detach(); + + boost::fibers::shared_future< int > f1 = p1.get_future().share(); + + // wait on future + BOOST_CHECK( 7 == f1.get() ); +} + +void test_shared_future_wait_with_fiber_2() { + boost::fibers::fiber( boost::fibers::launch::post, fn2).join(); +} + +void test_shared_future_move() { + // future retrieved from promise is valid (if it is the first) + boost::fibers::promise< int > p1; + boost::fibers::shared_future< int > f1 = p1.get_future().share(); + BOOST_CHECK( f1.valid() ); + + // move construction + boost::fibers::shared_future< int > f2( std::move( f1) ); + BOOST_CHECK( ! f1.valid() ); + BOOST_CHECK( f2.valid() ); + + // move assignment + f1 = std::move( f2); + BOOST_CHECK( f1.valid() ); + BOOST_CHECK( ! f2.valid() ); +} + +void test_shared_future_move_move() { + // future retrieved from promise is valid (if it is the first) + boost::fibers::promise< A > p1; + boost::fibers::shared_future< A > f1 = p1.get_future().share(); + BOOST_CHECK( f1.valid() ); + + // move construction + boost::fibers::shared_future< A > f2( std::move( f1) ); + BOOST_CHECK( ! f1.valid() ); + BOOST_CHECK( f2.valid() ); + + // move assignment + f1 = std::move( f2); + BOOST_CHECK( f1.valid() ); + BOOST_CHECK( ! f2.valid() ); +} + +void test_shared_future_move_ref() { + // future retrieved from promise is valid (if it is the first) + boost::fibers::promise< int& > p1; + boost::fibers::shared_future< int& > f1 = p1.get_future().share(); + BOOST_CHECK( f1.valid() ); + + // move construction + boost::fibers::shared_future< int& > f2( std::move( f1) ); + BOOST_CHECK( ! f1.valid() ); + BOOST_CHECK( f2.valid() ); + + // move assignment + f1 = std::move( f2); + BOOST_CHECK( f1.valid() ); + BOOST_CHECK( ! f2.valid() ); +} + +void test_shared_future_move_void() { + // future retrieved from promise is valid (if it is the first) + boost::fibers::promise< void > p1; + boost::fibers::shared_future< void > f1 = p1.get_future().share(); + BOOST_CHECK( f1.valid() ); + + // move construction + boost::fibers::shared_future< void > f2( std::move( f1) ); + BOOST_CHECK( ! f1.valid() ); + BOOST_CHECK( f2.valid() ); + + // move assignment + f1 = std::move( f2); + BOOST_CHECK( f1.valid() ); + BOOST_CHECK( ! f2.valid() ); +} + + +boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[]) { + boost::unit_test_framework::test_suite* test = + BOOST_TEST_SUITE("Boost.Fiber: shared_future test suite"); + + test->add(BOOST_TEST_CASE(test_shared_future_create)); + test->add(BOOST_TEST_CASE(test_shared_future_create_ref)); + test->add(BOOST_TEST_CASE(test_shared_future_create_void)); + test->add(BOOST_TEST_CASE(test_shared_future_move)); + test->add(BOOST_TEST_CASE(test_shared_future_move_move)); + test->add(BOOST_TEST_CASE(test_shared_future_move_ref)); + test->add(BOOST_TEST_CASE(test_shared_future_move_void)); + test->add(BOOST_TEST_CASE(test_shared_future_get)); + test->add(BOOST_TEST_CASE(test_shared_future_get_move)); + test->add(BOOST_TEST_CASE(test_shared_future_get_ref)); + test->add(BOOST_TEST_CASE(test_shared_future_get_void)); + test->add(BOOST_TEST_CASE(test_shared_future_wait)); + test->add(BOOST_TEST_CASE(test_shared_future_wait_ref)); + test->add(BOOST_TEST_CASE(test_shared_future_wait_void)); + test->add(BOOST_TEST_CASE(test_shared_future_wait_for)); + test->add(BOOST_TEST_CASE(test_shared_future_wait_for_ref)); + test->add(BOOST_TEST_CASE(test_shared_future_wait_for_void)); + test->add(BOOST_TEST_CASE(test_shared_future_wait_until)); + test->add(BOOST_TEST_CASE(test_shared_future_wait_until_ref)); + test->add(BOOST_TEST_CASE(test_shared_future_wait_until_void)); + test->add(BOOST_TEST_CASE(test_shared_future_wait_with_fiber_1)); + test->add(BOOST_TEST_CASE(test_shared_future_wait_with_fiber_2)); + + return test; +} diff --git a/src/boost/libs/fiber/test/test_unbuffered_channel_dispatch.cpp b/src/boost/libs/fiber/test/test_unbuffered_channel_dispatch.cpp new file mode 100644 index 00000000..22650576 --- /dev/null +++ b/src/boost/libs/fiber/test/test_unbuffered_channel_dispatch.cpp @@ -0,0 +1,451 @@ + +// Copyright Oliver Kowalke 2013. +// 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) + +#include <chrono> +#include <sstream> +#include <string> +#include <vector> + +#include <boost/assert.hpp> +#include <boost/test/unit_test.hpp> + +#include <boost/fiber/all.hpp> + +struct moveable { + bool state; + int value; + + moveable() : + state( false), + value( -1) { + } + + moveable( int v) : + state( true), + value( v) { + } + + moveable( moveable && other) : + state( other.state), + value( other.value) { + other.state = false; + other.value = -1; + } + + moveable & operator=( moveable && other) { + if ( this == & other) return * this; + state = other.state; + other.state = false; + value = other.value; + other.value = -1; + return * this; + } +}; + +void test_push() { + boost::fibers::unbuffered_channel< int > c; + boost::fibers::fiber f( boost::fibers::launch::dispatch, [&c](){ + BOOST_CHECK( boost::fibers::channel_op_status::success == c.push( 1) ); + }); + int value = 0; + BOOST_CHECK( boost::fibers::channel_op_status::success == c.pop( value) ); + BOOST_CHECK_EQUAL( 1, value); + f.join(); +} + +void test_push_closed() { + boost::fibers::unbuffered_channel< int > c; + c.close(); + BOOST_CHECK( boost::fibers::channel_op_status::closed == c.push( 1) ); +} + + +void test_push_wait_for() { + boost::fibers::unbuffered_channel< int > c; + boost::fibers::fiber f( boost::fibers::launch::dispatch, [&c](){ + BOOST_CHECK( boost::fibers::channel_op_status::success == c.push_wait_for( 1, std::chrono::seconds( 1) ) ); + }); + int value = 0; + BOOST_CHECK( boost::fibers::channel_op_status::success == c.pop( value) ); + BOOST_CHECK_EQUAL( 1, value); + f.join(); +} + +void test_push_wait_for_closed() { + boost::fibers::unbuffered_channel< int > c; + c.close(); + BOOST_CHECK( boost::fibers::channel_op_status::closed == c.push_wait_for( 1, std::chrono::seconds( 1) ) ); +} + +void test_push_wait_for_timeout() { + boost::fibers::unbuffered_channel< int > c; + boost::fibers::fiber f( boost::fibers::launch::dispatch, [&c](){ + int value = 0; + BOOST_CHECK( boost::fibers::channel_op_status::success == c.pop( value) ); + BOOST_CHECK_EQUAL( 1, value); + }); + BOOST_CHECK( boost::fibers::channel_op_status::success == c.push_wait_for( 1, std::chrono::seconds( 1) ) ); + BOOST_CHECK( boost::fibers::channel_op_status::timeout == c.push_wait_for( 1, std::chrono::seconds( 1) ) ); + f.join(); +} + +void test_push_wait_until() { + boost::fibers::unbuffered_channel< int > c; + boost::fibers::fiber f( boost::fibers::launch::dispatch, [&c](){ + BOOST_CHECK( boost::fibers::channel_op_status::success == c.push_wait_until( 1, + std::chrono::system_clock::now() + std::chrono::seconds( 1) ) ); + }); + int value = 0; + BOOST_CHECK( boost::fibers::channel_op_status::success == c.pop( value) ); + BOOST_CHECK_EQUAL( 1, value); + f.join(); +} + +void test_push_wait_until_closed() { + boost::fibers::unbuffered_channel< int > c; + c.close(); + BOOST_CHECK( boost::fibers::channel_op_status::closed == c.push_wait_until( 1, + std::chrono::system_clock::now() + std::chrono::seconds( 1) ) ); +} + +void test_push_wait_until_timeout() { + boost::fibers::unbuffered_channel< int > c; + boost::fibers::fiber f( boost::fibers::launch::dispatch, [&c](){ + int value = 0; + BOOST_CHECK( boost::fibers::channel_op_status::success == c.pop( value) ); + BOOST_CHECK_EQUAL( 1, value); + }); + BOOST_CHECK( boost::fibers::channel_op_status::success == c.push_wait_until( 1, + std::chrono::system_clock::now() + std::chrono::seconds( 1) ) ); + BOOST_CHECK( boost::fibers::channel_op_status::timeout == c.push_wait_until( 1, + std::chrono::system_clock::now() + std::chrono::seconds( 1) ) ); + f.join(); +} + +void test_pop() { + boost::fibers::unbuffered_channel< int > c; + int v1 = 2, v2 = 0; + boost::fibers::fiber f( boost::fibers::launch::dispatch, [&v1,&c](){ + BOOST_CHECK( boost::fibers::channel_op_status::success == c.push( v1) ); + }); + BOOST_CHECK( boost::fibers::channel_op_status::success == c.pop( v2) ); + BOOST_CHECK_EQUAL( v1, v2); + f.join(); +} + +void test_pop_closed() { + boost::fibers::unbuffered_channel< int > c; + int v1 = 2, v2 = 0; + boost::fibers::fiber f( boost::fibers::launch::dispatch, [&v1,&c](){ + BOOST_CHECK( boost::fibers::channel_op_status::success == c.push( v1) ); + c.close(); + }); + BOOST_CHECK( boost::fibers::channel_op_status::success == c.pop( v2) ); + BOOST_CHECK_EQUAL( v1, v2); + BOOST_CHECK( boost::fibers::channel_op_status::closed == c.pop( v2) ); + f.join(); +} + +void test_pop_success() { + boost::fibers::unbuffered_channel< int > c; + int v1 = 2, v2 = 0; + boost::fibers::fiber f( boost::fibers::launch::dispatch, [&c,&v2](){ + BOOST_CHECK( boost::fibers::channel_op_status::success == c.pop( v2) ); + }); + BOOST_CHECK( boost::fibers::channel_op_status::success == c.push( v1) ); + f.join(); + BOOST_CHECK_EQUAL( v1, v2); +} + +void test_value_pop() { + boost::fibers::unbuffered_channel< int > c; + int v1 = 2, v2 = 0; + boost::fibers::fiber f( boost::fibers::launch::dispatch, [&c,&v1](){ + BOOST_CHECK( boost::fibers::channel_op_status::success == c.push( v1) ); + }); + v2 = c.value_pop(); + f.join(); + BOOST_CHECK_EQUAL( v1, v2); +} + +void test_value_pop_closed() { + boost::fibers::unbuffered_channel< int > c; + int v1 = 2; + boost::fibers::fiber f( boost::fibers::launch::dispatch, [&c,&v1](){ + BOOST_CHECK( boost::fibers::channel_op_status::success == c.push( v1) ); + c.close(); + }); + int v2 = c.value_pop(); + BOOST_CHECK_EQUAL( v1, v2); + f.join(); + bool thrown = false; + try { + c.value_pop(); + } catch ( boost::fibers::fiber_error const&) { + thrown = true; + } + BOOST_CHECK( thrown); +} + +void test_value_pop_success() { + boost::fibers::unbuffered_channel< int > c; + int v1 = 2, v2 = 0; + boost::fibers::fiber f( boost::fibers::launch::dispatch, [&c,&v2](){ + v2 = c.value_pop(); + }); + BOOST_CHECK( boost::fibers::channel_op_status::success == c.push( v1) ); + f.join(); + BOOST_CHECK_EQUAL( v1, v2); +} + +void test_pop_wait_for() { + boost::fibers::unbuffered_channel< int > c; + int v1 = 2, v2 = 0; + boost::fibers::fiber f( boost::fibers::launch::dispatch, [&c,&v1](){ + BOOST_CHECK( boost::fibers::channel_op_status::success == c.push( v1) ); + }); + BOOST_CHECK( boost::fibers::channel_op_status::success == c.pop_wait_for( v2, std::chrono::seconds( 1) ) ); + f.join(); + BOOST_CHECK_EQUAL( v1, v2); +} + +void test_pop_wait_for_closed() { + boost::fibers::unbuffered_channel< int > c; + int v1 = 2, v2 = 0; + boost::fibers::fiber f( boost::fibers::launch::dispatch, [&c,&v1](){ + BOOST_CHECK( boost::fibers::channel_op_status::success == c.push( v1) ); + c.close(); + }); + BOOST_CHECK( boost::fibers::channel_op_status::success == c.pop_wait_for( v2, std::chrono::seconds( 1) ) ); + BOOST_CHECK_EQUAL( v1, v2); + BOOST_CHECK( boost::fibers::channel_op_status::closed == c.pop_wait_for( v2, std::chrono::seconds( 1) ) ); + f.join(); +} + +void test_pop_wait_for_success() { + boost::fibers::unbuffered_channel< int > c; + int v1 = 2, v2 = 0; + boost::fibers::fiber f( boost::fibers::launch::dispatch, [&c,&v2](){ + BOOST_CHECK( boost::fibers::channel_op_status::success == c.pop_wait_for( v2, std::chrono::seconds( 1) ) ); + }); + BOOST_CHECK( boost::fibers::channel_op_status::success == c.push( v1) ); + f.join(); + BOOST_CHECK_EQUAL( v1, v2); +} + +void test_pop_wait_for_timeout() { + boost::fibers::unbuffered_channel< int > c; + int v = 0; + boost::fibers::fiber f( boost::fibers::launch::dispatch, [&c,&v](){ + BOOST_CHECK( boost::fibers::channel_op_status::timeout == c.pop_wait_for( v, std::chrono::seconds( 1) ) ); + }); + f.join(); +} + +void test_pop_wait_until() { + boost::fibers::unbuffered_channel< int > c; + int v1 = 2, v2 = 0; + boost::fibers::fiber f( boost::fibers::launch::dispatch, [&c,&v1](){ + BOOST_CHECK( boost::fibers::channel_op_status::success == c.push( v1) ); + }); + BOOST_CHECK( boost::fibers::channel_op_status::success == c.pop_wait_until( v2, + std::chrono::system_clock::now() + std::chrono::seconds( 1) ) ); + BOOST_CHECK_EQUAL( v1, v2); + f.join(); +} + +void test_pop_wait_until_closed() { + boost::fibers::unbuffered_channel< int > c; + int v1 = 2, v2 = 0; + boost::fibers::fiber f( boost::fibers::launch::dispatch, [&c,&v1](){ + BOOST_CHECK( boost::fibers::channel_op_status::success == c.push( v1) ); + c.close(); + }); + BOOST_CHECK( boost::fibers::channel_op_status::success == c.pop_wait_until( v2, + std::chrono::system_clock::now() + std::chrono::seconds( 1) ) ); + BOOST_CHECK_EQUAL( v1, v2); + BOOST_CHECK( boost::fibers::channel_op_status::closed == c.pop_wait_until( v2, + std::chrono::system_clock::now() + std::chrono::seconds( 1) ) ); + f.join(); +} + +void test_pop_wait_until_success() { + boost::fibers::unbuffered_channel< int > c; + int v1 = 2, v2 = 0; + boost::fibers::fiber f( boost::fibers::launch::dispatch, [&c,&v2](){ + BOOST_CHECK( boost::fibers::channel_op_status::success == c.pop_wait_until( v2, + std::chrono::system_clock::now() + std::chrono::seconds( 1) ) ); + }); + BOOST_CHECK( boost::fibers::channel_op_status::success == c.push( v1) ); + f.join(); + BOOST_CHECK_EQUAL( v1, v2); +} + +void test_pop_wait_until_timeout() { + boost::fibers::unbuffered_channel< int > c; + int v = 0; + BOOST_CHECK( + boost::fibers::channel_op_status::timeout == c.pop_wait_until( v, + std::chrono::system_clock::now() + std::chrono::seconds( 1) ) ); +} + +void test_wm_1() { + boost::fibers::unbuffered_channel< int > c; + std::vector< boost::fibers::fiber::id > ids; + boost::fibers::fiber f1( boost::fibers::launch::dispatch, [&c,&ids](){ + ids.push_back( boost::this_fiber::get_id() ); + BOOST_CHECK( boost::fibers::channel_op_status::success == c.push( 1) ); + + ids.push_back( boost::this_fiber::get_id() ); + BOOST_CHECK( boost::fibers::channel_op_status::success == c.push( 2) ); + + ids.push_back( boost::this_fiber::get_id() ); + BOOST_CHECK( boost::fibers::channel_op_status::success == c.push( 3) ); + + ids.push_back( boost::this_fiber::get_id() ); + // would be blocked because channel is full + BOOST_CHECK( boost::fibers::channel_op_status::success == c.push( 4) ); + + ids.push_back( boost::this_fiber::get_id() ); + // would be blocked because channel is full + BOOST_CHECK( boost::fibers::channel_op_status::success == c.push( 5) ); + + ids.push_back( boost::this_fiber::get_id() ); + }); + boost::fibers::fiber f2( boost::fibers::launch::dispatch, [&c,&ids](){ + ids.push_back( boost::this_fiber::get_id() ); + BOOST_CHECK_EQUAL( 1, c.value_pop() ); + + // let other fiber run + boost::this_fiber::yield(); + + ids.push_back( boost::this_fiber::get_id() ); + BOOST_CHECK_EQUAL( 2, c.value_pop() ); + + ids.push_back( boost::this_fiber::get_id() ); + BOOST_CHECK_EQUAL( 3, c.value_pop() ); + + ids.push_back( boost::this_fiber::get_id() ); + BOOST_CHECK_EQUAL( 4, c.value_pop() ); + + ids.push_back( boost::this_fiber::get_id() ); + // would block because channel is empty + BOOST_CHECK_EQUAL( 5, c.value_pop() ); + + ids.push_back( boost::this_fiber::get_id() ); + }); + boost::fibers::fiber::id id1 = f1.get_id(); + boost::fibers::fiber::id id2 = f2.get_id(); + f1.join(); + f2.join(); + BOOST_CHECK_EQUAL( 12u, ids.size() ); + BOOST_CHECK_EQUAL( id1, ids[0]); + BOOST_CHECK_EQUAL( id2, ids[1]); + BOOST_CHECK_EQUAL( id1, ids[2]); + BOOST_CHECK_EQUAL( id2, ids[3]); + BOOST_CHECK_EQUAL( id2, ids[4]); + BOOST_CHECK_EQUAL( id1, ids[5]); + BOOST_CHECK_EQUAL( id2, ids[6]); + BOOST_CHECK_EQUAL( id1, ids[7]); + BOOST_CHECK_EQUAL( id2, ids[8]); + BOOST_CHECK_EQUAL( id1, ids[9]); + BOOST_CHECK_EQUAL( id2, ids[10]); + BOOST_CHECK_EQUAL( id1, ids[11]); +} + +void test_moveable() { + boost::fibers::unbuffered_channel< moveable > c; + boost::fibers::fiber f( boost::fibers::launch::dispatch, [&c]{ + moveable m1( 3); + BOOST_CHECK( m1.state); + BOOST_CHECK_EQUAL( 3, m1.value); + BOOST_CHECK( boost::fibers::channel_op_status::success == c.push( std::move( m1) ) ); + }); + moveable m2; + BOOST_CHECK( ! m2.state); + BOOST_CHECK_EQUAL( -1, m2.value); + BOOST_CHECK( boost::fibers::channel_op_status::success == c.pop( m2) ); + BOOST_CHECK( m2.state); + BOOST_CHECK_EQUAL( 3, m2.value); + f.join(); +} + +void test_rangefor() { + boost::fibers::unbuffered_channel< int > chan; + std::vector< int > vec; + boost::fibers::fiber f1( boost::fibers::launch::dispatch, [&chan]{ + chan.push( 1); + chan.push( 1); + chan.push( 2); + chan.push( 3); + chan.push( 5); + chan.push( 8); + chan.push( 12); + chan.close(); + }); + boost::fibers::fiber f2( boost::fibers::launch::dispatch, [&vec,&chan]{ + for ( int value : chan) { + vec.push_back( value); + } + }); + f1.join(); + f2.join(); + BOOST_CHECK_EQUAL( 1, vec[0]); + BOOST_CHECK_EQUAL( 1, vec[1]); + BOOST_CHECK_EQUAL( 2, vec[2]); + BOOST_CHECK_EQUAL( 3, vec[3]); + BOOST_CHECK_EQUAL( 5, vec[4]); + BOOST_CHECK_EQUAL( 8, vec[5]); + BOOST_CHECK_EQUAL( 12, vec[6]); +} + +void test_issue_181() { + boost::fibers::unbuffered_channel< int > chan; + boost::fibers::fiber f1( boost::fibers::launch::dispatch, [&chan]() { + auto state = chan.push( 1); + BOOST_CHECK( boost::fibers::channel_op_status::closed == state); + }); + boost::fibers::fiber f2( boost::fibers::launch::dispatch, [&chan]() { + boost::this_fiber::sleep_for( std::chrono::milliseconds( 100) ); + chan.close(); + }); + f2.join(); + f1.join(); +} + +boost::unit_test::test_suite * init_unit_test_suite( int, char* []) { + boost::unit_test::test_suite * test = + BOOST_TEST_SUITE("Boost.Fiber: unbuffered_channel test suite"); + + test->add( BOOST_TEST_CASE( & test_push) ); + test->add( BOOST_TEST_CASE( & test_push_closed) ); + test->add( BOOST_TEST_CASE( & test_push_wait_for) ); + test->add( BOOST_TEST_CASE( & test_push_wait_for_closed) ); + test->add( BOOST_TEST_CASE( & test_push_wait_for_timeout) ); + test->add( BOOST_TEST_CASE( & test_push_wait_until) ); + test->add( BOOST_TEST_CASE( & test_push_wait_until_closed) ); + test->add( BOOST_TEST_CASE( & test_push_wait_until_timeout) ); + test->add( BOOST_TEST_CASE( & test_pop) ); + test->add( BOOST_TEST_CASE( & test_pop_closed) ); + test->add( BOOST_TEST_CASE( & test_pop_success) ); + test->add( BOOST_TEST_CASE( & test_value_pop) ); + test->add( BOOST_TEST_CASE( & test_value_pop_closed) ); + test->add( BOOST_TEST_CASE( & test_value_pop_success) ); + test->add( BOOST_TEST_CASE( & test_pop_wait_for) ); + test->add( BOOST_TEST_CASE( & test_pop_wait_for_closed) ); + test->add( BOOST_TEST_CASE( & test_pop_wait_for_success) ); + test->add( BOOST_TEST_CASE( & test_pop_wait_for_timeout) ); + test->add( BOOST_TEST_CASE( & test_pop_wait_until) ); + test->add( BOOST_TEST_CASE( & test_pop_wait_until_closed) ); + test->add( BOOST_TEST_CASE( & test_pop_wait_until_success) ); + test->add( BOOST_TEST_CASE( & test_pop_wait_until_timeout) ); + test->add( BOOST_TEST_CASE( & test_wm_1) ); + test->add( BOOST_TEST_CASE( & test_moveable) ); + test->add( BOOST_TEST_CASE( & test_rangefor) ); + test->add( BOOST_TEST_CASE( & test_issue_181) ); + + return test; +} diff --git a/src/boost/libs/fiber/test/test_unbuffered_channel_post.cpp b/src/boost/libs/fiber/test/test_unbuffered_channel_post.cpp new file mode 100644 index 00000000..ff0f01de --- /dev/null +++ b/src/boost/libs/fiber/test/test_unbuffered_channel_post.cpp @@ -0,0 +1,451 @@ + +// Copyright Oliver Kowalke 2013. +// 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) + +#include <chrono> +#include <sstream> +#include <string> +#include <vector> + +#include <boost/assert.hpp> +#include <boost/test/unit_test.hpp> + +#include <boost/fiber/all.hpp> + +struct moveable { + bool state; + int value; + + moveable() : + state( false), + value( -1) { + } + + moveable( int v) : + state( true), + value( v) { + } + + moveable( moveable && other) : + state( other.state), + value( other.value) { + other.state = false; + other.value = -1; + } + + moveable & operator=( moveable && other) { + if ( this == & other) return * this; + state = other.state; + other.state = false; + value = other.value; + other.value = -1; + return * this; + } +}; + +void test_push() { + boost::fibers::unbuffered_channel< int > c; + boost::fibers::fiber f( boost::fibers::launch::post, [&c](){ + BOOST_CHECK( boost::fibers::channel_op_status::success == c.push( 1) ); + }); + int value = 0; + BOOST_CHECK( boost::fibers::channel_op_status::success == c.pop( value) ); + BOOST_CHECK_EQUAL( 1, value); + f.join(); +} + +void test_push_closed() { + boost::fibers::unbuffered_channel< int > c; + c.close(); + BOOST_CHECK( boost::fibers::channel_op_status::closed == c.push( 1) ); +} + + +void test_push_wait_for() { + boost::fibers::unbuffered_channel< int > c; + boost::fibers::fiber f( boost::fibers::launch::post, [&c](){ + BOOST_CHECK( boost::fibers::channel_op_status::success == c.push_wait_for( 1, std::chrono::seconds( 1) ) ); + }); + int value = 0; + BOOST_CHECK( boost::fibers::channel_op_status::success == c.pop( value) ); + BOOST_CHECK_EQUAL( 1, value); + f.join(); +} + +void test_push_wait_for_closed() { + boost::fibers::unbuffered_channel< int > c; + c.close(); + BOOST_CHECK( boost::fibers::channel_op_status::closed == c.push_wait_for( 1, std::chrono::seconds( 1) ) ); +} + +void test_push_wait_for_timeout() { + boost::fibers::unbuffered_channel< int > c; + boost::fibers::fiber f( boost::fibers::launch::post, [&c](){ + int value = 0; + BOOST_CHECK( boost::fibers::channel_op_status::success == c.pop( value) ); + BOOST_CHECK_EQUAL( 1, value); + }); + BOOST_CHECK( boost::fibers::channel_op_status::success == c.push_wait_for( 1, std::chrono::seconds( 1) ) ); + BOOST_CHECK( boost::fibers::channel_op_status::timeout == c.push_wait_for( 1, std::chrono::seconds( 1) ) ); + f.join(); +} + +void test_push_wait_until() { + boost::fibers::unbuffered_channel< int > c; + boost::fibers::fiber f( boost::fibers::launch::post, [&c](){ + BOOST_CHECK( boost::fibers::channel_op_status::success == c.push_wait_until( 1, + std::chrono::system_clock::now() + std::chrono::seconds( 1) ) ); + }); + int value = 0; + BOOST_CHECK( boost::fibers::channel_op_status::success == c.pop( value) ); + BOOST_CHECK_EQUAL( 1, value); + f.join(); +} + +void test_push_wait_until_closed() { + boost::fibers::unbuffered_channel< int > c; + c.close(); + BOOST_CHECK( boost::fibers::channel_op_status::closed == c.push_wait_until( 1, + std::chrono::system_clock::now() + std::chrono::seconds( 1) ) ); +} + +void test_push_wait_until_timeout() { + boost::fibers::unbuffered_channel< int > c; + boost::fibers::fiber f( boost::fibers::launch::post, [&c](){ + int value = 0; + BOOST_CHECK( boost::fibers::channel_op_status::success == c.pop( value) ); + BOOST_CHECK_EQUAL( 1, value); + }); + BOOST_CHECK( boost::fibers::channel_op_status::success == c.push_wait_until( 1, + std::chrono::system_clock::now() + std::chrono::seconds( 1) ) ); + BOOST_CHECK( boost::fibers::channel_op_status::timeout == c.push_wait_until( 1, + std::chrono::system_clock::now() + std::chrono::seconds( 1) ) ); + f.join(); +} + +void test_pop() { + boost::fibers::unbuffered_channel< int > c; + int v1 = 2, v2 = 0; + boost::fibers::fiber f( boost::fibers::launch::post, [&v1,&c](){ + BOOST_CHECK( boost::fibers::channel_op_status::success == c.push( v1) ); + }); + BOOST_CHECK( boost::fibers::channel_op_status::success == c.pop( v2) ); + BOOST_CHECK_EQUAL( v1, v2); + f.join(); +} + +void test_pop_closed() { + boost::fibers::unbuffered_channel< int > c; + int v1 = 2, v2 = 0; + boost::fibers::fiber f( boost::fibers::launch::post, [&v1,&c](){ + BOOST_CHECK( boost::fibers::channel_op_status::success == c.push( v1) ); + c.close(); + }); + BOOST_CHECK( boost::fibers::channel_op_status::success == c.pop( v2) ); + BOOST_CHECK_EQUAL( v1, v2); + BOOST_CHECK( boost::fibers::channel_op_status::closed == c.pop( v2) ); + f.join(); +} + +void test_pop_success() { + boost::fibers::unbuffered_channel< int > c; + int v1 = 2, v2 = 0; + boost::fibers::fiber f( boost::fibers::launch::post, [&c,&v2](){ + BOOST_CHECK( boost::fibers::channel_op_status::success == c.pop( v2) ); + }); + BOOST_CHECK( boost::fibers::channel_op_status::success == c.push( v1) ); + f.join(); + BOOST_CHECK_EQUAL( v1, v2); +} + +void test_value_pop() { + boost::fibers::unbuffered_channel< int > c; + int v1 = 2, v2 = 0; + boost::fibers::fiber f( boost::fibers::launch::post, [&c,&v1](){ + BOOST_CHECK( boost::fibers::channel_op_status::success == c.push( v1) ); + }); + v2 = c.value_pop(); + f.join(); + BOOST_CHECK_EQUAL( v1, v2); +} + +void test_value_pop_closed() { + boost::fibers::unbuffered_channel< int > c; + int v1 = 2; + boost::fibers::fiber f( boost::fibers::launch::post, [&c,&v1](){ + BOOST_CHECK( boost::fibers::channel_op_status::success == c.push( v1) ); + c.close(); + }); + int v2 = c.value_pop(); + BOOST_CHECK_EQUAL( v1, v2); + f.join(); + bool thrown = false; + try { + c.value_pop(); + } catch ( boost::fibers::fiber_error const&) { + thrown = true; + } + BOOST_CHECK( thrown); +} + +void test_value_pop_success() { + boost::fibers::unbuffered_channel< int > c; + int v1 = 2, v2 = 0; + boost::fibers::fiber f( boost::fibers::launch::post, [&c,&v2](){ + v2 = c.value_pop(); + }); + BOOST_CHECK( boost::fibers::channel_op_status::success == c.push( v1) ); + f.join(); + BOOST_CHECK_EQUAL( v1, v2); +} + +void test_pop_wait_for() { + boost::fibers::unbuffered_channel< int > c; + int v1 = 2, v2 = 0; + boost::fibers::fiber f( boost::fibers::launch::post, [&c,&v1](){ + BOOST_CHECK( boost::fibers::channel_op_status::success == c.push( v1) ); + }); + BOOST_CHECK( boost::fibers::channel_op_status::success == c.pop_wait_for( v2, std::chrono::seconds( 1) ) ); + f.join(); + BOOST_CHECK_EQUAL( v1, v2); +} + +void test_pop_wait_for_closed() { + boost::fibers::unbuffered_channel< int > c; + int v1 = 2, v2 = 0; + boost::fibers::fiber f( boost::fibers::launch::post, [&c,&v1](){ + BOOST_CHECK( boost::fibers::channel_op_status::success == c.push( v1) ); + c.close(); + }); + BOOST_CHECK( boost::fibers::channel_op_status::success == c.pop_wait_for( v2, std::chrono::seconds( 1) ) ); + BOOST_CHECK_EQUAL( v1, v2); + BOOST_CHECK( boost::fibers::channel_op_status::closed == c.pop_wait_for( v2, std::chrono::seconds( 1) ) ); + f.join(); +} + +void test_pop_wait_for_success() { + boost::fibers::unbuffered_channel< int > c; + int v1 = 2, v2 = 0; + boost::fibers::fiber f( boost::fibers::launch::post, [&c,&v2](){ + BOOST_CHECK( boost::fibers::channel_op_status::success == c.pop_wait_for( v2, std::chrono::seconds( 1) ) ); + }); + BOOST_CHECK( boost::fibers::channel_op_status::success == c.push( v1) ); + f.join(); + BOOST_CHECK_EQUAL( v1, v2); +} + +void test_pop_wait_for_timeout() { + boost::fibers::unbuffered_channel< int > c; + int v = 0; + boost::fibers::fiber f( boost::fibers::launch::post, [&c,&v](){ + BOOST_CHECK( boost::fibers::channel_op_status::timeout == c.pop_wait_for( v, std::chrono::seconds( 1) ) ); + }); + f.join(); +} + +void test_pop_wait_until() { + boost::fibers::unbuffered_channel< int > c; + int v1 = 2, v2 = 0; + boost::fibers::fiber f( boost::fibers::launch::post, [&c,&v1](){ + BOOST_CHECK( boost::fibers::channel_op_status::success == c.push( v1) ); + }); + BOOST_CHECK( boost::fibers::channel_op_status::success == c.pop_wait_until( v2, + std::chrono::system_clock::now() + std::chrono::seconds( 1) ) ); + BOOST_CHECK_EQUAL( v1, v2); + f.join(); +} + +void test_pop_wait_until_closed() { + boost::fibers::unbuffered_channel< int > c; + int v1 = 2, v2 = 0; + boost::fibers::fiber f( boost::fibers::launch::post, [&c,&v1](){ + BOOST_CHECK( boost::fibers::channel_op_status::success == c.push( v1) ); + c.close(); + }); + BOOST_CHECK( boost::fibers::channel_op_status::success == c.pop_wait_until( v2, + std::chrono::system_clock::now() + std::chrono::seconds( 1) ) ); + BOOST_CHECK_EQUAL( v1, v2); + BOOST_CHECK( boost::fibers::channel_op_status::closed == c.pop_wait_until( v2, + std::chrono::system_clock::now() + std::chrono::seconds( 1) ) ); + f.join(); +} + +void test_pop_wait_until_success() { + boost::fibers::unbuffered_channel< int > c; + int v1 = 2, v2 = 0; + boost::fibers::fiber f( boost::fibers::launch::post, [&c,&v2](){ + BOOST_CHECK( boost::fibers::channel_op_status::success == c.pop_wait_until( v2, + std::chrono::system_clock::now() + std::chrono::seconds( 1) ) ); + }); + BOOST_CHECK( boost::fibers::channel_op_status::success == c.push( v1) ); + f.join(); + BOOST_CHECK_EQUAL( v1, v2); +} + +void test_pop_wait_until_timeout() { + boost::fibers::unbuffered_channel< int > c; + int v = 0; + BOOST_CHECK( + boost::fibers::channel_op_status::timeout == c.pop_wait_until( v, + std::chrono::system_clock::now() + std::chrono::seconds( 1) ) ); +} + +void test_wm_1() { + boost::fibers::unbuffered_channel< int > c; + std::vector< boost::fibers::fiber::id > ids; + boost::fibers::fiber f1( boost::fibers::launch::post, [&c,&ids](){ + ids.push_back( boost::this_fiber::get_id() ); + BOOST_CHECK( boost::fibers::channel_op_status::success == c.push( 1) ); + + ids.push_back( boost::this_fiber::get_id() ); + BOOST_CHECK( boost::fibers::channel_op_status::success == c.push( 2) ); + + ids.push_back( boost::this_fiber::get_id() ); + BOOST_CHECK( boost::fibers::channel_op_status::success == c.push( 3) ); + + ids.push_back( boost::this_fiber::get_id() ); + // would be blocked because channel is full + BOOST_CHECK( boost::fibers::channel_op_status::success == c.push( 4) ); + + ids.push_back( boost::this_fiber::get_id() ); + // would be blocked because channel is full + BOOST_CHECK( boost::fibers::channel_op_status::success == c.push( 5) ); + + ids.push_back( boost::this_fiber::get_id() ); + }); + boost::fibers::fiber f2( boost::fibers::launch::post, [&c,&ids](){ + ids.push_back( boost::this_fiber::get_id() ); + BOOST_CHECK_EQUAL( 1, c.value_pop() ); + + // let other fiber run + boost::this_fiber::yield(); + + ids.push_back( boost::this_fiber::get_id() ); + BOOST_CHECK_EQUAL( 2, c.value_pop() ); + + ids.push_back( boost::this_fiber::get_id() ); + BOOST_CHECK_EQUAL( 3, c.value_pop() ); + + ids.push_back( boost::this_fiber::get_id() ); + BOOST_CHECK_EQUAL( 4, c.value_pop() ); + + ids.push_back( boost::this_fiber::get_id() ); + // would block because channel is empty + BOOST_CHECK_EQUAL( 5, c.value_pop() ); + + ids.push_back( boost::this_fiber::get_id() ); + }); + boost::fibers::fiber::id id1 = f1.get_id(); + boost::fibers::fiber::id id2 = f2.get_id(); + f1.join(); + f2.join(); + BOOST_CHECK_EQUAL( 12u, ids.size() ); + BOOST_CHECK_EQUAL( id1, ids[0]); + BOOST_CHECK_EQUAL( id2, ids[1]); + BOOST_CHECK_EQUAL( id1, ids[2]); + BOOST_CHECK_EQUAL( id2, ids[3]); + BOOST_CHECK_EQUAL( id2, ids[4]); + BOOST_CHECK_EQUAL( id1, ids[5]); + BOOST_CHECK_EQUAL( id2, ids[6]); + BOOST_CHECK_EQUAL( id1, ids[7]); + BOOST_CHECK_EQUAL( id2, ids[8]); + BOOST_CHECK_EQUAL( id1, ids[9]); + BOOST_CHECK_EQUAL( id2, ids[10]); + BOOST_CHECK_EQUAL( id1, ids[11]); +} + +void test_moveable() { + boost::fibers::unbuffered_channel< moveable > c; + boost::fibers::fiber f( boost::fibers::launch::post, [&c]{ + moveable m1( 3); + BOOST_CHECK( m1.state); + BOOST_CHECK_EQUAL( 3, m1.value); + BOOST_CHECK( boost::fibers::channel_op_status::success == c.push( std::move( m1) ) ); + }); + moveable m2; + BOOST_CHECK( ! m2.state); + BOOST_CHECK_EQUAL( -1, m2.value); + BOOST_CHECK( boost::fibers::channel_op_status::success == c.pop( m2) ); + BOOST_CHECK( m2.state); + BOOST_CHECK_EQUAL( 3, m2.value); + f.join(); +} + +void test_rangefor() { + boost::fibers::unbuffered_channel< int > chan; + std::vector< int > vec; + boost::fibers::fiber f1( boost::fibers::launch::post, [&chan]{ + chan.push( 1); + chan.push( 1); + chan.push( 2); + chan.push( 3); + chan.push( 5); + chan.push( 8); + chan.push( 12); + chan.close(); + }); + boost::fibers::fiber f2( boost::fibers::launch::post, [&vec,&chan]{ + for ( int value : chan) { + vec.push_back( value); + } + }); + f1.join(); + f2.join(); + BOOST_CHECK_EQUAL( 1, vec[0]); + BOOST_CHECK_EQUAL( 1, vec[1]); + BOOST_CHECK_EQUAL( 2, vec[2]); + BOOST_CHECK_EQUAL( 3, vec[3]); + BOOST_CHECK_EQUAL( 5, vec[4]); + BOOST_CHECK_EQUAL( 8, vec[5]); + BOOST_CHECK_EQUAL( 12, vec[6]); +} + +void test_issue_181() { + boost::fibers::unbuffered_channel< int > chan; + boost::fibers::fiber f1( boost::fibers::launch::post, [&chan]() { + auto state = chan.push( 1); + BOOST_CHECK( boost::fibers::channel_op_status::closed == state); + }); + boost::fibers::fiber f2( boost::fibers::launch::post, [&chan]() { + boost::this_fiber::sleep_for( std::chrono::milliseconds( 100) ); + chan.close(); + }); + f2.join(); + f1.join(); +} + +boost::unit_test::test_suite * init_unit_test_suite( int, char* []) { + boost::unit_test::test_suite * test = + BOOST_TEST_SUITE("Boost.Fiber: unbuffered_channel test suite"); + + test->add( BOOST_TEST_CASE( & test_push) ); + test->add( BOOST_TEST_CASE( & test_push_closed) ); + test->add( BOOST_TEST_CASE( & test_push_wait_for) ); + test->add( BOOST_TEST_CASE( & test_push_wait_for_closed) ); + test->add( BOOST_TEST_CASE( & test_push_wait_for_timeout) ); + test->add( BOOST_TEST_CASE( & test_push_wait_until) ); + test->add( BOOST_TEST_CASE( & test_push_wait_until_closed) ); + test->add( BOOST_TEST_CASE( & test_push_wait_until_timeout) ); + test->add( BOOST_TEST_CASE( & test_pop) ); + test->add( BOOST_TEST_CASE( & test_pop_closed) ); + test->add( BOOST_TEST_CASE( & test_pop_success) ); + test->add( BOOST_TEST_CASE( & test_value_pop) ); + test->add( BOOST_TEST_CASE( & test_value_pop_closed) ); + test->add( BOOST_TEST_CASE( & test_value_pop_success) ); + test->add( BOOST_TEST_CASE( & test_pop_wait_for) ); + test->add( BOOST_TEST_CASE( & test_pop_wait_for_closed) ); + test->add( BOOST_TEST_CASE( & test_pop_wait_for_success) ); + test->add( BOOST_TEST_CASE( & test_pop_wait_for_timeout) ); + test->add( BOOST_TEST_CASE( & test_pop_wait_until) ); + test->add( BOOST_TEST_CASE( & test_pop_wait_until_closed) ); + test->add( BOOST_TEST_CASE( & test_pop_wait_until_success) ); + test->add( BOOST_TEST_CASE( & test_pop_wait_until_timeout) ); + test->add( BOOST_TEST_CASE( & test_wm_1) ); + test->add( BOOST_TEST_CASE( & test_moveable) ); + test->add( BOOST_TEST_CASE( & test_rangefor) ); + test->add( BOOST_TEST_CASE( & test_issue_181) ); + + return test; +} |