From 5127e91864936e3ee907e564e59add75947cb435 Mon Sep 17 00:00:00 2001 From: James Hunsaker <18537138+jhunsaker@users.noreply.github.com> Date: Fri, 27 Mar 2026 17:57:57 -0400 Subject: [PATCH 01/15] Remove unused CUDA and HIP headers from fiber submodule Co-Authored-By: Claude Opus 4.6 --- examples/cuda/Makefile | 29 ------ examples/cuda/multiple_streams.cu | 112 --------------------- examples/cuda/single_stream.cu | 96 ------------------ examples/hip/Makefile | 29 ------ examples/hip/multiple_streams.cpp | 111 --------------------- examples/hip/single_stream.cpp | 96 ------------------ include/boost/fiber/cuda/waitfor.hpp | 139 --------------------------- include/boost/fiber/hip/waitfor.hpp | 139 --------------------------- 8 files changed, 751 deletions(-) delete mode 100644 examples/cuda/Makefile delete mode 100644 examples/cuda/multiple_streams.cu delete mode 100644 examples/cuda/single_stream.cu delete mode 100644 examples/hip/Makefile delete mode 100644 examples/hip/multiple_streams.cpp delete mode 100644 examples/hip/single_stream.cpp delete mode 100644 include/boost/fiber/cuda/waitfor.hpp delete mode 100644 include/boost/fiber/hip/waitfor.hpp diff --git a/examples/cuda/Makefile b/examples/cuda/Makefile deleted file mode 100644 index 60a3098e..00000000 --- a/examples/cuda/Makefile +++ /dev/null @@ -1,29 +0,0 @@ -CUDA_PATH := /opt/cuda - -NVCC := $(CUDA_PATH)/bin/nvcc - -CPPFLAGS := -O2 -std=c++11 -LDFLAGS := -g -L/usr/local/lib -INCLUDES := -I/usr/local/include -I$(CUDA_PATH)/include -LIBRARIES := -lboost_fiber -lboost_context -lboost_system -lboost_filesystem - -all: build - -build: single_stream multiple_streams - -single_stream.o:single_stream.cu - $(NVCC) $(INCLUDES) $(CPPFLAGS) -o $@ -c $< - -single_stream: single_stream.o - $(NVCC) $(LDFLAGS) -o $@ $+ $(LIBRARIES) - -multiple_streams.o:multiple_streams.cu - $(NVCC) $(INCLUDES) $(CPPFLAGS) -o $@ -c $< - -multiple_streams: multiple_streams.o - $(NVCC) $(LDFLAGS) -o $@ $+ $(LIBRARIES) - -clean: - rm -f single_stream single_stream.o multiple_streams multiple_streams.o - -clobber: clean diff --git a/examples/cuda/multiple_streams.cu b/examples/cuda/multiple_streams.cu deleted file mode 100644 index 0c665e29..00000000 --- a/examples/cuda/multiple_streams.cu +++ /dev/null @@ -1,112 +0,0 @@ - -// 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 -#include -#include -#include -#include -#include - -#include - -#include -#include -#include - -#include -#include - -__global__ -void vector_add( int * a, int * b, int * c, int size) { - int idx = threadIdx.x + blockIdx.x * blockDim.x; - if ( idx < size) { - c[idx] = a[idx] + b[idx]; - } -} - -int main() { - try { - bool done = false; - boost::fibers::fiber f1( [&done]{ - std::cout << "f1: entered" << std::endl; - try { - cudaStream_t stream0, stream1; - cudaStreamCreate( & stream0); - cudaStreamCreate( & stream1); - int size = 1024 * 1024; - int full_size = 20 * size; - int * host_a, * host_b, * host_c; - cudaHostAlloc( & host_a, full_size * sizeof( int), cudaHostAllocDefault); - cudaHostAlloc( & host_b, full_size * sizeof( int), cudaHostAllocDefault); - cudaHostAlloc( & host_c, full_size * sizeof( int), cudaHostAllocDefault); - int * dev_a0, * dev_b0, * dev_c0; - int * dev_a1, * dev_b1, * dev_c1; - cudaMalloc( & dev_a0, size * sizeof( int) ); - cudaMalloc( & dev_b0, size * sizeof( int) ); - cudaMalloc( & dev_c0, size * sizeof( int) ); - cudaMalloc( & dev_a1, size * sizeof( int) ); - cudaMalloc( & dev_b1, size * sizeof( int) ); - cudaMalloc( & dev_c1, size * sizeof( int) ); - std::minstd_rand generator; - std::uniform_int_distribution<> distribution(1, 6); - for ( int i = 0; i < full_size; ++i) { - host_a[i] = distribution( generator); - host_b[i] = distribution( generator); - } - for ( int i = 0; i < full_size; i += 2 * size) { - cudaMemcpyAsync( dev_a0, host_a + i, size * sizeof( int), cudaMemcpyHostToDevice, stream0); - cudaMemcpyAsync( dev_a1, host_a + i + size, size * sizeof( int), cudaMemcpyHostToDevice, stream1); - cudaMemcpyAsync( dev_b0, host_b + i, size * sizeof( int), cudaMemcpyHostToDevice, stream0); - cudaMemcpyAsync( dev_b1, host_b + i + size, size * sizeof( int), cudaMemcpyHostToDevice, stream1); - vector_add<<< size / 256, 256, 0, stream0 >>>( dev_a0, dev_b0, dev_c0, size); - vector_add<<< size / 256, 256, 0, stream1 >>>( dev_a1, dev_b1, dev_c1, size); - cudaMemcpyAsync( host_c + i, dev_c0, size * sizeof( int), cudaMemcpyDeviceToHost, stream0); - cudaMemcpyAsync( host_c + i + size, dev_c1, size * sizeof( int), cudaMemcpyDeviceToHost, stream1); - } - auto results = boost::fibers::cuda::waitfor_all( stream0, stream1); - for ( auto & result : results) { - BOOST_ASSERT( stream0 == std::get< 0 >( result) || stream1 == std::get< 0 >( result) ); - BOOST_ASSERT( cudaSuccess == std::get< 1 >( result) ); - } - std::cout << "f1: GPU computation finished" << std::endl; - cudaFreeHost( host_a); - cudaFreeHost( host_b); - cudaFreeHost( host_c); - cudaFree( dev_a0); - cudaFree( dev_b0); - cudaFree( dev_c0); - cudaFree( dev_a1); - cudaFree( dev_b1); - cudaFree( dev_c1); - cudaStreamDestroy( stream0); - cudaStreamDestroy( stream1); - done = true; - } catch ( std::exception const& ex) { - std::cerr << "exception: " << ex.what() << std::endl; - } - std::cout << "f1: leaving" << std::endl; - }); - boost::fibers::fiber f2([&done]{ - std::cout << "f2: entered" << std::endl; - while ( ! done) { - std::cout << "f2: sleeping" << std::endl; - boost::this_fiber::sleep_for( std::chrono::milliseconds( 1 ) ); - } - std::cout << "f2: leaving" << std::endl; - }); - f1.join(); - f2.join(); - std::cout << "done." << std::endl; - return EXIT_SUCCESS; - } catch ( std::exception const& e) { - std::cerr << "exception: " << e.what() << std::endl; - } catch (...) { - std::cerr << "unhandled exception" << std::endl; - } - return EXIT_FAILURE; -} diff --git a/examples/cuda/single_stream.cu b/examples/cuda/single_stream.cu deleted file mode 100644 index 79f398a1..00000000 --- a/examples/cuda/single_stream.cu +++ /dev/null @@ -1,96 +0,0 @@ - -// Copyright Oliver Kowalke 2017. -// 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 -#include -#include -#include -#include -#include - -#include - -#include -#include -#include - -#include -#include - -__global__ -void vector_add( int * a, int * b, int * c, int size) { - int idx = threadIdx.x + blockIdx.x * blockDim.x; - if ( idx < size) { - c[idx] = a[idx] + b[idx]; - } -} - -int main() { - try { - bool done = false; - boost::fibers::fiber f1([&done]{ - std::cout << "f1: entered" << std::endl; - try { - cudaStream_t stream; - cudaStreamCreate( & stream); - int size = 1024 * 1024; - int full_size = 20 * size; - int * host_a, * host_b, * host_c; - cudaHostAlloc( & host_a, full_size * sizeof( int), cudaHostAllocDefault); - cudaHostAlloc( & host_b, full_size * sizeof( int), cudaHostAllocDefault); - cudaHostAlloc( & host_c, full_size * sizeof( int), cudaHostAllocDefault); - int * dev_a, * dev_b, * dev_c; - cudaMalloc( & dev_a, size * sizeof( int) ); - cudaMalloc( & dev_b, size * sizeof( int) ); - cudaMalloc( & dev_c, size * sizeof( int) ); - std::minstd_rand generator; - std::uniform_int_distribution<> distribution(1, 6); - for ( int i = 0; i < full_size; ++i) { - host_a[i] = distribution( generator); - host_b[i] = distribution( generator); - } - for ( int i = 0; i < full_size; i += size) { - cudaMemcpyAsync( dev_a, host_a + i, size * sizeof( int), cudaMemcpyHostToDevice, stream); - cudaMemcpyAsync( dev_b, host_b + i, size * sizeof( int), cudaMemcpyHostToDevice, stream); - vector_add<<< size / 256, 256, 0, stream >>>( dev_a, dev_b, dev_c, size); - cudaMemcpyAsync( host_c + i, dev_c, size * sizeof( int), cudaMemcpyDeviceToHost, stream); - } - auto result = boost::fibers::cuda::waitfor_all( stream); - BOOST_ASSERT( stream == std::get< 0 >( result) ); - BOOST_ASSERT( cudaSuccess == std::get< 1 >( result) ); - std::cout << "f1: GPU computation finished" << std::endl; - cudaFreeHost( host_a); - cudaFreeHost( host_b); - cudaFreeHost( host_c); - cudaFree( dev_a); - cudaFree( dev_b); - cudaFree( dev_c); - cudaStreamDestroy( stream); - done = true; - } catch ( std::exception const& ex) { - std::cerr << "exception: " << ex.what() << std::endl; - } - std::cout << "f1: leaving" << std::endl; - }); - boost::fibers::fiber f2([&done]{ - std::cout << "f2: entered" << std::endl; - while ( ! done) { - std::cout << "f2: sleeping" << std::endl; - boost::this_fiber::sleep_for( std::chrono::milliseconds( 1 ) ); - } - std::cout << "f2: leaving" << std::endl; - }); - f1.join(); - f2.join(); - std::cout << "done." << std::endl; - return EXIT_SUCCESS; - } catch ( std::exception const& e) { - std::cerr << "exception: " << e.what() << std::endl; - } catch (...) { - std::cerr << "unhandled exception" << std::endl; - } - return EXIT_FAILURE; -} diff --git a/examples/hip/Makefile b/examples/hip/Makefile deleted file mode 100644 index d40e8c1a..00000000 --- a/examples/hip/Makefile +++ /dev/null @@ -1,29 +0,0 @@ -HIP_PATH := /opt/rocm/hip - -HIPCC := $(HIP_PATH)/bin/hipcc - -CPPFLAGS := -O2 -std=c++11 -LDFLAGS := -L/usr/local/lib -INCLUDES := -I/usr/local/include -I$(HIP_PATH)/include -LIBRARIES := -lboost_fiber -lboost_context -lboost_system -lboost_filesystem - -all: build - -build: single_stream multiple_streams - -single_stream.o:single_stream.cpp - $(HIPCC) $(INCLUDES) $(CPPFLAGS) -o $@ -c $< - -single_stream: single_stream.o - $(HIPCC) $(LDFLAGS) -o $@ $+ $(LIBRARIES) - -multiple_streams.o:multiple_streams.cpp - $(HIPCC) $(INCLUDES) $(CPPFLAGS) -o $@ -c $< - -multiple_streams: multiple_streams.o - $(HIPCC) $(LDFLAGS) -o $@ $+ $(LIBRARIES) - -clean: - rm -f single_stream single_stream.o multiple_streams multiple_streams.o - -clobber: clean diff --git a/examples/hip/multiple_streams.cpp b/examples/hip/multiple_streams.cpp deleted file mode 100644 index 75a7449c..00000000 --- a/examples/hip/multiple_streams.cpp +++ /dev/null @@ -1,111 +0,0 @@ - -// Copyright Oliver Kowalke 2017. -// 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 -#include -#include -#include -#include -#include - -#include - -#include -#include -#include - -#include -#include - -__global__ -void vector_add(hipLaunchParm lp, int * a, int * b, int * c, int size) { - int idx = threadIdx.x + blockIdx.x * blockDim.x; - if ( idx < size) { - c[idx] = a[idx] + b[idx]; - } -} - -int main() { - try { - bool done = false; - boost::fibers::fiber f1( [&done]{ - std::cout << "f1: entered" << std::endl; - try { - hipStream_t stream0, stream1; - hipStreamCreate( & stream0); - hipStreamCreate( & stream1); - int size = 1024 * 1024; - int full_size = 20 * size; - int * host_a, * host_b, * host_c; - hipHostMalloc( & host_a, full_size * sizeof( int), hipHostMallocDefault); - hipHostMalloc( & host_b, full_size * sizeof( int), hipHostMallocDefault); - hipHostMalloc( & host_c, full_size * sizeof( int), hipHostMallocDefault); - int * dev_a0, * dev_b0, * dev_c0; - int * dev_a1, * dev_b1, * dev_c1; - hipMalloc( & dev_a0, size * sizeof( int) ); - hipMalloc( & dev_b0, size * sizeof( int) ); - hipMalloc( & dev_c0, size * sizeof( int) ); - hipMalloc( & dev_a1, size * sizeof( int) ); - hipMalloc( & dev_b1, size * sizeof( int) ); - hipMalloc( & dev_c1, size * sizeof( int) ); - std::minstd_rand generator; - std::uniform_int_distribution<> distribution(1, 6); - for ( int i = 0; i < full_size; ++i) { - host_a[i] = distribution( generator); - host_b[i] = distribution( generator); - } - for ( int i = 0; i < full_size; i += 2 * size) { - hipMemcpyAsync( dev_a0, host_a + i, size * sizeof( int), hipMemcpyHostToDevice, stream0); - hipMemcpyAsync( dev_a1, host_a + i + size, size * sizeof( int), hipMemcpyHostToDevice, stream1); - hipMemcpyAsync( dev_b0, host_b + i, size * sizeof( int), hipMemcpyHostToDevice, stream0); - hipMemcpyAsync( dev_b1, host_b + i + size, size * sizeof( int), hipMemcpyHostToDevice, stream1); - hipLaunchKernel( vector_add, dim3(size / 256), dim3(256), 0, stream0, dev_a0, dev_b0, dev_c0, size); - hipLaunchKernel( vector_add, dim3(size / 256), dim3(256), 0, stream1, dev_a1, dev_b1, dev_c1, size); - hipMemcpyAsync( host_c + i, dev_c0, size * sizeof( int), hipMemcpyDeviceToHost, stream0); - hipMemcpyAsync( host_c + i + size, dev_c1, size * sizeof( int), hipMemcpyDeviceToHost, stream1); - } - auto results = boost::fibers::hip::waitfor_all( stream0, stream1); - for ( auto & result : results) { - BOOST_ASSERT( stream0 == std::get< 0 >( result) || stream1 == std::get< 0 >( result) ); - BOOST_ASSERT( hipSuccess == std::get< 1 >( result) ); - } - std::cout << "f1: GPU computation finished" << std::endl; - hipHostFree( host_a); - hipHostFree( host_b); - hipHostFree( host_c); - hipFree( dev_a0); - hipFree( dev_b0); - hipFree( dev_c0); - hipFree( dev_a1); - hipFree( dev_b1); - hipFree( dev_c1); - hipStreamDestroy( stream0); - hipStreamDestroy( stream1); - done = true; - } catch ( std::exception const& ex) { - std::cerr << "exception: " << ex.what() << std::endl; - } - std::cout << "f1: leaving" << std::endl; - }); - boost::fibers::fiber f2([&done]{ - std::cout << "f2: entered" << std::endl; - while ( ! done) { - std::cout << "f2: sleeping" << std::endl; - boost::this_fiber::sleep_for( std::chrono::milliseconds( 1 ) ); - } - std::cout << "f2: leaving" << std::endl; - }); - f1.join(); - f2.join(); - std::cout << "done." << std::endl; - return EXIT_SUCCESS; - } catch ( std::exception const& e) { - std::cerr << "exception: " << e.what() << std::endl; - } catch (...) { - std::cerr << "unhandled exception" << std::endl; - } - return EXIT_FAILURE; -} diff --git a/examples/hip/single_stream.cpp b/examples/hip/single_stream.cpp deleted file mode 100644 index 1959528e..00000000 --- a/examples/hip/single_stream.cpp +++ /dev/null @@ -1,96 +0,0 @@ - -// Copyright Oliver Kowalke 2017. -// 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 -#include -#include -#include -#include -#include - -#include - -#include -#include -#include - -#include -#include - -__global__ -void vector_add(hipLaunchParm lp, int * a, int * b, int * c, int size) { - int idx = threadIdx.x + blockIdx.x * blockDim.x; - if ( idx < size) { - c[idx] = a[idx] + b[idx]; - } -} - -int main() { - try { - bool done = false; - boost::fibers::fiber f1([&done]{ - std::cout << "f1: entered" << std::endl; - try { - hipStream_t stream; - hipStreamCreate( & stream); - int size = 1024 * 1024; - int full_size = 20 * size; - int * host_a, * host_b, * host_c; - hipHostMalloc( & host_a, full_size * sizeof( int), hipHostMallocDefault); - hipHostMalloc( & host_b, full_size * sizeof( int), hipHostMallocDefault); - hipHostMalloc( & host_c, full_size * sizeof( int), hipHostMallocDefault); - int * dev_a, * dev_b, * dev_c; - hipMalloc( & dev_a, size * sizeof( int) ); - hipMalloc( & dev_b, size * sizeof( int) ); - hipMalloc( & dev_c, size * sizeof( int) ); - std::minstd_rand generator; - std::uniform_int_distribution<> distribution(1, 6); - for ( int i = 0; i < full_size; ++i) { - host_a[i] = distribution( generator); - host_b[i] = distribution( generator); - } - for ( int i = 0; i < full_size; i += size) { - hipMemcpyAsync( dev_a, host_a + i, size * sizeof( int), hipMemcpyHostToDevice, stream); - hipMemcpyAsync( dev_b, host_b + i, size * sizeof( int), hipMemcpyHostToDevice, stream); - hipLaunchKernel( vector_add, dim3(size / 256), dim3(256), 0, stream, dev_a, dev_b, dev_c, size); - hipMemcpyAsync( host_c + i, dev_c, size * sizeof( int), hipMemcpyDeviceToHost, stream); - } - auto result = boost::fibers::hip::waitfor_all( stream); - BOOST_ASSERT( stream == std::get< 0 >( result) ); - BOOST_ASSERT( hipSuccess == std::get< 1 >( result) ); - std::cout << "f1: GPU computation finished" << std::endl; - hipHostFree( host_a); - hipHostFree( host_b); - hipHostFree( host_c); - hipFree( dev_a); - hipFree( dev_b); - hipFree( dev_c); - hipStreamDestroy( stream); - done = true; - } catch ( std::exception const& ex) { - std::cerr << "exception: " << ex.what() << std::endl; - } - std::cout << "f1: leaving" << std::endl; - }); - boost::fibers::fiber f2([&done]{ - std::cout << "f2: entered" << std::endl; - while ( ! done) { - std::cout << "f2: sleeping" << std::endl; - boost::this_fiber::sleep_for( std::chrono::milliseconds( 1 ) ); - } - std::cout << "f2: leaving" << std::endl; - }); - f1.join(); - f2.join(); - std::cout << "done." << std::endl; - return EXIT_SUCCESS; - } catch ( std::exception const& e) { - std::cerr << "exception: " << e.what() << std::endl; - } catch (...) { - std::cerr << "unhandled exception" << std::endl; - } - return EXIT_FAILURE; -} diff --git a/include/boost/fiber/cuda/waitfor.hpp b/include/boost/fiber/cuda/waitfor.hpp deleted file mode 100644 index 262efd9a..00000000 --- a/include/boost/fiber/cuda/waitfor.hpp +++ /dev/null @@ -1,139 +0,0 @@ - -// Copyright Oliver Kowalke 2017. -// 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) - -#ifndef BOOST_FIBERS_CUDA_WAITFOR_H -#define BOOST_FIBERS_CUDA_WAITFOR_H - -#include -#include -#include -#include -#include -#include - -#include -#include - -#include - -#include -#include -#include -#include - -#ifdef BOOST_HAS_ABI_HEADERS -# include BOOST_ABI_PREFIX -#endif - -namespace boost { -namespace fibers { -namespace cuda { -namespace detail { - -template< typename Rendezvous > -static void trampoline( cudaStream_t st, cudaError_t status, void * vp) { - Rendezvous * data = static_cast< Rendezvous * >( vp); - data->notify( st, status); -} - -class single_stream_rendezvous { -public: - single_stream_rendezvous( cudaStream_t st) { - unsigned int flags = 0; - cudaError_t status = ::cudaStreamAddCallback( st, trampoline< single_stream_rendezvous >, this, flags); - if ( cudaSuccess != status) { - st_ = st; - status_ = status; - done_ = true; - } - } - - void notify( cudaStream_t st, cudaError_t status) noexcept { - std::unique_lock< mutex > lk{ mtx_ }; - st_ = st; - status_ = status; - done_ = true; - lk.unlock(); - cv_.notify_one(); - } - - std::tuple< cudaStream_t, cudaError_t > wait() { - std::unique_lock< mutex > lk{ mtx_ }; - cv_.wait( lk, [this]{ return done_; }); - return std::make_tuple( st_, status_); - } - -private: - mutex mtx_{}; - condition_variable cv_{}; - cudaStream_t st_{}; - cudaError_t status_{ cudaErrorUnknown }; - bool done_{ false }; -}; - -class many_streams_rendezvous { -public: - many_streams_rendezvous( std::initializer_list< cudaStream_t > l) : - stx_{ l } { - results_.reserve( stx_.size() ); - for ( cudaStream_t st : stx_) { - unsigned int flags = 0; - cudaError_t status = ::cudaStreamAddCallback( st, trampoline< many_streams_rendezvous >, this, flags); - if ( cudaSuccess != status) { - std::unique_lock< mutex > lk{ mtx_ }; - stx_.erase( st); - results_.push_back( std::make_tuple( st, status) ); - } - } - } - - void notify( cudaStream_t st, cudaError_t status) noexcept { - std::unique_lock< mutex > lk{ mtx_ }; - stx_.erase( st); - results_.push_back( std::make_tuple( st, status) ); - if ( stx_.empty() ) { - lk.unlock(); - cv_.notify_one(); - } - } - - std::vector< std::tuple< cudaStream_t, cudaError_t > > wait() { - std::unique_lock< mutex > lk{ mtx_ }; - cv_.wait( lk, [this]{ return stx_.empty(); }); - return results_; - } - -private: - mutex mtx_{}; - condition_variable cv_{}; - std::set< cudaStream_t > stx_; - std::vector< std::tuple< cudaStream_t, cudaError_t > > results_; -}; - -} - -void waitfor_all(); - -inline -std::tuple< cudaStream_t, cudaError_t > waitfor_all( cudaStream_t st) { - detail::single_stream_rendezvous rendezvous( st); - return rendezvous.wait(); -} - -template< typename ... STP > -std::vector< std::tuple< cudaStream_t, cudaError_t > > waitfor_all( cudaStream_t st0, STP ... stx) { - static_assert( boost::fibers::detail::is_all_same< cudaStream_t, STP ...>::value, "all arguments must be of type `CUstream*`."); - detail::many_streams_rendezvous rendezvous{ st0, stx ... }; - return rendezvous.wait(); -} - -}}} - -#ifdef BOOST_HAS_ABI_HEADERS -# include BOOST_ABI_SUFFIX -#endif - -#endif // BOOST_FIBERS_CUDA_WAITFOR_H diff --git a/include/boost/fiber/hip/waitfor.hpp b/include/boost/fiber/hip/waitfor.hpp deleted file mode 100644 index e05099ef..00000000 --- a/include/boost/fiber/hip/waitfor.hpp +++ /dev/null @@ -1,139 +0,0 @@ - -// Copyright Oliver Kowalke 2017. -// 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) - -#ifndef BOOST_FIBERS_CUDA_WAITFOR_H -#define BOOST_FIBERS_CUDA_WAITFOR_H - -#include -#include -#include -#include -#include -#include - -#include -#include - -#include - -#include -#include -#include -#include - -#ifdef BOOST_HAS_ABI_HEADERS -# include BOOST_ABI_PREFIX -#endif - -namespace boost { -namespace fibers { -namespace cuda { -namespace detail { - -template< typename Rendezvous > -static void trampoline( hipStream_t st, hipError_t status, void * vp) { - Rendezvous * data = static_cast< Rendezvous * >( vp); - data->notify( st, status); -} - -class single_stream_rendezvous { -public: - single_stream_rendezvous( hipStream_t st) { - unsigned int flags = 0; - hipError_t status = ::hipStreamAddCallback( st, trampoline< single_stream_rendezvous >, this, flags); - if ( hipSuccess != status) { - st_ = st; - status_ = status; - done_ = true; - } - } - - void notify( hipStream_t st, hipError_t status) noexcept { - std::unique_lock< mutex > lk{ mtx_ }; - st_ = st; - status_ = status; - done_ = true; - lk.unlock(); - cv_.notify_one(); - } - - std::tuple< hipStream_t, hipError_t > wait() { - std::unique_lock< mutex > lk{ mtx_ }; - cv_.wait( lk, [this]{ return done_; }); - return std::make_tuple( st_, status_); - } - -private: - mutex mtx_{}; - condition_variable cv_{}; - hipStream_t st_{}; - hipError_t status_{ hipErrorUnknown }; - bool done_{ false }; -}; - -class many_streams_rendezvous { -public: - many_streams_rendezvous( std::initializer_list< hipStream_t > l) : - stx_{ l } { - results_.reserve( stx_.size() ); - for ( hipStream_t st : stx_) { - unsigned int flags = 0; - hipError_t status = ::hipStreamAddCallback( st, trampoline< many_streams_rendezvous >, this, flags); - if ( hipSuccess != status) { - std::unique_lock< mutex > lk{ mtx_ }; - stx_.erase( st); - results_.push_back( std::make_tuple( st, status) ); - } - } - } - - void notify( hipStream_t st, hipError_t status) noexcept { - std::unique_lock< mutex > lk{ mtx_ }; - stx_.erase( st); - results_.push_back( std::make_tuple( st, status) ); - if ( stx_.empty() ) { - lk.unlock(); - cv_.notify_one(); - } - } - - std::vector< std::tuple< hipStream_t, hipError_t > > wait() { - std::unique_lock< mutex > lk{ mtx_ }; - cv_.wait( lk, [this]{ return stx_.empty(); }); - return results_; - } - -private: - mutex mtx_{}; - condition_variable cv_{}; - std::set< hipStream_t > stx_; - std::vector< std::tuple< hipStream_t, hipError_t > > results_; -}; - -} - -void waitfor_all(); - -inline -std::tuple< hipStream_t, hipError_t > waitfor_all( hipStream_t st) { - detail::single_stream_rendezvous rendezvous( st); - return rendezvous.wait(); -} - -template< typename ... STP > -std::vector< std::tuple< hipStream_t, hipError_t > > waitfor_all( hipStream_t st0, STP ... stx) { - static_assert( boost::fibers::detail::is_all_same< hipStream_t, STP ...>::value, "all arguments must be of type `CUstream*`."); - detail::many_streams_rendezvous rendezvous{ st0, stx ... }; - return rendezvous.wait(); -} - -}}} - -#ifdef BOOST_HAS_ABI_HEADERS -# include BOOST_ABI_SUFFIX -#endif - -#endif // BOOST_FIBERS_CUDA_WAITFOR_H From 34bb6b62bd3d13f3bc6411ec8f6b6b7c2cdfdbd3 Mon Sep 17 00:00:00 2001 From: James Hunsaker <18537138+jhunsaker@users.noreply.github.com> Date: Fri, 27 Mar 2026 18:28:46 -0400 Subject: [PATCH 02/15] Remove timed and recursive mutex support These mutex types are unused by the top-level project. Removes source files, headers, and references from CMakeLists.txt and all.hpp. Co-Authored-By: Claude Opus 4.6 --- CMakeLists.txt | 3 - include/boost/fiber/all.hpp | 3 - include/boost/fiber/recursive_mutex.hpp | 75 ----- include/boost/fiber/recursive_timed_mutex.hpp | 90 ------ include/boost/fiber/timed_mutex.hpp | 84 ----- src/recursive_mutex.cpp | 77 ----- src/recursive_timed_mutex.cpp | 100 ------ src/timed_mutex.cpp | 95 ------ test/test_mutex_dispatch.cpp | 305 +----------------- test/test_mutex_mt_dispatch.cpp | 56 +--- test/test_mutex_mt_post.cpp | 56 +--- test/test_mutex_post.cpp | 305 +----------------- 12 files changed, 4 insertions(+), 1245 deletions(-) delete mode 100644 include/boost/fiber/recursive_mutex.hpp delete mode 100644 include/boost/fiber/recursive_timed_mutex.hpp delete mode 100644 include/boost/fiber/timed_mutex.hpp delete mode 100644 src/recursive_mutex.cpp delete mode 100644 src/recursive_timed_mutex.cpp delete mode 100644 src/timed_mutex.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index d786a6ed..f016d4c5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -20,10 +20,7 @@ add_library(boost_fiber src/future.cpp src/mutex.cpp src/properties.cpp - src/recursive_mutex.cpp - src/recursive_timed_mutex.cpp src/scheduler.cpp - src/timed_mutex.cpp src/waker.cpp ) diff --git a/include/boost/fiber/all.hpp b/include/boost/fiber/all.hpp index 460df529..0b607df8 100644 --- a/include/boost/fiber/all.hpp +++ b/include/boost/fiber/all.hpp @@ -27,11 +27,8 @@ #include #include #include -#include -#include #include #include -#include #include #include diff --git a/include/boost/fiber/recursive_mutex.hpp b/include/boost/fiber/recursive_mutex.hpp deleted file mode 100644 index a793eb1b..00000000 --- a/include/boost/fiber/recursive_mutex.hpp +++ /dev/null @@ -1,75 +0,0 @@ - -// 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) -// -// based on boost::interprocess::sync::interprocess_spinlock - -#ifndef BOOST_FIBERS_RECURSIVE_MUTEX_H -#define BOOST_FIBERS_RECURSIVE_MUTEX_H - -#include - -#include - -#include - -#include -#include -#include -#include - -#ifdef BOOST_HAS_ABI_HEADERS -# include BOOST_ABI_PREFIX -#endif - -#ifdef _MSC_VER -# pragma warning(push) -# pragma warning(disable:4251) -#endif - -namespace boost { -namespace fibers { - -class condition_variable; - -class BOOST_FIBERS_DECL recursive_mutex { -private: - friend class condition_variable; - - detail::spinlock wait_queue_splk_{}; - wait_queue wait_queue_{}; - context * owner_{ nullptr }; - std::size_t count_{ 0 }; - -public: - recursive_mutex() = default; - - ~recursive_mutex() { - BOOST_ASSERT( nullptr == owner_); - BOOST_ASSERT( 0 == count_); - BOOST_ASSERT( wait_queue_.empty() ); - } - - recursive_mutex( recursive_mutex const&) = delete; - recursive_mutex & operator=( recursive_mutex const&) = delete; - - void lock(); - - bool try_lock() noexcept; - - void unlock(); -}; - -}} - -#ifdef _MSC_VER -# pragma warning(pop) -#endif - -#ifdef BOOST_HAS_ABI_HEADERS -# include BOOST_ABI_SUFFIX -#endif - -#endif // BOOST_FIBERS_RECURSIVE_MUTEX_H diff --git a/include/boost/fiber/recursive_timed_mutex.hpp b/include/boost/fiber/recursive_timed_mutex.hpp deleted file mode 100644 index 96bc9273..00000000 --- a/include/boost/fiber/recursive_timed_mutex.hpp +++ /dev/null @@ -1,90 +0,0 @@ - -// 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) -// -// based on boost::interprocess::sync::interprocess_spinlock - -#ifndef BOOST_FIBERS_RECURSIVE_TIMED_MUTEX_H -#define BOOST_FIBERS_RECURSIVE_TIMED_MUTEX_H - -#include -#include - -#include - -#include - -#include -#include -#include -#include -#include - -#ifdef BOOST_HAS_ABI_HEADERS -# include BOOST_ABI_PREFIX -#endif - -#ifdef _MSC_VER -# pragma warning(push) -# pragma warning(disable:4251) -#endif - -namespace boost { -namespace fibers { - -class condition_variable; - -class BOOST_FIBERS_DECL recursive_timed_mutex { -private: - friend class condition_variable; - - detail::spinlock wait_queue_splk_{}; - wait_queue wait_queue_{}; - context * owner_{ nullptr }; - std::size_t count_{ 0 }; - - bool try_lock_until_( std::chrono::steady_clock::time_point const& timeout_time) noexcept; - -public: - recursive_timed_mutex() = default; - - ~recursive_timed_mutex() { - BOOST_ASSERT( nullptr == owner_); - BOOST_ASSERT( 0 == count_); - BOOST_ASSERT( wait_queue_.empty() ); - } - - recursive_timed_mutex( recursive_timed_mutex const&) = delete; - recursive_timed_mutex & operator=( recursive_timed_mutex const&) = delete; - - void lock(); - - bool try_lock() noexcept; - - template< typename Clock, typename Duration > - bool try_lock_until( std::chrono::time_point< Clock, Duration > const& timeout_time_) { - std::chrono::steady_clock::time_point timeout_time = detail::convert( timeout_time_); - return try_lock_until_( timeout_time); - } - - template< typename Rep, typename Period > - bool try_lock_for( std::chrono::duration< Rep, Period > const& timeout_duration) { - return try_lock_until_( std::chrono::steady_clock::now() + timeout_duration); - } - - void unlock(); -}; - -}} - -#ifdef _MSC_VER -# pragma warning(pop) -#endif - -#ifdef BOOST_HAS_ABI_HEADERS -# include BOOST_ABI_SUFFIX -#endif - -#endif // BOOST_FIBERS_RECURSIVE_TIMED_MUTEX_H diff --git a/include/boost/fiber/timed_mutex.hpp b/include/boost/fiber/timed_mutex.hpp deleted file mode 100644 index 3cdb91d3..00000000 --- a/include/boost/fiber/timed_mutex.hpp +++ /dev/null @@ -1,84 +0,0 @@ - -// 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) - -#ifndef BOOST_FIBERS_TIMED_MUTEX_H -#define BOOST_FIBERS_TIMED_MUTEX_H - -#include - -#include -#include - -#include -#include -#include -#include -#include - -#ifdef BOOST_HAS_ABI_HEADERS -# include BOOST_ABI_PREFIX -#endif - -#ifdef _MSC_VER -# pragma warning(push) -# pragma warning(disable:4251) -#endif - -namespace boost { -namespace fibers { - -class condition_variable; - -class BOOST_FIBERS_DECL timed_mutex { -private: - friend class condition_variable; - - detail::spinlock wait_queue_splk_{}; - wait_queue wait_queue_{}; - context * owner_{ nullptr }; - - bool try_lock_until_( std::chrono::steady_clock::time_point const& timeout_time) noexcept; - -public: - timed_mutex() = default; - - ~timed_mutex() { - BOOST_ASSERT( nullptr == owner_); - BOOST_ASSERT( wait_queue_.empty() ); - } - - timed_mutex( timed_mutex const&) = delete; - timed_mutex & operator=( timed_mutex const&) = delete; - - void lock(); - - bool try_lock(); - - template< typename Clock, typename Duration > - bool try_lock_until( std::chrono::time_point< Clock, Duration > const& timeout_time_) { - std::chrono::steady_clock::time_point timeout_time = detail::convert( timeout_time_); - return try_lock_until_( timeout_time); - } - - template< typename Rep, typename Period > - bool try_lock_for( std::chrono::duration< Rep, Period > const& timeout_duration) { - return try_lock_until_( std::chrono::steady_clock::now() + timeout_duration); - } - - void unlock(); -}; - -}} - -#ifdef _MSC_VER -# pragma warning(pop) -#endif - -#ifdef BOOST_HAS_ABI_HEADERS -# include BOOST_ABI_SUFFIX -#endif - -#endif // BOOST_FIBERS_TIMED_MUTEX_H diff --git a/src/recursive_mutex.cpp b/src/recursive_mutex.cpp deleted file mode 100644 index 93580661..00000000 --- a/src/recursive_mutex.cpp +++ /dev/null @@ -1,77 +0,0 @@ - -// 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 "boost/fiber/recursive_mutex.hpp" - -#include -#include - -#include "boost/fiber/exceptions.hpp" -#include "boost/fiber/scheduler.hpp" - -#ifdef BOOST_HAS_ABI_HEADERS -# include BOOST_ABI_PREFIX -#endif - -namespace boost { -namespace fibers { - -void -recursive_mutex::lock() { - while ( true) { - context * active_ctx = context::active(); - // store this fiber in order to be notified later - detail::spinlock_lock lk{ wait_queue_splk_ }; - if ( active_ctx == owner_) { - ++count_; - return; - } - if ( nullptr == owner_) { - owner_ = active_ctx; - count_ = 1; - return; - } - - wait_queue_.suspend_and_wait( lk, active_ctx); - } -} - -bool -recursive_mutex::try_lock() noexcept { - context * active_ctx = context::active(); - detail::spinlock_lock lk{ wait_queue_splk_ }; - if ( nullptr == owner_) { - owner_ = active_ctx; - count_ = 1; - } else if ( active_ctx == owner_) { - ++count_; - } - lk.unlock(); - // let other fiber release the lock - context::active()->yield(); - return active_ctx == owner_; -} - -void -recursive_mutex::unlock() { - context * active_ctx = context::active(); - detail::spinlock_lock lk( wait_queue_splk_); - if ( BOOST_UNLIKELY( active_ctx != owner_) ) { - throw lock_error( - std::make_error_code( std::errc::operation_not_permitted), - "boost fiber: no privilege to perform the operation"); - } - if ( 0 == --count_) { - owner_ = nullptr; - wait_queue_.notify_one(); - } -} - -}} - -#ifdef BOOST_HAS_ABI_HEADERS -# include BOOST_ABI_SUFFIX -#endif diff --git a/src/recursive_timed_mutex.cpp b/src/recursive_timed_mutex.cpp deleted file mode 100644 index 5958c721..00000000 --- a/src/recursive_timed_mutex.cpp +++ /dev/null @@ -1,100 +0,0 @@ - -// 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 "boost/fiber/recursive_timed_mutex.hpp" - -#include -#include - -#include "boost/fiber/exceptions.hpp" -#include "boost/fiber/scheduler.hpp" - -#ifdef BOOST_HAS_ABI_HEADERS -# include BOOST_ABI_PREFIX -#endif - -namespace boost { -namespace fibers { - -bool -recursive_timed_mutex::try_lock_until_( std::chrono::steady_clock::time_point const& timeout_time) noexcept { - while ( true) { - if ( std::chrono::steady_clock::now() > timeout_time) { - return false; - } - context * active_ctx = context::active(); - // store this fiber in order to be notified later - detail::spinlock_lock lk{ wait_queue_splk_ }; - if ( active_ctx == owner_) { - ++count_; - return true; - } - if ( nullptr == owner_) { - owner_ = active_ctx; - count_ = 1; - return true; - } - if ( ! wait_queue_.suspend_and_wait_until( lk, active_ctx, timeout_time)) { - return false; - } - } -} - -void -recursive_timed_mutex::lock() { - while ( true) { - context * active_ctx = context::active(); - // store this fiber in order to be notified later - detail::spinlock_lock lk{ wait_queue_splk_ }; - if ( active_ctx == owner_) { - ++count_; - return; - } - if ( nullptr == owner_) { - owner_ = active_ctx; - count_ = 1; - return; - } - wait_queue_.suspend_and_wait( lk, active_ctx); - } -} - -bool -recursive_timed_mutex::try_lock() noexcept { - context * active_ctx = context::active(); - detail::spinlock_lock lk{ wait_queue_splk_ }; - if ( nullptr == owner_) { - owner_ = active_ctx; - count_ = 1; - } else if ( active_ctx == owner_) { - ++count_; - } - lk.unlock(); - // let other fiber release the lock - active_ctx->yield(); - return active_ctx == owner_; -} - -void -recursive_timed_mutex::unlock() { - context * active_ctx = context::active(); - detail::spinlock_lock lk{ wait_queue_splk_ }; - if ( BOOST_UNLIKELY( active_ctx != owner_) ) { - throw lock_error{ - std::make_error_code( std::errc::operation_not_permitted), - "boost fiber: no privilege to perform the operation" }; - } - if ( 0 == --count_) { - owner_ = nullptr; - wait_queue_.notify_one(); - } -} - -}} - -#ifdef BOOST_HAS_ABI_HEADERS -# include BOOST_ABI_SUFFIX -#endif diff --git a/src/timed_mutex.cpp b/src/timed_mutex.cpp deleted file mode 100644 index d0482c5c..00000000 --- a/src/timed_mutex.cpp +++ /dev/null @@ -1,95 +0,0 @@ - -// 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 "boost/fiber/timed_mutex.hpp" - -#include -#include - -#include "boost/fiber/exceptions.hpp" -#include "boost/fiber/scheduler.hpp" - -#ifdef BOOST_HAS_ABI_HEADERS -# include BOOST_ABI_PREFIX -#endif - -namespace boost { -namespace fibers { - -bool -timed_mutex::try_lock_until_( std::chrono::steady_clock::time_point const& timeout_time) noexcept { - while ( true) { - if ( std::chrono::steady_clock::now() > timeout_time) { - return false; - } - context * active_ctx = context::active(); - detail::spinlock_lock lk{ wait_queue_splk_ }; - if ( nullptr == owner_) { - owner_ = active_ctx; - return true; - } - if ( ! wait_queue_.suspend_and_wait_until( lk, active_ctx, timeout_time)) { - return false; - } - } -} - -void -timed_mutex::lock() { - while ( true) { - context * active_ctx = context::active(); - // store this fiber in order to be notified later - detail::spinlock_lock lk{ wait_queue_splk_ }; - if ( BOOST_UNLIKELY( active_ctx == owner_) ) { - throw lock_error{ - std::make_error_code( std::errc::resource_deadlock_would_occur), - "boost fiber: a deadlock is detected" }; - } - if ( nullptr == owner_) { - owner_ = active_ctx; - return; - } - wait_queue_.suspend_and_wait( lk, active_ctx); - } -} - -bool -timed_mutex::try_lock() { - context * active_ctx = context::active(); - detail::spinlock_lock lk{ wait_queue_splk_ }; - if ( BOOST_UNLIKELY( active_ctx == owner_) ) { - throw lock_error{ - std::make_error_code( std::errc::resource_deadlock_would_occur), - "boost fiber: a deadlock is detected" }; - } - if ( nullptr == owner_) { - owner_ = active_ctx; - } - lk.unlock(); - // let other fiber release the lock - active_ctx->yield(); - return active_ctx == owner_; -} - -void -timed_mutex::unlock() { - context * active_ctx = context::active(); - detail::spinlock_lock lk{ wait_queue_splk_ }; - if ( BOOST_UNLIKELY( active_ctx != owner_) ) { - throw lock_error{ - std::make_error_code( std::errc::operation_not_permitted), - "boost fiber: no privilege to perform the operation" }; - } - owner_ = nullptr; - - wait_queue_.notify_one(); -} - -}} - -#ifdef BOOST_HAS_ABI_HEADERS -# include BOOST_ABI_SUFFIX -#endif diff --git a/test/test_mutex_dispatch.cpp b/test/test_mutex_dispatch.cpp index dec8ed4d..d0bb9112 100644 --- a/test/test_mutex_dispatch.cpp +++ b/test/test_mutex_dispatch.cpp @@ -4,7 +4,7 @@ // (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 +// This test is based on the tests of Boost.Thread #include #include @@ -41,139 +41,6 @@ void fn2( M & 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(); @@ -240,18 +107,6 @@ struct test_exclusive { } }; -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 >()(); @@ -279,169 +134,11 @@ 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/test/test_mutex_mt_dispatch.cpp b/test/test_mutex_mt_dispatch.cpp index 2087d17c..7673aefb 100644 --- a/test/test_mutex_mt_dispatch.cpp +++ b/test/test_mutex_mt_dispatch.cpp @@ -4,7 +4,7 @@ // (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 +// This test is based on the tests of Boost.Thread #include #include @@ -68,57 +68,6 @@ void test_mutex() { } } -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() { } @@ -128,9 +77,6 @@ boost::unit_test::test_suite * init_unit_test_suite( int, char* []) { #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 diff --git a/test/test_mutex_mt_post.cpp b/test/test_mutex_mt_post.cpp index 758acf9d..046ada50 100644 --- a/test/test_mutex_mt_post.cpp +++ b/test/test_mutex_mt_post.cpp @@ -4,7 +4,7 @@ // (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 +// This test is based on the tests of Boost.Thread #include #include @@ -68,57 +68,6 @@ void test_mutex() { } } -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() { } @@ -128,9 +77,6 @@ boost::unit_test::test_suite * init_unit_test_suite( int, char* []) { #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 diff --git a/test/test_mutex_post.cpp b/test/test_mutex_post.cpp index f88a571f..c33ee4e8 100644 --- a/test/test_mutex_post.cpp +++ b/test/test_mutex_post.cpp @@ -4,7 +4,7 @@ // (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 +// This test is based on the tests of Boost.Thread #include #include @@ -41,139 +41,6 @@ void fn2( M & 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(); @@ -240,18 +107,6 @@ struct test_exclusive { } }; -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 >()(); @@ -279,169 +134,11 @@ 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; } From 8c71e32e5b9914c8d1cec528aba1211857dce368 Mon Sep 17 00:00:00 2001 From: James Hunsaker <18537138+jhunsaker@users.noreply.github.com> Date: Tue, 7 Apr 2026 22:50:37 -0400 Subject: [PATCH 03/15] Remove work_stealing algorithm Unused by the top-level project. Removes source, header, examples, and performance benchmarks. Co-Authored-By: Claude Opus 4.6 --- CMakeLists.txt | 1 - examples/work_stealing.cpp | 126 ------------------- include/boost/fiber/algo/work_stealing.hpp | 88 ------------- include/boost/fiber/all.hpp | 1 - performance/fiber/skynet_stealing_async.cpp | 114 ----------------- performance/fiber/skynet_stealing_detach.cpp | 109 ---------------- performance/fiber/skynet_stealing_join.cpp | 113 ----------------- src/algo/work_stealing.cpp | 120 ------------------ 8 files changed, 672 deletions(-) delete mode 100644 examples/work_stealing.cpp delete mode 100644 include/boost/fiber/algo/work_stealing.hpp delete mode 100644 performance/fiber/skynet_stealing_async.cpp delete mode 100644 performance/fiber/skynet_stealing_detach.cpp delete mode 100644 performance/fiber/skynet_stealing_join.cpp delete mode 100644 src/algo/work_stealing.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index f016d4c5..35a953b3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -12,7 +12,6 @@ add_library(boost_fiber src/algo/algorithm.cpp src/algo/round_robin.cpp src/algo/shared_work.cpp - src/algo/work_stealing.cpp src/barrier.cpp src/condition_variable.cpp src/context.cpp diff --git a/examples/work_stealing.cpp b/examples/work_stealing.cpp deleted file mode 100644 index 42c99491..00000000 --- a/examples/work_stealing.cpp +++ /dev/null @@ -1,126 +0,0 @@ -// Copyright Nat Goodspeed + Oliver Kowalke 2015. -// 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include - -#include - -static std::size_t fiber_count{ 0 }; -static std::mutex mtx_count{}; -static boost::fibers::condition_variable_any cnd_count{}; -typedef std::unique_lock< std::mutex > lock_type; - -/***************************************************************************** -* example fiber function -*****************************************************************************/ -//[fiber_fn_ws -void whatevah( char me) { - try { - std::thread::id my_thread = std::this_thread::get_id(); /*< get ID of initial thread >*/ - { - std::ostringstream buffer; - buffer << "fiber " << me << " started on thread " << my_thread << '\n'; - std::cout << buffer.str() << std::flush; - } - for ( unsigned i = 0; i < 10; ++i) { /*< loop ten times >*/ - boost::this_fiber::yield(); /*< yield to other fibers >*/ - std::thread::id new_thread = std::this_thread::get_id(); /*< get ID of current thread >*/ - if ( new_thread != my_thread) { /*< test if fiber was migrated to another thread >*/ - my_thread = new_thread; - std::ostringstream buffer; - buffer << "fiber " << me << " switched to thread " << my_thread << '\n'; - std::cout << buffer.str() << std::flush; - } - } - } catch ( ... ) { - } - lock_type lk( mtx_count); - if ( 0 == --fiber_count) { /*< Decrement fiber counter for each completed fiber. >*/ - lk.unlock(); - cnd_count.notify_all(); /*< Notify all fibers waiting on `cnd_count`. >*/ - } -} -//] - -/***************************************************************************** -* example thread function -*****************************************************************************/ -//[thread_fn_ws -void thread() { - std::ostringstream buffer; - buffer << "thread started " << std::this_thread::get_id() << std::endl; - std::cout << buffer.str() << std::flush; - boost::fibers::use_scheduling_algorithm< boost::fibers::algo::work_stealing >( 4); /*< - Install the scheduling algorithm `boost::fibers::algo::work_stealing` in order to - join the work sharing. - >*/ - lock_type lk( mtx_count); - cnd_count.wait( lk, [](){ return 0 == fiber_count; } ); /*< - Suspend main fiber and resume worker fibers in the meanwhile. - Main fiber gets resumed (e.g returns from `condition_variable_any::wait()`) - if all worker fibers are complete. - >*/ - BOOST_ASSERT( 0 == fiber_count); -} -//] - -/***************************************************************************** -* main() -*****************************************************************************/ -int main( int argc, char *argv[]) { - std::cout << "main thread started " << std::this_thread::get_id() << std::endl; -//[main_ws - for ( char c : std::string("abcdefghijklmnopqrstuvwxyz")) { /*< - Launch a number of worker fibers; each worker fiber picks up a character - that is passed as parameter to fiber-function `whatevah`. - Each worker fiber gets detached. - >*/ - boost::fibers::fiber([c](){ whatevah( c); }).detach(); - ++fiber_count; /*< Increment fiber counter for each new fiber. >*/ - } - std::thread threads[] = { /*< - Launch a couple of threads that join the work sharing. - >*/ - std::thread( thread), - std::thread( thread), - std::thread( thread) - }; - boost::fibers::use_scheduling_algorithm< boost::fibers::algo::work_stealing >( 4); /*< - Install the scheduling algorithm `boost::fibers::algo::work_stealing` in the main thread - too, so each new fiber gets launched into the shared pool. - >*/ - { - lock_type/*< `lock_type` is typedef'ed as __unique_lock__< [@http://en.cppreference.com/w/cpp/thread/mutex `std::mutex`] > >*/ lk( mtx_count); - cnd_count.wait( lk, [](){ return 0 == fiber_count; } ); /*< - Suspend main fiber and resume worker fibers in the meanwhile. - Main fiber gets resumed (e.g returns from `condition_variable_any::wait()`) - if all worker fibers are complete. - >*/ - } /*< - Releasing lock of mtx_count is required before joining the threads, otherwise - the other threads would be blocked inside condition_variable::wait() and - would never return (deadlock). - >*/ - BOOST_ASSERT( 0 == fiber_count); - for ( std::thread & t : threads) { /*< wait for threads to terminate >*/ - t.join(); - } -//] - std::cout << "done." << std::endl; - return EXIT_SUCCESS; -} diff --git a/include/boost/fiber/algo/work_stealing.hpp b/include/boost/fiber/algo/work_stealing.hpp deleted file mode 100644 index b50469a5..00000000 --- a/include/boost/fiber/algo/work_stealing.hpp +++ /dev/null @@ -1,88 +0,0 @@ - -// Copyright Oliver Kowalke 2015. -// 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) -// - -#ifndef BOOST_FIBERS_ALGO_WORK_STEALING_H -#define BOOST_FIBERS_ALGO_WORK_STEALING_H - -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include -#include -#include -#include - -#ifdef BOOST_HAS_ABI_HEADERS -# include BOOST_ABI_PREFIX -#endif - -namespace boost { -namespace fibers { -namespace algo { - -class BOOST_FIBERS_DECL work_stealing : public algorithm { -private: - static std::atomic< std::uint32_t > counter_; - static std::vector< intrusive_ptr< work_stealing > > schedulers_; - - std::uint32_t id_; - std::uint32_t thread_count_; -#ifdef BOOST_FIBERS_USE_SPMC_QUEUE - detail::context_spmc_queue rqueue_{}; -#else - detail::context_spinlock_queue rqueue_{}; -#endif - std::mutex mtx_{}; - std::condition_variable cnd_{}; - bool flag_{ false }; - bool suspend_; - - static void init_( std::uint32_t, std::vector< intrusive_ptr< work_stealing > > &); - -public: - work_stealing( std::uint32_t, bool = false); - - work_stealing( work_stealing const&) = delete; - work_stealing( work_stealing &&) = delete; - - work_stealing & operator=( work_stealing const&) = delete; - work_stealing & operator=( work_stealing &&) = delete; - - void awakened( context *) noexcept override; - - context * pick_next() noexcept override; - - virtual context * steal() noexcept { - return rqueue_.steal(); - } - - bool has_ready_fibers() const noexcept override { - return ! rqueue_.empty(); - } - - void suspend_until( std::chrono::steady_clock::time_point const&) noexcept override; - - void notify() noexcept override; -}; - -}}} - -#ifdef BOOST_HAS_ABI_HEADERS -# include BOOST_ABI_SUFFIX -#endif - -#endif // BOOST_FIBERS_ALGO_WORK_STEALING_H diff --git a/include/boost/fiber/all.hpp b/include/boost/fiber/all.hpp index 0b607df8..1a18d2c4 100644 --- a/include/boost/fiber/all.hpp +++ b/include/boost/fiber/all.hpp @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include diff --git a/performance/fiber/skynet_stealing_async.cpp b/performance/fiber/skynet_stealing_async.cpp deleted file mode 100644 index 3701253b..00000000 --- a/performance/fiber/skynet_stealing_async.cpp +++ /dev/null @@ -1,114 +0,0 @@ - -// Copyright Oliver Kowalke 2015. -// 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) - -// based on https://github.com/atemerev/skynet from Alexander Temerev - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "barrier.hpp" - -using clock_type = std::chrono::steady_clock; -using duration_type = clock_type::duration; -using time_point_type = clock_type::time_point; -using channel_type = boost::fibers::buffered_channel< std::uint64_t >; -using allocator_type = boost::fibers::fixedsize_stack; -using lock_type = std::unique_lock< std::mutex >; - -static bool done = false; -static std::mutex mtx{}; -static boost::fibers::condition_variable_any cnd{}; - -// microbenchmark -std::uint64_t skynet(allocator_type& salloc, std::uint64_t num, std::uint64_t size, std::uint64_t div) { - if ( size != 1){ - size /= div; - - std::vector > results; - results.reserve( div); - - for ( std::uint64_t i = 0; i != div; ++i) { - std::uint64_t sub_num = num + i * size; - results.emplace_back(boost::fibers::async( - boost::fibers::launch::dispatch - , std::allocator_arg, salloc - , skynet - , std::ref( salloc), sub_num, size, div)); - } - - std::uint64_t sum = 0; - for ( auto& f : results) - sum += f.get(); - - return sum; - } - - return num; -} - -void thread( std::uint32_t thread_count) { - // thread registers itself at work-stealing scheduler - boost::fibers::use_scheduling_algorithm< boost::fibers::algo::work_stealing >( thread_count); - lock_type lk( mtx); - cnd.wait( lk, [](){ return done; }); - BOOST_ASSERT( done); -} - -int main() { - try { - // count of logical ids - std::uint32_t thread_count = std::thread::hardware_concurrency(); - std::size_t size{ 1000000 }; - std::size_t div{ 10 }; - allocator_type salloc{ 2*allocator_type::traits_type::page_size() }; - std::uint64_t result{ 0 }; - channel_type rc{ 2 }; - std::vector< std::thread > threads; - for ( std::uint32_t i = 1 /* count main-thread */; i < thread_count; ++i) { - // spawn thread - threads.emplace_back( thread, thread_count); - } - // main-thread registers itself at work-stealing scheduler - boost::fibers::use_scheduling_algorithm< boost::fibers::algo::work_stealing >( thread_count); - time_point_type start{ clock_type::now() }; - result = skynet( salloc, 0, size, div); - if ( 499999500000 != result) { - throw std::runtime_error("invalid result"); - } - auto duration = clock_type::now() - start; - lock_type lk( mtx); - done = true; - lk.unlock(); - cnd.notify_all(); - for ( std::thread & t : threads) { - t.join(); - } - std::cout << "duration: " << duration.count() / 1000000 << " ms" << std::endl; - return EXIT_SUCCESS; - } catch ( std::exception const& e) { - std::cerr << "exception: " << e.what() << std::endl; - } catch (...) { - std::cerr << "unhandled exception" << std::endl; - } - return EXIT_FAILURE; -} diff --git a/performance/fiber/skynet_stealing_detach.cpp b/performance/fiber/skynet_stealing_detach.cpp deleted file mode 100644 index fbc1b205..00000000 --- a/performance/fiber/skynet_stealing_detach.cpp +++ /dev/null @@ -1,109 +0,0 @@ - -// Copyright Oliver Kowalke 2015. -// 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) - -// based on https://github.com/atemerev/skynet from Alexander Temerev - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "barrier.hpp" - -using clock_type = std::chrono::steady_clock; -using duration_type = clock_type::duration; -using time_point_type = clock_type::time_point; -using channel_type = boost::fibers::buffered_channel< std::uint64_t >; -using allocator_type = boost::fibers::fixedsize_stack; -using lock_type = std::unique_lock< std::mutex >; - -static bool done = false; -static std::mutex mtx{}; -static boost::fibers::condition_variable_any cnd{}; - -// microbenchmark -void skynet( allocator_type & salloc, channel_type & c, std::size_t num, std::size_t size, std::size_t div) { - if ( 1 == size) { - c.push( num); - } else { - channel_type rc{ 16 }; - for ( std::size_t i = 0; i < div; ++i) { - auto sub_num = num + i * size / div; - boost::fibers::fiber{ boost::fibers::launch::dispatch, - std::allocator_arg, salloc, - skynet, - std::ref( salloc), std::ref( rc), sub_num, size / div, div }.detach(); - } - std::uint64_t sum{ 0 }; - for ( std::size_t i = 0; i < div; ++i) { - sum += rc.value_pop(); - } - c.push( sum); - } -} - -void thread( std::uint32_t thread_count) { - // thread registers itself at work-stealing scheduler - boost::fibers::use_scheduling_algorithm< boost::fibers::algo::work_stealing >( thread_count); - lock_type lk( mtx); - cnd.wait( lk, [](){ return done; }); - BOOST_ASSERT( done); -} - -int main() { - try { - // count of logical cpus - std::uint32_t thread_count = std::thread::hardware_concurrency(); - std::size_t size{ 1000000 }; - std::size_t div{ 10 }; - allocator_type salloc{ 2*allocator_type::traits_type::page_size() }; - std::uint64_t result{ 0 }; - channel_type rc{ 2 }; - std::vector< std::thread > threads; - for ( std::uint32_t i = 1 /* count main-thread */; i < thread_count; ++i) { - // spawn thread - threads.emplace_back( thread, thread_count); - } - // main-thread registers itself at work-stealing scheduler - boost::fibers::use_scheduling_algorithm< boost::fibers::algo::work_stealing >( thread_count); - time_point_type start{ clock_type::now() }; - skynet( salloc, rc, 0, size, div); - result = rc.value_pop(); - if ( 499999500000 != result) { - throw std::runtime_error("invalid result"); - } - auto duration = clock_type::now() - start; - lock_type lk( mtx); - done = true; - lk.unlock(); - cnd.notify_all(); - for ( std::thread & t : threads) { - t.join(); - } - std::cout << "duration: " << duration.count() / 1000000 << " ms" << std::endl; - return EXIT_SUCCESS; - } catch ( std::exception const& e) { - std::cerr << "exception: " << e.what() << std::endl; - } catch (...) { - std::cerr << "unhandled exception" << std::endl; - } - return EXIT_FAILURE; -} diff --git a/performance/fiber/skynet_stealing_join.cpp b/performance/fiber/skynet_stealing_join.cpp deleted file mode 100644 index 5acb1f7d..00000000 --- a/performance/fiber/skynet_stealing_join.cpp +++ /dev/null @@ -1,113 +0,0 @@ - -// Copyright Oliver Kowalke 2015. -// 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) - -// based on https://github.com/atemerev/skynet from Alexander Temerev - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "barrier.hpp" - -using clock_type = std::chrono::steady_clock; -using duration_type = clock_type::duration; -using time_point_type = clock_type::time_point; -using channel_type = boost::fibers::buffered_channel< std::uint64_t >; -using allocator_type = boost::fibers::fixedsize_stack; -using lock_type = std::unique_lock< std::mutex >; - -static bool done = false; -static std::mutex mtx{}; -static boost::fibers::condition_variable_any cnd{}; - -// microbenchmark -void skynet( allocator_type & salloc, channel_type & c, std::size_t num, std::size_t size, std::size_t div) { - if ( 1 == size) { - c.push( num); - } else { - channel_type rc{ 16 }; - std::vector< boost::fibers::fiber > fibers; - for ( std::size_t i = 0; i < div; ++i) { - auto sub_num = num + i * size / div; - fibers.emplace_back( boost::fibers::launch::dispatch, - std::allocator_arg, salloc, - skynet, - std::ref( salloc), std::ref( rc), sub_num, size / div, div); - } - std::uint64_t sum{ 0 }; - for ( std::size_t i = 0; i < div; ++i) { - sum += rc.value_pop(); - } - c.push( sum); - for ( auto & f : fibers) { - f.join(); - } - } -} - -void thread( std::uint32_t thread_count) { - // thread registers itself at work-stealing scheduler - boost::fibers::use_scheduling_algorithm< boost::fibers::algo::work_stealing >( thread_count); - lock_type lk( mtx); - cnd.wait( lk, [](){ return done; }); - BOOST_ASSERT( done); -} - -int main() { - try { - // count of logical cpus - std::uint32_t thread_count = std::thread::hardware_concurrency(); - std::size_t size{ 1000000 }; - std::size_t div{ 10 }; - allocator_type salloc{ 2*allocator_type::traits_type::page_size() }; - std::uint64_t result{ 0 }; - channel_type rc{ 2 }; - std::vector< std::thread > threads; - for ( std::uint32_t i = 1 /* count main-thread */; i < thread_count; ++i) { - // spawn thread - threads.emplace_back( thread, thread_count); - } - // main-thread registers itself at work-stealing scheduler - boost::fibers::use_scheduling_algorithm< boost::fibers::algo::work_stealing >( thread_count); - time_point_type start{ clock_type::now() }; - skynet( salloc, rc, 0, size, div); - result = rc.value_pop(); - if ( 499999500000 != result) { - throw std::runtime_error("invalid result"); - } - auto duration = clock_type::now() - start; - lock_type lk( mtx); - done = true; - lk.unlock(); - cnd.notify_all(); - for ( std::thread & t : threads) { - t.join(); - } - std::cout << "duration: " << duration.count() / 1000000 << " ms" << std::endl; - return EXIT_SUCCESS; - } catch ( std::exception const& e) { - std::cerr << "exception: " << e.what() << std::endl; - } catch (...) { - std::cerr << "unhandled exception" << std::endl; - } - return EXIT_FAILURE; -} diff --git a/src/algo/work_stealing.cpp b/src/algo/work_stealing.cpp deleted file mode 100644 index ae9ece8d..00000000 --- a/src/algo/work_stealing.cpp +++ /dev/null @@ -1,120 +0,0 @@ - -// Copyright Oliver Kowalke 2015. -// 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 "boost/fiber/algo/work_stealing.hpp" - -#include - -#include -#include - -#include "boost/fiber/detail/thread_barrier.hpp" -#include "boost/fiber/type.hpp" - -#ifdef BOOST_HAS_ABI_HEADERS -# include BOOST_ABI_PREFIX -#endif - -namespace boost { -namespace fibers { -namespace algo { - -std::atomic< std::uint32_t > work_stealing::counter_{ 0 }; -std::vector< intrusive_ptr< work_stealing > > work_stealing::schedulers_{}; - -void -work_stealing::init_( std::uint32_t thread_count, - std::vector< intrusive_ptr< work_stealing > > & schedulers) { - // resize array of schedulers to thread_count, initilized with nullptr - std::vector< intrusive_ptr< work_stealing > >{ thread_count, nullptr }.swap( schedulers); -} - -work_stealing::work_stealing( std::uint32_t thread_count, bool suspend) : - id_{ counter_++ }, - thread_count_{ thread_count }, - suspend_{ suspend } { - static boost::fibers::detail::thread_barrier b{ thread_count }; - // initialize the array of schedulers - static std::once_flag flag; - std::call_once( flag, & work_stealing::init_, thread_count_, std::ref( schedulers_) ); - // register pointer of this scheduler - schedulers_[id_] = this; - b.wait(); -} - -void -work_stealing::awakened( context * ctx) noexcept { - if ( ! ctx->is_context( type::pinned_context) ) { - ctx->detach(); - } - rqueue_.push( ctx); -} - -context * -work_stealing::pick_next() noexcept { - context * victim = rqueue_.pop(); - if ( nullptr != victim) { - boost::context::detail::prefetch_range( victim, sizeof( context) ); - if ( ! victim->is_context( type::pinned_context) ) { - context::active()->attach( victim); - } - } else { - std::uint32_t id = 0; - std::size_t count = 0, size = schedulers_.size(); - static thread_local std::minstd_rand generator{ std::random_device{}() }; - std::uniform_int_distribution< std::uint32_t > distribution{ - 0, static_cast< std::uint32_t >( thread_count_ - 1) }; - do { - do { - ++count; - // random selection of one logical cpu - // that belongs to the local NUMA node - id = distribution( generator); - // prevent stealing from own scheduler - } while ( id == id_); - // steal context from other scheduler - victim = schedulers_[id]->steal(); - } while ( nullptr == victim && count < size); - if ( nullptr != victim) { - boost::context::detail::prefetch_range( victim, sizeof( context) ); - BOOST_ASSERT( ! victim->is_context( type::pinned_context) ); - context::active()->attach( victim); - } - } - return victim; -} - -void -work_stealing::suspend_until( std::chrono::steady_clock::time_point const& time_point) noexcept { - if ( suspend_) { - if ( (std::chrono::steady_clock::time_point::max)() == time_point) { - std::unique_lock< std::mutex > lk{ mtx_ }; - cnd_.wait( lk, [this](){ return flag_; }); - flag_ = false; - } else { - std::unique_lock< std::mutex > lk{ mtx_ }; - cnd_.wait_until( lk, time_point, [this](){ return flag_; }); - flag_ = false; - } - } -} - -void -work_stealing::notify() noexcept { - if ( suspend_) { - std::unique_lock< std::mutex > lk{ mtx_ }; - flag_ = true; - lk.unlock(); - cnd_.notify_all(); - } -} - -}}} - -#ifdef BOOST_HAS_ABI_HEADERS -# include BOOST_ABI_SUFFIX -#endif From 5c37e0ef662cd3c66e0b15ffabf6fccd8ab783c9 Mon Sep 17 00:00:00 2001 From: James Hunsaker <18537138+jhunsaker@users.noreply.github.com> Date: Wed, 8 Apr 2026 00:05:38 -0400 Subject: [PATCH 04/15] Remove shared_work algorithm Unused by the top-level project. Removes source, header, examples, and performance benchmarks. Co-Authored-By: Claude Opus 4.6 --- CMakeLists.txt | 1 - examples/work_sharing.cpp | 130 --------------------- include/boost/fiber/algo/shared_work.hpp | 86 -------------- include/boost/fiber/all.hpp | 1 - performance/fiber/skynet_shared_detach.cpp | 109 ----------------- performance/fiber/skynet_shared_join.cpp | 113 ------------------ src/algo/shared_work.cpp | 101 ---------------- 7 files changed, 541 deletions(-) delete mode 100644 examples/work_sharing.cpp delete mode 100644 include/boost/fiber/algo/shared_work.hpp delete mode 100644 performance/fiber/skynet_shared_detach.cpp delete mode 100644 performance/fiber/skynet_shared_join.cpp delete mode 100644 src/algo/shared_work.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 35a953b3..152b0af1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,7 +11,6 @@ project(boost_fiber VERSION "${BOOST_SUPERPROJECT_VERSION}" LANGUAGES CXX) add_library(boost_fiber src/algo/algorithm.cpp src/algo/round_robin.cpp - src/algo/shared_work.cpp src/barrier.cpp src/condition_variable.cpp src/context.cpp diff --git a/examples/work_sharing.cpp b/examples/work_sharing.cpp deleted file mode 100644 index f5e31e51..00000000 --- a/examples/work_sharing.cpp +++ /dev/null @@ -1,130 +0,0 @@ -// Copyright Nat Goodspeed + Oliver Kowalke 2015. -// 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include - -#include - -static std::size_t fiber_count{ 0 }; -static std::mutex mtx_count{}; -static boost::fibers::condition_variable_any cnd_count{}; -typedef std::unique_lock< std::mutex > lock_type; - -/***************************************************************************** -* example fiber function -*****************************************************************************/ -//[fiber_fn_ws -void whatevah( char me) { - try { - std::thread::id my_thread = std::this_thread::get_id(); /*< get ID of initial thread >*/ - { - std::ostringstream buffer; - buffer << "fiber " << me << " started on thread " << my_thread << '\n'; - std::cout << buffer.str() << std::flush; - } - for ( unsigned i = 0; i < 10; ++i) { /*< loop ten times >*/ - boost::this_fiber::yield(); /*< yield to other fibers >*/ - std::thread::id new_thread = std::this_thread::get_id(); /*< get ID of current thread >*/ - if ( new_thread != my_thread) { /*< test if fiber was migrated to another thread >*/ - my_thread = new_thread; - std::ostringstream buffer; - buffer << "fiber " << me << " switched to thread " << my_thread << '\n'; - std::cout << buffer.str() << std::flush; - } - } - } catch ( ... ) { - } - lock_type lk( mtx_count); - if ( 0 == --fiber_count) { /*< Decrement fiber counter for each completed fiber. >*/ - lk.unlock(); - cnd_count.notify_all(); /*< Notify all fibers waiting on `cnd_count`. >*/ - } -} -//] - -/***************************************************************************** -* example thread function -*****************************************************************************/ -//[thread_fn_ws -void thread( boost::fibers::detail::thread_barrier * b) { - std::ostringstream buffer; - buffer << "thread started " << std::this_thread::get_id() << std::endl; - std::cout << buffer.str() << std::flush; - boost::fibers::use_scheduling_algorithm< boost::fibers::algo::shared_work >(); /*< - Install the scheduling algorithm `boost::fibers::algo::shared_work` in order to - join the work sharing. - >*/ - b->wait(); /*< sync with other threads: allow them to start processing >*/ - lock_type lk( mtx_count); - cnd_count.wait( lk, [](){ return 0 == fiber_count; } ); /*< - Suspend main fiber and resume worker fibers in the meanwhile. - Main fiber gets resumed (e.g returns from `condition_variable_any::wait()`) - if all worker fibers are complete. - >*/ - BOOST_ASSERT( 0 == fiber_count); -} -//] - -/***************************************************************************** -* main() -*****************************************************************************/ -int main( int argc, char *argv[]) { - std::cout << "main thread started " << std::this_thread::get_id() << std::endl; -//[main_ws - boost::fibers::use_scheduling_algorithm< boost::fibers::algo::shared_work >(); /*< - Install the scheduling algorithm `boost::fibers::algo::shared_work` in the main thread - too, so each new fiber gets launched into the shared pool. - >*/ - - for ( char c : std::string("abcdefghijklmnopqrstuvwxyz")) { /*< - Launch a number of worker fibers; each worker fiber picks up a character - that is passed as parameter to fiber-function `whatevah`. - Each worker fiber gets detached. - >*/ - boost::fibers::fiber([c](){ whatevah( c); }).detach(); - ++fiber_count; /*< Increment fiber counter for each new fiber. >*/ - } - boost::fibers::detail::thread_barrier b( 4); - std::thread threads[] = { /*< - Launch a couple of threads that join the work sharing. - >*/ - std::thread( thread, & b), - std::thread( thread, & b), - std::thread( thread, & b) - }; - b.wait(); /*< sync with other threads: allow them to start processing >*/ - { - lock_type/*< `lock_type` is typedef'ed as __unique_lock__< [@http://en.cppreference.com/w/cpp/thread/mutex `std::mutex`] > >*/ lk( mtx_count); - cnd_count.wait( lk, [](){ return 0 == fiber_count; } ); /*< - Suspend main fiber and resume worker fibers in the meanwhile. - Main fiber gets resumed (e.g returns from `condition_variable_any::wait()`) - if all worker fibers are complete. - >*/ - } /*< - Releasing lock of mtx_count is required before joining the threads, otherwise - the other threads would be blocked inside condition_variable::wait() and - would never return (deadlock). - >*/ - BOOST_ASSERT( 0 == fiber_count); - for ( std::thread & t : threads) { /*< wait for threads to terminate >*/ - t.join(); - } -//] - std::cout << "done." << std::endl; - return EXIT_SUCCESS; -} diff --git a/include/boost/fiber/algo/shared_work.hpp b/include/boost/fiber/algo/shared_work.hpp deleted file mode 100644 index cba7e871..00000000 --- a/include/boost/fiber/algo/shared_work.hpp +++ /dev/null @@ -1,86 +0,0 @@ - -// Copyright Nat Goodspeed + Oliver Kowalke 2015. -// 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) - -#ifndef BOOST_FIBERS_ALGO_SHARED_WORK_H -#define BOOST_FIBERS_ALGO_SHARED_WORK_H - -#include -#include -#include -#include - -#include - -#include -#include -#include -#include - -#ifdef BOOST_HAS_ABI_HEADERS -# include BOOST_ABI_PREFIX -#endif - -#ifdef _MSC_VER -# pragma warning(push) -# pragma warning(disable:4251) -#endif - -namespace boost { -namespace fibers { -namespace algo { - -class BOOST_FIBERS_DECL shared_work : public algorithm { -private: - typedef std::deque< context * > rqueue_type; - typedef scheduler::ready_queue_type lqueue_type; - - static rqueue_type rqueue_; - static std::mutex rqueue_mtx_; - - lqueue_type lqueue_{}; - std::mutex mtx_{}; - std::condition_variable cnd_{}; - bool flag_{ false }; - bool suspend_{ false }; - -public: - shared_work() = default; - - shared_work( bool suspend) : - suspend_{ suspend } { - } - - shared_work( shared_work const&) = delete; - shared_work( shared_work &&) = delete; - - shared_work & operator=( shared_work const&) = delete; - shared_work & operator=( shared_work &&) = delete; - - void awakened( context * ctx) noexcept override; - - context * pick_next() noexcept override; - - bool has_ready_fibers() const noexcept override { - std::unique_lock< std::mutex > lock{ rqueue_mtx_ }; - return ! rqueue_.empty() || ! lqueue_.empty(); - } - - void suspend_until( std::chrono::steady_clock::time_point const& time_point) noexcept override; - - void notify() noexcept override; -}; - -}}} - -#ifdef _MSC_VER -# pragma warning(pop) -#endif - -#ifdef BOOST_HAS_ABI_HEADERS -# include BOOST_ABI_SUFFIX -#endif - -#endif // BOOST_FIBERS_ALGO_SHARED_WORK_H diff --git a/include/boost/fiber/all.hpp b/include/boost/fiber/all.hpp index 1a18d2c4..2f12df2f 100644 --- a/include/boost/fiber/all.hpp +++ b/include/boost/fiber/all.hpp @@ -9,7 +9,6 @@ #include #include -#include #include #include #include diff --git a/performance/fiber/skynet_shared_detach.cpp b/performance/fiber/skynet_shared_detach.cpp deleted file mode 100644 index 12fd5653..00000000 --- a/performance/fiber/skynet_shared_detach.cpp +++ /dev/null @@ -1,109 +0,0 @@ - -// Copyright Oliver Kowalke 2015. -// 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) - -// based on https://github.com/atemerev/skynet from Alexander Temerev - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "barrier.hpp" - -using allocator_type = boost::fibers::fixedsize_stack; -using channel_type = boost::fibers::buffered_channel< std::uint64_t >; -using clock_type = std::chrono::steady_clock; -using duration_type = clock_type::duration; -using lock_type = std::unique_lock< std::mutex >; -using time_point_type = clock_type::time_point; - -static bool done = false; -static std::mutex mtx{}; -static boost::fibers::condition_variable_any cnd{}; - -// microbenchmark -void skynet( allocator_type & salloc, channel_type & c, std::size_t num, std::size_t size, std::size_t div) { - if ( 1 == size) { - c.push( num); - } else { - channel_type rc{ 16 }; - for ( std::size_t i = 0; i < div; ++i) { - auto sub_num = num + i * size / div; - boost::fibers::fiber{ boost::fibers::launch::dispatch, - std::allocator_arg, salloc, - skynet, - std::ref( salloc), std::ref( rc), sub_num, size / div, div }.detach(); - } - std::uint64_t sum{ 0 }; - for ( std::size_t i = 0; i < div; ++i) { - sum += rc.value_pop(); - } - c.push( sum); - } -} - -void thread( unsigned int idx, barrier * b) { - boost::fibers::numa::pin_thread( idx); - boost::fibers::use_scheduling_algorithm< boost::fibers::algo::shared_work >(); - b->wait(); - lock_type lk( mtx); - cnd.wait( lk, [](){ return done; }); - BOOST_ASSERT( done); -} - -int main() { - try { - boost::fibers::use_scheduling_algorithm< boost::fibers::algo::shared_work >(); - unsigned int n = std::thread::hardware_concurrency(); - barrier b( n); - boost::fibers::numa::pin_thread( n - 1); - std::size_t size{ 1000000 }; - std::size_t div{ 10 }; - std::vector< std::thread > threads; - for ( unsigned int i = 1; i < n; ++i) { - threads.emplace_back( thread, i - 1, & b); - }; - allocator_type salloc{ 2*allocator_type::traits_type::page_size() }; - std::uint64_t result{ 0 }; - channel_type rc{ 2 }; - b.wait(); - time_point_type start{ clock_type::now() }; - skynet( salloc, rc, 0, size, div); - result = rc.value_pop(); - if ( 499999500000 != result) { - throw std::runtime_error("invalid result"); - } - auto duration = clock_type::now() - start; - lock_type lk( mtx); - done = true; - lk.unlock(); - cnd.notify_all(); - for ( std::thread & t : threads) { - t.join(); - } - std::cout << "duration: " << duration.count() / 1000000 << " ms" << std::endl; - return EXIT_SUCCESS; - } catch ( std::exception const& e) { - std::cerr << "exception: " << e.what() << std::endl; - } catch (...) { - std::cerr << "unhandled exception" << std::endl; - } - return EXIT_FAILURE; -} diff --git a/performance/fiber/skynet_shared_join.cpp b/performance/fiber/skynet_shared_join.cpp deleted file mode 100644 index c26530f2..00000000 --- a/performance/fiber/skynet_shared_join.cpp +++ /dev/null @@ -1,113 +0,0 @@ - -// Copyright Oliver Kowalke 2015. -// 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) - -// based on https://github.com/atemerev/skynet from Alexander Temerev - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "barrier.hpp" - -using allocator_type = boost::fibers::fixedsize_stack; -using channel_type = boost::fibers::buffered_channel< std::uint64_t >; -using clock_type = std::chrono::steady_clock; -using duration_type = clock_type::duration; -using lock_type = std::unique_lock< std::mutex >; -using time_point_type = clock_type::time_point; - -static bool done = false; -static std::mutex mtx{}; -static boost::fibers::condition_variable_any cnd{}; - -// microbenchmark -void skynet( allocator_type & salloc, channel_type & c, std::size_t num, std::size_t size, std::size_t div) { - if ( 1 == size) { - c.push( num); - } else { - channel_type rc{ 16 }; - std::vector< boost::fibers::fiber > fibers; - for ( std::size_t i = 0; i < div; ++i) { - auto sub_num = num + i * size / div; - fibers.emplace_back( boost::fibers::launch::dispatch, - std::allocator_arg, salloc, - skynet, - std::ref( salloc), std::ref( rc), sub_num, size / div, div); - } - for ( auto & f: fibers) { - f.join(); - } - std::uint64_t sum{ 0 }; - for ( std::size_t i = 0; i < div; ++i) { - sum += rc.value_pop(); - } - c.push( sum); - } -} - -void thread( unsigned int idx, barrier * b) { - boost::fibers::numa::pin_thread( idx); - boost::fibers::use_scheduling_algorithm< boost::fibers::algo::shared_work >(); - b->wait(); - lock_type lk( mtx); - cnd.wait( lk, [](){ return done; }); - BOOST_ASSERT( done); -} - -int main() { - try { - boost::fibers::use_scheduling_algorithm< boost::fibers::algo::shared_work >(); - unsigned int n = std::thread::hardware_concurrency(); - barrier b( n); - boost::fibers::numa::pin_thread( n - 1); - std::size_t size{ 1000000 }; - std::size_t div{ 10 }; - std::vector< std::thread > threads; - for ( unsigned int i = 1; i < n; ++i) { - threads.emplace_back( thread, i - 1, & b); - }; - allocator_type salloc{ 2*allocator_type::traits_type::page_size() }; - std::uint64_t result{ 0 }; - channel_type rc{ 2 }; - b.wait(); - time_point_type start{ clock_type::now() }; - skynet( salloc, rc, 0, size, div); - result = rc.value_pop(); - if ( 499999500000 != result) { - throw std::runtime_error("invalid result"); - } - auto duration = clock_type::now() - start; - lock_type lk( mtx); - done = true; - lk.unlock(); - cnd.notify_all(); - for ( std::thread & t : threads) { - t.join(); - } - std::cout << "duration: " << duration.count() / 1000000 << " ms" << std::endl; - return EXIT_SUCCESS; - } catch ( std::exception const& e) { - std::cerr << "exception: " << e.what() << std::endl; - } catch (...) { - std::cerr << "unhandled exception" << std::endl; - } - return EXIT_FAILURE; -} diff --git a/src/algo/shared_work.cpp b/src/algo/shared_work.cpp deleted file mode 100644 index a055c1e9..00000000 --- a/src/algo/shared_work.cpp +++ /dev/null @@ -1,101 +0,0 @@ - -// 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 "boost/fiber/algo/shared_work.hpp" - -#include - -#include "boost/fiber/type.hpp" - -#ifdef BOOST_HAS_ABI_HEADERS -# include BOOST_ABI_PREFIX -#endif - -namespace boost { -namespace fibers { -namespace algo { - -//[awakened_ws -void -shared_work::awakened( context * ctx) noexcept { - if ( ctx->is_context( type::pinned_context) ) { /*< - recognize when we're passed this thread's main fiber (or an - implicit library helper fiber): never put those on the shared - queue - >*/ - lqueue_.push_back( * ctx); - } else { - ctx->detach(); - std::unique_lock< std::mutex > lk{ rqueue_mtx_ }; /*< - worker fiber, enqueue on shared queue - >*/ - rqueue_.push_back( ctx); - } -} -//] - -//[pick_next_ws -context * -shared_work::pick_next() noexcept { - context * ctx = nullptr; - std::unique_lock< std::mutex > lk{ rqueue_mtx_ }; - if ( ! rqueue_.empty() ) { /*< - pop an item from the ready queue - >*/ - ctx = rqueue_.front(); - rqueue_.pop_front(); - lk.unlock(); - BOOST_ASSERT( nullptr != ctx); - context::active()->attach( ctx); /*< - attach context to current scheduler via the active fiber - of this thread - >*/ - } else { - lk.unlock(); - if ( ! lqueue_.empty() ) { /*< - nothing in the ready queue, return main or dispatcher fiber - >*/ - ctx = & lqueue_.front(); - lqueue_.pop_front(); - } - } - return ctx; -} -//] - -void -shared_work::suspend_until( std::chrono::steady_clock::time_point const& time_point) noexcept { - if ( suspend_) { - if ( (std::chrono::steady_clock::time_point::max)() == time_point) { - std::unique_lock< std::mutex > lk{ mtx_ }; - cnd_.wait( lk, [this](){ return flag_; }); - flag_ = false; - } else { - std::unique_lock< std::mutex > lk{ mtx_ }; - cnd_.wait_until( lk, time_point, [this](){ return flag_; }); - flag_ = false; - } - } -} - -void -shared_work::notify() noexcept { - if ( suspend_) { - std::unique_lock< std::mutex > lk{ mtx_ }; - flag_ = true; - lk.unlock(); - cnd_.notify_all(); - } -} - -shared_work::rqueue_type shared_work::rqueue_{}; -std::mutex shared_work::rqueue_mtx_{}; - -}}} - -#ifdef BOOST_HAS_ABI_HEADERS -# include BOOST_ABI_SUFFIX -#endif From a58880a41144675c310425eb7cc59387721954aa Mon Sep 17 00:00:00 2001 From: James Hunsaker <18537138+jhunsaker@users.noreply.github.com> Date: Wed, 8 Apr 2026 00:09:40 -0400 Subject: [PATCH 05/15] Remove segmented_stack Unused by the top-level project. Removes header, example, and include references from fiber.hpp and all.hpp. Co-Authored-By: Claude Opus 4.6 --- examples/segmented_stack.cpp | 74 ------------------------- include/boost/fiber/all.hpp | 1 - include/boost/fiber/fiber.hpp | 1 - include/boost/fiber/segmented_stack.hpp | 35 ------------ 4 files changed, 111 deletions(-) delete mode 100644 examples/segmented_stack.cpp delete mode 100644 include/boost/fiber/segmented_stack.hpp diff --git a/examples/segmented_stack.cpp b/examples/segmented_stack.cpp deleted file mode 100644 index ce52ee10..00000000 --- a/examples/segmented_stack.cpp +++ /dev/null @@ -1,74 +0,0 @@ - -// 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 -#include - -#include -#include - -int count = 384; - -#ifdef BOOST_MSVC //MS VisualStudio -__declspec(noinline) void access( char *buf); -#else // GCC -void access( char *buf) __attribute__ ((noinline)); -#endif -void access( char *buf) -{ - buf[0] = '\0'; -} - -void bar( int i) -{ - char buf[4 * 1024]; - - if ( i > 0) - { - access( buf); - std::cout << i << ". iteration" << std::endl; - bar( i - 1); - } -} - -void foo() -{ - bar( count); - boost::this_fiber::yield(); -} - -void thread_fn() -{ - { - boost::fibers::fiber f( -#if defined(BOOST_USE_SEGMENTED_STACKS) - std::allocator_arg, - boost::fibers::segmented_stack( - boost::fibers::segmented_stack::traits_type::default_size() ), -#endif - foo); - f.join(); - } -} - -int main( int argc, char * argv[]) -{ -#if defined(BOOST_USE_SEGMENTED_STACKS) - std::cout << "using segmented_stack stacks: allocates " << count << " * 4kB == " << 4 * count << "kB on stack, "; - std::cout << "initial stack size = " << boost::fibers::segmented_stack::traits_type::default_size() / 1024 << "kB" << std::endl; - std::cout << "application should not fail" << std::endl; -#else - std::cout << "using standard stacks: allocates " << count << " * 4kB == " << 4 * count << "kB on stack, "; - std::cout << "initial stack size = " << boost::fibers::fixedsize_stack::traits_type::default_size() / 1024 << "kB" << std::endl; - std::cout << "application might fail" << std::endl; -#endif - - std::thread( thread_fn).join(); - - std::cout << "done." << std::endl; - - return 0; -} diff --git a/include/boost/fiber/all.hpp b/include/boost/fiber/all.hpp index 2f12df2f..ed0c9357 100644 --- a/include/boost/fiber/all.hpp +++ b/include/boost/fiber/all.hpp @@ -26,7 +26,6 @@ #include #include #include -#include #include #include diff --git a/include/boost/fiber/fiber.hpp b/include/boost/fiber/fiber.hpp index 709f634a..fd540625 100644 --- a/include/boost/fiber/fiber.hpp +++ b/include/boost/fiber/fiber.hpp @@ -23,7 +23,6 @@ #include #include #include -#include #ifdef BOOST_HAS_ABI_HEADERS # include BOOST_ABI_PREFIX diff --git a/include/boost/fiber/segmented_stack.hpp b/include/boost/fiber/segmented_stack.hpp deleted file mode 100644 index 868ddf4a..00000000 --- a/include/boost/fiber/segmented_stack.hpp +++ /dev/null @@ -1,35 +0,0 @@ - -// Copyright Oliver Kowalke 2014. -// 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) - -#ifndef BOOST_FIBERS_SEGMENTED_STACK_H -#define BOOST_FIBERS_SEGMENTED_STACK_H - -#include -#include - -#include - -#ifdef BOOST_HAS_ABI_HEADERS -# include BOOST_ABI_PREFIX -#endif - -namespace boost { -namespace fibers { - -#if defined(BOOST_USE_SEGMENTED_STACKS) -# if ! defined(BOOST_WINDOWS) -using segmented_stack = boost::context::segmented_stack; -using default_stack = boost::context::default_stack; -# endif -#endif - -}} - -#ifdef BOOST_HAS_ABI_HEADERS -# include BOOST_ABI_SUFFIX -#endif - -#endif // BOOST_FIBERS_SEGMENTED_STACK_H From baad8935c17e7a9ec9624b752d40ac4484f84191 Mon Sep 17 00:00:00 2001 From: James Hunsaker <18537138+jhunsaker@users.noreply.github.com> Date: Wed, 8 Apr 2026 00:17:20 -0400 Subject: [PATCH 06/15] Remove fiber barrier Unused by the top-level project. Removes source, header, dedicated test files, and dead do_wait() references in fiber tests. Co-Authored-By: Claude Opus 4.6 --- CMakeLists.txt | 1 - include/boost/fiber/all.hpp | 1 - include/boost/fiber/barrier.hpp | 48 ---------------------- src/barrier.cpp | 50 ----------------------- test/test_barrier_dispatch.cpp | 71 --------------------------------- test/test_barrier_post.cpp | 71 --------------------------------- test/test_fiber_dispatch.cpp | 4 -- test/test_fiber_post.cpp | 4 -- 8 files changed, 250 deletions(-) delete mode 100644 include/boost/fiber/barrier.hpp delete mode 100644 src/barrier.cpp delete mode 100644 test/test_barrier_dispatch.cpp delete mode 100644 test/test_barrier_post.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 152b0af1..8f3cd7f7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,7 +11,6 @@ project(boost_fiber VERSION "${BOOST_SUPERPROJECT_VERSION}" LANGUAGES CXX) add_library(boost_fiber src/algo/algorithm.cpp src/algo/round_robin.cpp - src/barrier.cpp src/condition_variable.cpp src/context.cpp src/fiber.cpp diff --git a/include/boost/fiber/all.hpp b/include/boost/fiber/all.hpp index ed0c9357..a56d5a94 100644 --- a/include/boost/fiber/all.hpp +++ b/include/boost/fiber/all.hpp @@ -9,7 +9,6 @@ #include #include -#include #include #include #include diff --git a/include/boost/fiber/barrier.hpp b/include/boost/fiber/barrier.hpp deleted file mode 100644 index 31a2cd61..00000000 --- a/include/boost/fiber/barrier.hpp +++ /dev/null @@ -1,48 +0,0 @@ - -// 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) - -#ifndef BOOST_FIBERS_BARRIER_H -#define BOOST_FIBERS_BARRIER_H - -#include - -#include - -#include -#include -#include - -#ifdef BOOST_HAS_ABI_HEADERS -# include BOOST_ABI_PREFIX -#endif - -namespace boost { -namespace fibers { - -class BOOST_FIBERS_DECL barrier { -private: - std::size_t initial_; - std::size_t current_; - std::size_t cycle_{ 0 }; - mutex mtx_{}; - condition_variable cond_{}; - -public: - explicit barrier( std::size_t); - - barrier( barrier const&) = delete; - barrier & operator=( barrier const&) = delete; - - bool wait(); -}; - -}} - -#ifdef BOOST_HAS_ABI_HEADERS -# include BOOST_ABI_SUFFIX -#endif - -#endif // BOOST_FIBERS_BARRIER_H diff --git a/src/barrier.cpp b/src/barrier.cpp deleted file mode 100644 index 92d59090..00000000 --- a/src/barrier.cpp +++ /dev/null @@ -1,50 +0,0 @@ - -// 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 "boost/fiber/barrier.hpp" - -#include -#include - -#include "boost/fiber/exceptions.hpp" - -#ifdef BOOST_HAS_ABI_HEADERS -# include BOOST_ABI_PREFIX -#endif - -namespace boost { -namespace fibers { - -barrier::barrier( std::size_t initial) : - initial_{ initial }, - current_{ initial_ } { - if ( BOOST_UNLIKELY( 0 == initial) ) { - throw fiber_error{ std::make_error_code( std::errc::invalid_argument), - "boost fiber: zero initial barrier count" }; - } -} - -bool -barrier::wait() { - std::unique_lock< mutex > lk{ mtx_ }; - const std::size_t cycle = cycle_; - if ( 0 == --current_) { - ++cycle_; - current_ = initial_; - lk.unlock(); // no pessimization - cond_.notify_all(); - return true; - } - - cond_.wait( lk, [&]{ return cycle != cycle_; }); - return false; -} - -}} - -#ifdef BOOST_HAS_ABI_HEADERS -# include BOOST_ABI_SUFFIX -#endif diff --git a/test/test_barrier_dispatch.cpp b/test/test_barrier_dispatch.cpp deleted file mode 100644 index 8f1716d5..00000000 --- a/test/test_barrier_dispatch.cpp +++ /dev/null @@ -1,71 +0,0 @@ - -// 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 -#include - -#include - -#include - -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/test/test_barrier_post.cpp b/test/test_barrier_post.cpp deleted file mode 100644 index 15354dde..00000000 --- a/test/test_barrier_post.cpp +++ /dev/null @@ -1,71 +0,0 @@ - -// 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 -#include - -#include - -#include - -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/test/test_fiber_dispatch.cpp b/test/test_fiber_dispatch.cpp index 1126b001..0a05378a 100644 --- a/test/test_fiber_dispatch.cpp +++ b/test/test_fiber_dispatch.cpp @@ -392,10 +392,6 @@ void test_sleep_until() { } } -void do_wait( boost::fibers::barrier* b) { - b->wait(); -} - void test_detach() { { boost::fibers::fiber f( boost::fibers::launch::dispatch, (detachable()) ); diff --git a/test/test_fiber_post.cpp b/test/test_fiber_post.cpp index 01a7e74c..67d9a6b2 100644 --- a/test/test_fiber_post.cpp +++ b/test/test_fiber_post.cpp @@ -392,10 +392,6 @@ void test_sleep_until() { } } -void do_wait( boost::fibers::barrier* b) { - b->wait(); -} - void test_detach() { { boost::fibers::fiber f( boost::fibers::launch::post, (detachable()) ); From fd59853571edc61bd0f686d47f87f9c8a665d32b Mon Sep 17 00:00:00 2001 From: James Hunsaker <18537138+jhunsaker@users.noreply.github.com> Date: Wed, 8 Apr 2026 00:18:57 -0400 Subject: [PATCH 07/15] Remove pooled_fixedsize_stack Unused by the top-level project. Co-Authored-By: Claude Opus 4.6 --- include/boost/fiber/all.hpp | 1 - .../boost/fiber/pooled_fixedsize_stack.hpp | 30 ------------------- 2 files changed, 31 deletions(-) delete mode 100644 include/boost/fiber/pooled_fixedsize_stack.hpp diff --git a/include/boost/fiber/all.hpp b/include/boost/fiber/all.hpp index a56d5a94..23ad404b 100644 --- a/include/boost/fiber/all.hpp +++ b/include/boost/fiber/all.hpp @@ -21,7 +21,6 @@ #include #include #include -#include #include #include #include diff --git a/include/boost/fiber/pooled_fixedsize_stack.hpp b/include/boost/fiber/pooled_fixedsize_stack.hpp deleted file mode 100644 index 24ea1447..00000000 --- a/include/boost/fiber/pooled_fixedsize_stack.hpp +++ /dev/null @@ -1,30 +0,0 @@ - -// Copyright Oliver Kowalke 2014. -// 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) - -#ifndef BOOST_FIBERS_POOLED_FIXEDSIZE_STACK_H -#define BOOST_FIBERS_POOLED_FIXEDSIZE_STACK_H - -#include -#include - -#include - -#ifdef BOOST_HAS_ABI_HEADERS -# include BOOST_ABI_PREFIX -#endif - -namespace boost { -namespace fibers { - -using pooled_fixedsize_stack = boost::context::pooled_fixedsize_stack; - -}} - -#ifdef BOOST_HAS_ABI_HEADERS -# include BOOST_ABI_SUFFIX -#endif - -#endif // BOOST_FIBERS_POOLED_FIXEDSIZE_STACK_H From b491046320ec75bfd73cb50ba33196ba96178a06 Mon Sep 17 00:00:00 2001 From: James Hunsaker <18537138+jhunsaker@users.noreply.github.com> Date: Wed, 8 Apr 2026 00:25:35 -0400 Subject: [PATCH 08/15] Remove fiber-specific storage (fss) Unused by the top-level project. Removes fss.hpp, detail/fss.hpp, test files, and cleans fss_data_ from context.hpp and context.cpp. Co-Authored-By: Claude Opus 4.6 --- include/boost/fiber/all.hpp | 1 - include/boost/fiber/context.hpp | 30 ---- include/boost/fiber/detail/fss.hpp | 59 ------- include/boost/fiber/fss.hpp | 107 ------------- include/boost/fiber/type.hpp | 1 - src/context.cpp | 37 ----- test/test_fss_dispatch.cpp | 237 ----------------------------- test/test_fss_post.cpp | 237 ----------------------------- 8 files changed, 709 deletions(-) delete mode 100644 include/boost/fiber/detail/fss.hpp delete mode 100644 include/boost/fiber/fss.hpp delete mode 100644 test/test_fss_dispatch.cpp delete mode 100644 test/test_fss_post.cpp diff --git a/include/boost/fiber/all.hpp b/include/boost/fiber/all.hpp index 23ad404b..6789e99e 100644 --- a/include/boost/fiber/all.hpp +++ b/include/boost/fiber/all.hpp @@ -16,7 +16,6 @@ #include #include #include -#include #include #include #include diff --git a/include/boost/fiber/context.hpp b/include/boost/fiber/context.hpp index b7e814b0..62d1cb1b 100644 --- a/include/boost/fiber/context.hpp +++ b/include/boost/fiber/context.hpp @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include @@ -36,7 +35,6 @@ #include #include #include -#include #include #include #include @@ -113,25 +111,6 @@ class BOOST_FIBERS_DECL context { template< typename Fn, typename ... Arg > friend class worker_context; friend class scheduler; - struct fss_data { - void * vp{ nullptr }; - detail::fss_cleanup_function::ptr_t cleanup_function{}; - - fss_data() = default; - - fss_data( void * vp_, - detail::fss_cleanup_function::ptr_t fn) noexcept : - vp( vp_), - cleanup_function(std::move( fn)) { - BOOST_ASSERT( cleanup_function); - } - - void do_cleanup() { - ( * cleanup_function)( vp); - } - }; - - typedef std::map< uintptr_t, fss_data > fss_data_t; #if ! defined(BOOST_FIBERS_NO_ATOMICS) std::atomic< std::size_t > use_count_; @@ -150,7 +129,6 @@ class BOOST_FIBERS_DECL context { #endif private: scheduler * scheduler_{ nullptr }; - fss_data_t fss_data_{}; detail::sleep_hook sleep_hook_{}; waker sleep_waker_{}; detail::ready_hook ready_hook_{}; @@ -290,14 +268,6 @@ class BOOST_FIBERS_DECL context { return type::none != ( type_ & t); } - void * get_fss_data( void const * vp) const; - - void set_fss_data( - void const * vp, - detail::fss_cleanup_function::ptr_t const& cleanup_fn, - void * data, - bool cleanup_existing); - void set_properties( fiber_properties * props) noexcept; fiber_properties * get_properties() const noexcept { diff --git a/include/boost/fiber/detail/fss.hpp b/include/boost/fiber/detail/fss.hpp deleted file mode 100644 index 9bb0e9a8..00000000 --- a/include/boost/fiber/detail/fss.hpp +++ /dev/null @@ -1,59 +0,0 @@ - -// 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) -// -// based on tss.hpp from boost.thread - -#ifndef BOOST_FIBERS_DETAIL_FSS_H -#define BOOST_FIBERS_DETAIL_FSS_H - -#include -#include - -#include -#include - -#ifdef BOOST_HAS_ABI_HEADERS -# include BOOST_ABI_PREFIX -#endif - -namespace boost { -namespace fibers { -namespace detail { - -class fss_cleanup_function { -private: - std::atomic< std::size_t > use_count_{ 0 }; - -public: - typedef intrusive_ptr< fss_cleanup_function > ptr_t; - - fss_cleanup_function() = default; - - virtual ~fss_cleanup_function() = default; - - virtual void operator()( void * data) = 0; - - friend inline - void intrusive_ptr_add_ref( fss_cleanup_function * p) noexcept { - p->use_count_.fetch_add( 1, std::memory_order_relaxed); - } - - friend inline - void intrusive_ptr_release( fss_cleanup_function * p) noexcept { - if ( 1 == p->use_count_.fetch_sub( 1, std::memory_order_release) ) { - std::atomic_thread_fence( std::memory_order_acquire); - delete p; - } - } -}; - -}}} - -#ifdef BOOST_HAS_ABI_HEADERS -# include BOOST_ABI_SUFFIX -#endif - -#endif // BOOST_FIBERS_DETAIL_FSS_H diff --git a/include/boost/fiber/fss.hpp b/include/boost/fiber/fss.hpp deleted file mode 100644 index 34ecb4d7..00000000 --- a/include/boost/fiber/fss.hpp +++ /dev/null @@ -1,107 +0,0 @@ - -// 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) -// -// based on tss.hpp from boost.thread - -#ifndef BOOST_FIBERS_FSS_H -#define BOOST_FIBERS_FSS_H - -#include - -#include -#include - -#ifdef BOOST_HAS_ABI_HEADERS -# include BOOST_ABI_PREFIX -#endif - -namespace boost { -namespace fibers { - -template< typename T > -class fiber_specific_ptr { -private: - struct default_cleanup_function : public detail::fss_cleanup_function { - void operator()( void * data) noexcept override { - delete static_cast< T * >( data); - } - }; - - struct custom_cleanup_function : public detail::fss_cleanup_function { - void (*fn)(T*); - - explicit custom_cleanup_function( void(*fn_)(T*) ) noexcept : - fn{ fn_ } { - } - - void operator()( void * data) override { - if ( BOOST_LIKELY( nullptr != fn) ) { - fn( static_cast< T * >( data) ); - } - } - }; - - detail::fss_cleanup_function::ptr_t cleanup_fn_; - -public: - using element_type = T; - - fiber_specific_ptr() : - cleanup_fn_{ new default_cleanup_function() } { - } - - explicit fiber_specific_ptr( void(*fn)(T*) ) : - cleanup_fn_{ new custom_cleanup_function( fn) } { - } - - ~fiber_specific_ptr() { - context * active_ctx = context::active(); - if ( nullptr != active_ctx) { - active_ctx->set_fss_data( - this, cleanup_fn_, nullptr, true); - } - } - - fiber_specific_ptr( fiber_specific_ptr const&) = delete; - fiber_specific_ptr & operator=( fiber_specific_ptr const&) = delete; - - T * get() const noexcept { - BOOST_ASSERT( context::active() ); - void * vp = context::active()->get_fss_data( this); - return static_cast< T * >( vp); - } - - T * operator->() const noexcept { - return get(); - } - - T & operator*() const noexcept { - return * get(); - } - - T * release() { - T * tmp = get(); - context::active()->set_fss_data( - this, cleanup_fn_, nullptr, false); - return tmp; - } - - void reset( T * t) { - T * c = get(); - if ( BOOST_LIKELY( c != t) ) { - context::active()->set_fss_data( - this, cleanup_fn_, t, true); - } - } -}; - -}} - -#ifdef BOOST_HAS_ABI_HEADERS -# include BOOST_ABI_SUFFIX -#endif - -#endif // BOOST_FIBERS_FSS_H diff --git a/include/boost/fiber/type.hpp b/include/boost/fiber/type.hpp index d9ab0a94..6764beac 100644 --- a/include/boost/fiber/type.hpp +++ b/include/boost/fiber/type.hpp @@ -27,7 +27,6 @@ #include #include #include -#include #include #include #include diff --git a/src/context.cpp b/src/context.cpp index e76bc4d2..4254eb6c 100644 --- a/src/context.cpp +++ b/src/context.cpp @@ -228,11 +228,6 @@ context::terminate() noexcept { // notify all waiting fibers wait_queue_.notify_all(); BOOST_ASSERT( wait_queue_.empty() ); - // release fiber-specific-data - for ( fss_data_t::value_type & data : fss_data_) { - data.second.do_cleanup(); - } - fss_data_.clear(); // switch to another context return get_scheduler()->terminate( lk, this); } @@ -297,38 +292,6 @@ context::schedule( context * ctx) noexcept { #endif } -void * -context::get_fss_data( void const * vp) const { - auto key = reinterpret_cast< uintptr_t >( vp); - auto i = fss_data_.find( key); - return fss_data_.end() != i ? i->second.vp : nullptr; -} - -void -context::set_fss_data( void const * vp, - detail::fss_cleanup_function::ptr_t const& cleanup_fn, - void * data, - bool cleanup_existing) { - BOOST_ASSERT( cleanup_fn); - auto key = reinterpret_cast< uintptr_t >( vp); - auto i = fss_data_.find( key); - if ( fss_data_.end() != i) { - if( cleanup_existing) { - i->second.do_cleanup(); - } - if ( nullptr != data) { - i->second = fss_data{ data, cleanup_fn }; - } else { - fss_data_.erase( i); - } - } else { - fss_data_.insert( - std::make_pair( - key, - fss_data{ data, cleanup_fn } ) ); - } -} - void context::set_properties( fiber_properties * props) noexcept { delete properties_; diff --git a/test/test_fss_dispatch.cpp b/test/test_fss_dispatch.cpp deleted file mode 100644 index 367c6aa1..00000000 --- a/test/test_fss_dispatch.cpp +++ /dev/null @@ -1,237 +0,0 @@ -// 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 -#include - -#include - -#include - -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 lock(fss_mutex); - ++fss_instances; - ++fss_total; - value = 0; - } - ~fss_value_t() { - std::unique_lock lock(fss_mutex); - --fss_instances; - } - int value; -}; - -boost::fibers::fiber_specific_ptr 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 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 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 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 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 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 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/test/test_fss_post.cpp b/test/test_fss_post.cpp deleted file mode 100644 index 166c4ea1..00000000 --- a/test/test_fss_post.cpp +++ /dev/null @@ -1,237 +0,0 @@ -// 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 -#include - -#include - -#include - -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 lock(fss_mutex); - ++fss_instances; - ++fss_total; - value = 0; - } - ~fss_value_t() { - std::unique_lock lock(fss_mutex); - --fss_instances; - } - int value; -}; - -boost::fibers::fiber_specific_ptr 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 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 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 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 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 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 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; -} From a8c17f4336b78132aa8aabec85d42c3fc43aa41c Mon Sep 17 00:00:00 2001 From: James Hunsaker <18537138+jhunsaker@users.noreply.github.com> Date: Wed, 8 Apr 2026 00:28:11 -0400 Subject: [PATCH 09/15] Remove unbuffered_channel Unused by the top-level project. Removes header, test files, and examples that solely used unbuffered_channel. Co-Authored-By: Claude Opus 4.6 --- examples/asio/exchange.cpp | 56 --- examples/range_for.cpp | 53 --- include/boost/fiber/all.hpp | 1 - include/boost/fiber/unbuffered_channel.hpp | 484 --------------------- test/test_unbuffered_channel_dispatch.cpp | 451 ------------------- test/test_unbuffered_channel_post.cpp | 476 -------------------- 6 files changed, 1521 deletions(-) delete mode 100644 examples/asio/exchange.cpp delete mode 100644 examples/range_for.cpp delete mode 100644 include/boost/fiber/unbuffered_channel.hpp delete mode 100644 test/test_unbuffered_channel_dispatch.cpp delete mode 100644 test/test_unbuffered_channel_post.cpp diff --git a/examples/asio/exchange.cpp b/examples/asio/exchange.cpp deleted file mode 100644 index e35b71e0..00000000 --- a/examples/asio/exchange.cpp +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright Arnaud Kapp, Oliver Kowalke 2016 -// 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 -#include -#include - -#include - -#include -#include "round_robin.hpp" - -std::shared_ptr< boost::fibers::unbuffered_channel< int > > c; - -void foo() { - auto io_ptr = std::make_shared< boost::asio::io_context >(); - boost::fibers::use_scheduling_algorithm< boost::fibers::asio::round_robin >( io_ptr); - boost::fibers::fiber([io_ptr](){ - for ( int i = 0; i < 10; ++i) { - std::cout << "push " << i << std::endl; - c->push( i); - } - c->close(); - io_ptr->stop(); - }).detach(); - io_ptr->run(); -} - -void bar() { - auto io_ptr = std::make_shared< boost::asio::io_context >(); - boost::fibers::use_scheduling_algorithm< boost::fibers::asio::round_robin >( io_ptr); - boost::fibers::fiber([io_ptr](){ - try { - for (;;) { - int i = c->value_pop(); - std::cout << "pop " << i << std::endl; - } - } catch ( std::exception const& e) { - std::cout << "exception: " << e.what() << std::endl; - } - io_ptr->stop(); - }).detach(); - io_ptr->run(); -} - -int main() { - c = std::make_shared< boost::fibers::unbuffered_channel< int > >(); - std::thread t1( foo); - std::thread t2( bar); - t2.join(); - t1.join(); - std::cout << "done." << std::endl; - return 0; -} diff --git a/examples/range_for.cpp b/examples/range_for.cpp deleted file mode 100644 index 8a1dbba1..00000000 --- a/examples/range_for.cpp +++ /dev/null @@ -1,53 +0,0 @@ - -// 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 -#include -#include -#include - -#include - -typedef boost::fibers::unbuffered_channel< unsigned int > channel_t; - -void foo( channel_t & chan) { - chan.push( 1); - chan.push( 1); - chan.push( 2); - chan.push( 3); - chan.push( 5); - chan.push( 8); - chan.push( 12); - chan.close(); -} - -void bar( channel_t & chan) { - for ( unsigned int value : chan) { - std::cout << value << " "; - } - std::cout << std::endl; -} - -int main() { - try { - channel_t chan; - - boost::fibers::fiber f1( & foo, std::ref( chan) ); - boost::fibers::fiber f2( & bar, std::ref( chan) ); - - f1.join(); - f2.join(); - - std::cout << "done." << std::endl; - - return EXIT_SUCCESS; - } catch ( std::exception const& e) { - std::cerr << "exception: " << e.what() << std::endl; - } catch (...) { - std::cerr << "unhandled exception" << std::endl; - } - return EXIT_FAILURE; -} diff --git a/include/boost/fiber/all.hpp b/include/boost/fiber/all.hpp index 6789e99e..24d64058 100644 --- a/include/boost/fiber/all.hpp +++ b/include/boost/fiber/all.hpp @@ -24,6 +24,5 @@ #include #include #include -#include #endif // BOOST_FIBERS_H diff --git a/include/boost/fiber/unbuffered_channel.hpp b/include/boost/fiber/unbuffered_channel.hpp deleted file mode 100644 index 4b8c807b..00000000 --- a/include/boost/fiber/unbuffered_channel.hpp +++ /dev/null @@ -1,484 +0,0 @@ - -// Copyright Oliver Kowalke 2016. -// 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) - -#ifndef BOOST_FIBERS_UNBUFFERED_CHANNEL_H -#define BOOST_FIBERS_UNBUFFERED_CHANNEL_H - -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include -#include -#if defined(BOOST_NO_CXX14_STD_EXCHANGE) -#include -#endif -#include -#include -#include - -#ifdef BOOST_HAS_ABI_HEADERS -# include BOOST_ABI_PREFIX -#endif - -namespace boost { -namespace fibers { - -template< typename T > -class unbuffered_channel { -public: - using value_type = typename std::remove_reference::type; - -private: - struct slot { - value_type value; - waker w; - - slot( value_type const& value_, waker && w) : - value{ value_ }, - w{ std::move(w) } { - } - - slot( value_type && value_, waker && w) : - value{ std::move( value_) }, - w{ std::move(w) } { - } - }; - - // shared cacheline - std::atomic< slot * > slot_{ nullptr }; - // shared cacheline - std::atomic_bool closed_{ false }; - mutable detail::spinlock splk_producers_{}; - wait_queue waiting_producers_{}; - mutable detail::spinlock splk_consumers_{}; - wait_queue waiting_consumers_{}; - char pad_[cacheline_length]; - - bool is_empty_() { - return nullptr == slot_.load( std::memory_order_acquire); - } - - bool try_push_( slot * own_slot) { - for (;;) { - slot * s = slot_.load( std::memory_order_acquire); - if ( nullptr == s) { - if ( ! slot_.compare_exchange_strong( s, own_slot, std::memory_order_acq_rel) ) { - continue; - } - return true; - } - return false; - } - } - - slot * try_pop_() { - slot * nil_slot = nullptr; - for (;;) { - slot * s = slot_.load( std::memory_order_acquire); - if ( nullptr != s) { - if ( ! slot_.compare_exchange_strong( s, nil_slot, std::memory_order_acq_rel) ) { - continue;} - } - return s; - } - } - -public: - unbuffered_channel() = default; - - ~unbuffered_channel() { - close(); - } - - unbuffered_channel( unbuffered_channel const&) = delete; - unbuffered_channel & operator=( unbuffered_channel const&) = delete; - - bool is_closed() const noexcept { - return closed_.load( std::memory_order_acquire); - } - - void close() noexcept { - // set flag - if ( ! closed_.exchange( true, std::memory_order_acquire) ) { - // notify current waiting - slot * s = slot_.load( std::memory_order_acquire); - if ( nullptr != s) { - // notify context - s->w.wake(); - } - detail::spinlock_lock lk1{ splk_producers_ }; - waiting_producers_.notify_all(); - - detail::spinlock_lock lk2{ splk_consumers_ }; - waiting_consumers_.notify_all(); - } - } - - channel_op_status push( value_type const& value) { - context * active_ctx = context::active(); - slot s{ value, {} }; - for (;;) { - if ( BOOST_UNLIKELY( is_closed() ) ) { - return channel_op_status::closed; - } - s.w = active_ctx->create_waker(); - if ( try_push_( & s) ) { - detail::spinlock_lock lk{ splk_consumers_ }; - waiting_consumers_.notify_one(); - // suspend till value has been consumed - active_ctx->suspend( lk); - // resumed - if ( BOOST_UNLIKELY( is_closed() ) ) { - // channel was closed before value was consumed - return channel_op_status::closed; - } - // value has been consumed - return channel_op_status::success; - } - detail::spinlock_lock lk{ splk_producers_ }; - if ( BOOST_UNLIKELY( is_closed() ) ) { - return channel_op_status::closed; - } - if ( is_empty_() ) { - continue; - } - - waiting_producers_.suspend_and_wait( lk, active_ctx); - // resumed, slot mabye free - } - } - - channel_op_status push( value_type && value) { - context * active_ctx = context::active(); - slot s{ std::move( value), {} }; - for (;;) { - if ( BOOST_UNLIKELY( is_closed() ) ) { - return channel_op_status::closed; - } - s.w = active_ctx->create_waker(); - if ( try_push_( & s) ) { - detail::spinlock_lock lk{ splk_consumers_ }; - waiting_consumers_.notify_one(); - // suspend till value has been consumed - active_ctx->suspend( lk); - // resumed - if ( BOOST_UNLIKELY( is_closed() ) ) { - // channel was closed before value was consumed - return channel_op_status::closed; - } - // value has been consumed - return channel_op_status::success; - } - detail::spinlock_lock lk{ splk_producers_ }; - if ( BOOST_UNLIKELY( is_closed() ) ) { - return channel_op_status::closed; - } - if ( is_empty_() ) { - continue; - } - waiting_producers_.suspend_and_wait( lk, active_ctx); - // resumed, slot mabye free - } - } - - template< typename Rep, typename Period > - channel_op_status push_wait_for( value_type const& value, - std::chrono::duration< Rep, Period > const& timeout_duration) { - return push_wait_until( value, - std::chrono::steady_clock::now() + timeout_duration); - } - - template< typename Rep, typename Period > - channel_op_status push_wait_for( value_type && value, - std::chrono::duration< Rep, Period > const& timeout_duration) { - return push_wait_until( std::forward< value_type >( value), - std::chrono::steady_clock::now() + timeout_duration); - } - - template< typename Clock, typename Duration > - channel_op_status push_wait_until( value_type const& value, - std::chrono::time_point< Clock, Duration > const& timeout_time_) { - context * active_ctx = context::active(); - slot s{ value, {} }; - std::chrono::steady_clock::time_point timeout_time = detail::convert( timeout_time_); - for (;;) { - if ( BOOST_UNLIKELY( is_closed() ) ) { - return channel_op_status::closed; - } - s.w = active_ctx->create_waker(); - if ( try_push_( & s) ) { - detail::spinlock_lock lk{ splk_consumers_ }; - waiting_consumers_.notify_one(); - // suspend this producer - if ( ! active_ctx->wait_until(timeout_time, lk, waker(s.w))) { - // clear slot - slot * nil_slot = nullptr, * own_slot = & s; - slot_.compare_exchange_strong( own_slot, nil_slot, std::memory_order_acq_rel); - // resumed, value has not been consumed - return channel_op_status::timeout; - } - // resumed - if ( BOOST_UNLIKELY( is_closed() ) ) { - // channel was closed before value was consumed - return channel_op_status::closed; - } - // value has been consumed - return channel_op_status::success; - } - detail::spinlock_lock lk{ splk_producers_ }; - if ( BOOST_UNLIKELY( is_closed() ) ) { - return channel_op_status::closed; - } - if ( is_empty_() ) { - continue; - } - - if (! waiting_producers_.suspend_and_wait_until( lk, active_ctx, timeout_time)) - { - return channel_op_status::timeout; - } - // resumed, slot maybe free - } - } - - template< typename Clock, typename Duration > - channel_op_status push_wait_until( value_type && value, - std::chrono::time_point< Clock, Duration > const& timeout_time_) { - context * active_ctx = context::active(); - slot s{ std::move( value), {} }; - std::chrono::steady_clock::time_point timeout_time = detail::convert( timeout_time_); - for (;;) { - if ( BOOST_UNLIKELY( is_closed() ) ) { - return channel_op_status::closed; - } - s.w = active_ctx->create_waker(); - if ( try_push_( & s) ) { - detail::spinlock_lock lk{ splk_consumers_ }; - waiting_consumers_.notify_one(); - // suspend this producer - if ( ! active_ctx->wait_until(timeout_time, lk, waker(s.w))) { - // clear slot - slot * nil_slot = nullptr, * own_slot = & s; - slot_.compare_exchange_strong( own_slot, nil_slot, std::memory_order_acq_rel); - // resumed, value has not been consumed - return channel_op_status::timeout; - } - // resumed - if ( BOOST_UNLIKELY( is_closed() ) ) { - // channel was closed before value was consumed - return channel_op_status::closed; - } - // value has been consumed - return channel_op_status::success; - } - detail::spinlock_lock lk{ splk_producers_ }; - if ( BOOST_UNLIKELY( is_closed() ) ) { - return channel_op_status::closed; - } - if ( is_empty_() ) { - continue; - } - if (! waiting_producers_.suspend_and_wait_until( lk, active_ctx, timeout_time)) - { - return channel_op_status::timeout; - } - // resumed, slot maybe free - } - } - - channel_op_status pop( value_type & value) { - context * active_ctx = context::active(); - slot * s = nullptr; - for (;;) { - if ( nullptr != ( s = try_pop_() ) ) { - { - detail::spinlock_lock lk{ splk_producers_ }; - waiting_producers_.notify_one(); - } - value = std::move( s->value); - // notify context - s->w.wake(); - return channel_op_status::success; - } - detail::spinlock_lock lk{ splk_consumers_ }; - if ( BOOST_UNLIKELY( is_closed() ) ) { - return channel_op_status::closed; - } - if ( ! is_empty_() ) { - continue; - } - waiting_consumers_.suspend_and_wait( lk, active_ctx); - // resumed, slot mabye set - } - } - - value_type value_pop() { - context * active_ctx = context::active(); - slot * s = nullptr; - for (;;) { - if ( nullptr != ( s = try_pop_() ) ) { - { - detail::spinlock_lock lk{ splk_producers_ }; - waiting_producers_.notify_one(); - } - // consume value - value_type value = std::move( s->value); - // notify context - s->w.wake(); - return std::move( value); - } - detail::spinlock_lock lk{ splk_consumers_ }; - if ( BOOST_UNLIKELY( is_closed() ) ) { - throw fiber_error{ - std::make_error_code( std::errc::operation_not_permitted), - "boost fiber: channel is closed" }; - } - if ( ! is_empty_() ) { - continue; - } - waiting_consumers_.suspend_and_wait( lk, active_ctx); - // resumed, slot mabye set - } - } - - template< typename Rep, typename Period > - channel_op_status pop_wait_for( value_type & value, - std::chrono::duration< Rep, Period > const& timeout_duration) { - return pop_wait_until( value, - std::chrono::steady_clock::now() + timeout_duration); - } - - template< typename Clock, typename Duration > - channel_op_status pop_wait_until( value_type & value, - std::chrono::time_point< Clock, Duration > const& timeout_time_) { - context * active_ctx = context::active(); - slot * s = nullptr; - std::chrono::steady_clock::time_point timeout_time = detail::convert( timeout_time_); - for (;;) { - if ( nullptr != ( s = try_pop_() ) ) { - { - detail::spinlock_lock lk{ splk_producers_ }; - waiting_producers_.notify_one(); - } - // consume value - value = std::move( s->value); - // notify context - s->w.wake(); - return channel_op_status::success; - } - detail::spinlock_lock lk{ splk_consumers_ }; - if ( BOOST_UNLIKELY( is_closed() ) ) { - return channel_op_status::closed; - } - if ( ! is_empty_() ) { - continue; - } - if ( ! waiting_consumers_.suspend_and_wait_until( lk, active_ctx, timeout_time)) { - return channel_op_status::timeout; - } - } - } - - class iterator { - private: - typedef typename std::aligned_storage< sizeof( value_type), alignof( value_type) >::type storage_type; - - unbuffered_channel * chan_{ nullptr }; - storage_type storage_; - - void increment_( bool initial = false) { - BOOST_ASSERT( nullptr != chan_); - try { - if ( ! initial) { - reinterpret_cast< value_type * >( std::addressof( storage_) )->~value_type(); - } - ::new ( static_cast< void * >( std::addressof( storage_) ) ) value_type{ chan_->value_pop() }; - } catch ( fiber_error const&) { - chan_ = nullptr; - } - } - - public: - using iterator_category = std::input_iterator_tag; - using difference_type = std::ptrdiff_t; - using pointer = value_type *; - using reference = value_type &; - - using pointer_t = pointer; - using reference_t = reference; - - iterator() = default; - - explicit iterator( unbuffered_channel< T > * chan) noexcept : - chan_{ chan } { - increment_( true); - } - - iterator( iterator const& other) noexcept : - chan_{ other.chan_ } { - } - - iterator & operator=( iterator const& other) noexcept { - if ( this == & other) return * this; - chan_ = other.chan_; - return * this; - } - - bool operator==( iterator const& other) const noexcept { - return other.chan_ == chan_; - } - - bool operator!=( iterator const& other) const noexcept { - return other.chan_ != chan_; - } - - iterator & operator++() { - reinterpret_cast< value_type * >( std::addressof( storage_) )->~value_type(); - increment_(); - return * this; - } - - const iterator operator++( int) = delete; - - reference_t operator*() noexcept { - return * reinterpret_cast< value_type * >( std::addressof( storage_) ); - } - - pointer_t operator->() noexcept { - return reinterpret_cast< value_type * >( std::addressof( storage_) ); - } - }; - - friend class iterator; -}; - -template< typename T > -typename unbuffered_channel< T >::iterator -begin( unbuffered_channel< T > & chan) { - return typename unbuffered_channel< T >::iterator( & chan); -} - -template< typename T > -typename unbuffered_channel< T >::iterator -end( unbuffered_channel< T > &) { - return typename unbuffered_channel< T >::iterator(); -} - -}} - -#ifdef BOOST_HAS_ABI_HEADERS -# include BOOST_ABI_SUFFIX -#endif - -#endif // BOOST_FIBERS_UNBUFFERED_CHANNEL_H diff --git a/test/test_unbuffered_channel_dispatch.cpp b/test/test_unbuffered_channel_dispatch.cpp deleted file mode 100644 index 22650576..00000000 --- a/test/test_unbuffered_channel_dispatch.cpp +++ /dev/null @@ -1,451 +0,0 @@ - -// 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 -#include -#include -#include - -#include -#include - -#include - -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/test/test_unbuffered_channel_post.cpp b/test/test_unbuffered_channel_post.cpp deleted file mode 100644 index 20931c17..00000000 --- a/test/test_unbuffered_channel_post.cpp +++ /dev/null @@ -1,476 +0,0 @@ - -// 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 -#include -#include -#include - -#include -#include - -#include - -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(); -} - -void test_issue_268() { - boost::fibers::unbuffered_channel< int > chan; - std::vector< int > vec; - boost::fibers::fiber con( boost::fibers::launch::dispatch, [&]() { - int v; - while (chan.pop( v) == boost::fibers::channel_op_status::success) { - boost::this_fiber::yield(); - vec.push_back( v); - } - }); - - boost::fibers::fiber p1( boost::fibers::launch::post, [&]() { - chan.push( 12); - }); - chan.push( 22); - boost::this_fiber::sleep_for( std::chrono::milliseconds( 100) ); - BOOST_CHECK_EQUAL( 2u, vec.size()); - p1.join(); - chan.close(); - con.join(); - BOOST_CHECK_EQUAL( 22, vec[0]); - BOOST_CHECK_EQUAL( 12, vec[1]); -} - -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) ); - test->add( BOOST_TEST_CASE( & test_issue_268) ); - - return test; -} From 36e5d04f53023ba844d6e6206fa3c373ca2d2a47 Mon Sep 17 00:00:00 2001 From: James Hunsaker <18537138+jhunsaker@users.noreply.github.com> Date: Wed, 8 Apr 2026 00:46:04 -0400 Subject: [PATCH 10/15] Remove performance benchmarks Unused by the top-level project. Co-Authored-By: Claude Opus 4.6 --- performance/clock.hpp | 44 ----- performance/fiber/Jamfile.v2 | 50 ------ performance/fiber/barrier.hpp | 50 ------ performance/fiber/skynet_detach.cpp | 80 --------- performance/fiber/skynet_join.cpp | 84 --------- performance/thread/Jamfile.v2 | 34 ---- performance/thread/buffered_channel.hpp | 228 ------------------------ performance/thread/skynet_async.cpp | 76 -------- performance/thread/skynet_pthread.cpp | 90 ---------- performance/thread/skynet_std.cpp | 58 ------ 10 files changed, 794 deletions(-) delete mode 100644 performance/clock.hpp delete mode 100644 performance/fiber/Jamfile.v2 delete mode 100644 performance/fiber/barrier.hpp delete mode 100644 performance/fiber/skynet_detach.cpp delete mode 100644 performance/fiber/skynet_join.cpp delete mode 100644 performance/thread/Jamfile.v2 delete mode 100644 performance/thread/buffered_channel.hpp delete mode 100644 performance/thread/skynet_async.cpp delete mode 100644 performance/thread/skynet_pthread.cpp delete mode 100644 performance/thread/skynet_std.cpp diff --git a/performance/clock.hpp b/performance/clock.hpp deleted file mode 100644 index 00a1bb18..00000000 --- a/performance/clock.hpp +++ /dev/null @@ -1,44 +0,0 @@ - -// Copyright Oliver Kowalke 2009. -// 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) -// -#ifndef CLOCK_H -#define CLOCK_H - -#include -#include -#include -#include -#include -#include - -#include - -typedef std::chrono::steady_clock clock_type; -typedef clock_type::duration duration_type; -typedef clock_type::time_point time_point_type; - -struct clock_overhead -{ - std::uint64_t operator()() - { - time_point_type start( clock_type::now() ); - return ( clock_type::now() - start).count(); - } -}; - -duration_type overhead_clock() -{ - std::size_t iterations( 10); - std::vector< std::uint64_t > overhead( iterations, 0); - for ( std::size_t i = 0; i < iterations; ++i) - std::generate( - overhead.begin(), overhead.end(), - clock_overhead() ); - BOOST_ASSERT( overhead.begin() != overhead.end() ); - return duration_type( std::accumulate( overhead.begin(), overhead.end(), 0) / iterations); -} - -#endif // CLOCK_H diff --git a/performance/fiber/Jamfile.v2 b/performance/fiber/Jamfile.v2 deleted file mode 100644 index e856524d..00000000 --- a/performance/fiber/Jamfile.v2 +++ /dev/null @@ -1,50 +0,0 @@ - -# Copyright Oliver Kowalke 2009. -# 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) - -# For more information, see http://www.boost.org/ - -import common ; -import feature ; -import indirect ; -import modules ; -import os ; -import toolset ; - -project boost/fiber/performance/fiber - : requirements - /boost/fiber//boost_fiber - solaris:"-llgrp" - windows:_WIN32_WINNT=0x0601 - linux,gcc,on:-fsplit-stack - linux,gcc,on:-DBOOST_USE_SEGMENTED_STACKS - clang,on:-fsplit-stack - clang,on:-DBOOST_USE_SEGMENTED_STACKS - static - multi - speed - release - ; - -exe skynet_join : - skynet_join.cpp ; - -exe skynet_detach : - skynet_detach.cpp ; - -exe skynet_shared_join : - skynet_shared_join.cpp ; - -exe skynet_shared_detach : - skynet_shared_detach.cpp ; - -exe skynet_stealing_join : - skynet_stealing_join.cpp ; - -exe skynet_stealing_detach : - skynet_stealing_detach.cpp ; - -exe skynet_stealing_async : - skynet_stealing_async.cpp ; diff --git a/performance/fiber/barrier.hpp b/performance/fiber/barrier.hpp deleted file mode 100644 index dcbd7e98..00000000 --- a/performance/fiber/barrier.hpp +++ /dev/null @@ -1,50 +0,0 @@ - -// 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) - -#ifndef BARRIER_H -#define BARRIER_H - -#include -#include -#include - -#include - -class barrier { -private: - std::size_t initial_; - std::size_t current_; - bool cycle_{ true }; - std::mutex mtx_{}; - std::condition_variable cond_{}; - -public: - explicit barrier( std::size_t initial) : - initial_{ initial }, - current_{ initial_ } { - BOOST_ASSERT ( 0 != initial); - } - - barrier( barrier const&) = delete; - barrier & operator=( barrier const&) = delete; - - bool wait() { - std::unique_lock< std::mutex > lk( mtx_); - const bool cycle = cycle_; - if ( 0 == --current_) { - cycle_ = ! cycle_; - current_ = initial_; - lk.unlock(); // no pessimization - cond_.notify_all(); - return true; - } else { - cond_.wait( lk, [&](){ return cycle != cycle_; }); - } - return false; - } -}; - -#endif // BARRIER_H diff --git a/performance/fiber/skynet_detach.cpp b/performance/fiber/skynet_detach.cpp deleted file mode 100644 index 5e6d4052..00000000 --- a/performance/fiber/skynet_detach.cpp +++ /dev/null @@ -1,80 +0,0 @@ - -// Copyright Oliver Kowalke 2015. -// 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) - -// based on https://github.com/atemerev/skynet from Alexander Temerev - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -using allocator_type = boost::fibers::fixedsize_stack; -using channel_type = boost::fibers::buffered_channel< std::uint64_t >; -using clock_type = std::chrono::steady_clock; -using duration_type = clock_type::duration; -using time_point_type = clock_type::time_point; - -// microbenchmark -void skynet( allocator_type & salloc, channel_type & c, std::size_t num, std::size_t size, std::size_t div) { - if ( 1 == size) { - c.push( num); - } else { - channel_type rc{ 16 }; - for ( std::size_t i = 0; i < div; ++i) { - auto sub_num = num + i * size / div; - boost::fibers::fiber{ boost::fibers::launch::dispatch, - std::allocator_arg, salloc, - skynet, - std::ref( salloc), std::ref( rc), sub_num, size / div, div }.detach(); - } - std::uint64_t sum{ 0 }; - for ( std::size_t i = 0; i < div; ++i) { - sum += rc.value_pop(); - } - c.push( sum); - } -} - -int main() { - try { - std::size_t size{ 1000000 }; - std::size_t div{ 10 }; - // Windows 10 and FreeBSD require a fiber stack of 8kb - // otherwise the stack gets exhausted - // stack requirements must be checked for other OS too -#if BOOST_OS_WINDOWS || BOOST_OS_BSD - allocator_type salloc{ 2*allocator_type::traits_type::page_size() }; -#else - allocator_type salloc{ allocator_type::traits_type::page_size() }; -#endif - std::uint64_t result{ 0 }; - channel_type rc{ 2 }; - time_point_type start{ clock_type::now() }; - skynet( salloc, rc, 0, size, div); - result = rc.value_pop(); - if ( 499999500000 != result) { - throw std::runtime_error("invalid result"); - } - auto duration = clock_type::now() - start; - std::cout << "duration: " << duration.count() / 1000000 << " ms" << std::endl; - return EXIT_SUCCESS; - } catch ( std::exception const& e) { - std::cerr << "exception: " << e.what() << std::endl; - } catch (...) { - std::cerr << "unhandled exception" << std::endl; - } - return EXIT_FAILURE; -} diff --git a/performance/fiber/skynet_join.cpp b/performance/fiber/skynet_join.cpp deleted file mode 100644 index 543ee03f..00000000 --- a/performance/fiber/skynet_join.cpp +++ /dev/null @@ -1,84 +0,0 @@ - -// Copyright Oliver Kowalke 2015. -// 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) - -// based on https://github.com/atemerev/skynet from Alexander Temerev - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -using allocator_type = boost::fibers::fixedsize_stack; -using channel_type = boost::fibers::buffered_channel< std::uint64_t >; -using clock_type = std::chrono::steady_clock; -using duration_type = clock_type::duration; -using time_point_type = clock_type::time_point; - -// microbenchmark -void skynet( allocator_type & salloc, channel_type & c, std::size_t num, std::size_t size, std::size_t div) { - if ( 1 == size) { - c.push( num); - } else { - channel_type rc{ 16 }; - std::vector< boost::fibers::fiber > fibers; - for ( std::size_t i = 0; i < div; ++i) { - auto sub_num = num + i * size / div; - fibers.emplace_back( boost::fibers::launch::dispatch, - std::allocator_arg, salloc, - skynet, - std::ref( salloc), std::ref( rc), sub_num, size / div, div); - } - for ( auto & f: fibers) { - f.join(); - } - std::uint64_t sum{ 0 }; - for ( std::size_t i = 0; i < div; ++i) { - sum += rc.value_pop(); - } - c.push( sum); - } -} - -int main() { - try { - std::size_t size{ 1000000 }; - std::size_t div{ 10 }; - // Windows 10 and FreeBSD require a fiber stack of 8kb - // otherwise the stack gets exhausted - // stack requirements must be checked for other OS too -#if BOOST_OS_WINDOWS || BOOST_OS_BSD - allocator_type salloc{ 2*allocator_type::traits_type::page_size() }; -#else - allocator_type salloc{ allocator_type::traits_type::page_size() }; -#endif - std::uint64_t result{ 0 }; - channel_type rc{ 2 }; - time_point_type start{ clock_type::now() }; - skynet( salloc, rc, 0, size, div); - result = rc.value_pop(); - if ( 499999500000 != result) { - throw std::runtime_error("invalid result"); - } - auto duration = clock_type::now() - start; - std::cout << "duration: " << duration.count() / 1000000 << " ms" << std::endl; - return EXIT_SUCCESS; - } catch ( std::exception const& e) { - std::cerr << "exception: " << e.what() << std::endl; - } catch (...) { - std::cerr << "unhandled exception" << std::endl; - } - return EXIT_FAILURE; -} diff --git a/performance/thread/Jamfile.v2 b/performance/thread/Jamfile.v2 deleted file mode 100644 index baa18210..00000000 --- a/performance/thread/Jamfile.v2 +++ /dev/null @@ -1,34 +0,0 @@ - -# Copyright Oliver Kowalke 2009. -# 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) - -# For more information, see http://www.boost.org/ - -import common ; -import feature ; -import indirect ; -import modules ; -import os ; -import toolset ; - -project boost/fiber/performance/thread - : requirements - static - multi - speed - release - ; - -exe skynet_async - : skynet_async.cpp - ; - -exe skynet_std - : skynet_std.cpp - ; - -exe skynet_pthread - : skynet_pthread.cpp - ; diff --git a/performance/thread/buffered_channel.hpp b/performance/thread/buffered_channel.hpp deleted file mode 100644 index 7f021dfc..00000000 --- a/performance/thread/buffered_channel.hpp +++ /dev/null @@ -1,228 +0,0 @@ - -// Copyright Oliver Kowalke 2016. -// 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) -// -// based on Dmitry Vyukov's MPMC queue -// (http://www.1024cores.net/home/lock-free-algorithms/queues/bounded-mpmc-queue) - -#ifndef BUFFERED_CHANNEL_H -#define BUFFERED_CHANNEL_H - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -enum class channel_op_status { - success = 0, - empty, - full, - closed, - timeout -}; - -template< typename T > -class buffered_channel { -public: - typedef T value_type; - -private: - typedef typename std::aligned_storage< sizeof( T), alignof( T) >::type storage_type; - - struct alignas(cache_alignment) slot { - std::atomic< std::size_t > cycle{ 0 }; - storage_type storage{}; - - slot() = default; - }; - - // procuder cacheline - alignas(cache_alignment) std::atomic< std::size_t > producer_idx_{ 0 }; - // consumer cacheline - alignas(cache_alignment) std::atomic< std::size_t > consumer_idx_{ 0 }; - // shared write cacheline - alignas(cache_alignment) std::atomic_bool closed_{ false }; - mutable std::mutex mtx_{}; - std::condition_variable not_full_cnd_{}; - std::condition_variable not_empty_cnd_{}; - // shared read cacheline - alignas(cache_alignment) slot * slots_{ nullptr }; - std::size_t capacity_; - char pad_[cacheline_length]; - std::size_t waiting_consumer_{ 0 }; - - bool is_full_() { - std::size_t idx{ producer_idx_.load( std::memory_order_relaxed) }; - return 0 > static_cast< std::intptr_t >( slots_[idx & (capacity_ - 1)].cycle.load( std::memory_order_acquire) ) - static_cast< std::intptr_t >( idx); - } - - bool is_empty_() { - std::size_t idx{ consumer_idx_.load( std::memory_order_relaxed) }; - return 0 > static_cast< std::intptr_t >( slots_[idx & (capacity_ - 1)].cycle.load( std::memory_order_acquire) ) - static_cast< std::intptr_t >( idx + 1); - } - - template< typename ValueType > - channel_op_status try_push_( ValueType && value) { - slot * s{ nullptr }; - std::size_t idx{ producer_idx_.load( std::memory_order_relaxed) }; - for (;;) { - s = & slots_[idx & (capacity_ - 1)]; - std::size_t cycle{ s->cycle.load( std::memory_order_acquire) }; - std::intptr_t diff{ static_cast< std::intptr_t >( cycle) - static_cast< std::intptr_t >( idx) }; - if ( 0 == diff) { - if ( producer_idx_.compare_exchange_weak( idx, idx + 1, std::memory_order_relaxed) ) { - break; - } - } else if ( 0 > diff) { - return channel_op_status::full; - } else { - idx = producer_idx_.load( std::memory_order_relaxed); - } - } - ::new ( static_cast< void * >( std::addressof( s->storage) ) ) value_type( std::forward< ValueType >( value) ); - s->cycle.store( idx + 1, std::memory_order_release); - return channel_op_status::success; - } - - channel_op_status try_value_pop_( slot *& s, std::size_t & idx) { - idx = consumer_idx_.load( std::memory_order_relaxed); - for (;;) { - s = & slots_[idx & (capacity_ - 1)]; - std::size_t cycle = s->cycle.load( std::memory_order_acquire); - std::intptr_t diff{ static_cast< std::intptr_t >( cycle) - static_cast< std::intptr_t >( idx + 1) }; - if ( 0 == diff) { - if ( consumer_idx_.compare_exchange_weak( idx, idx + 1, std::memory_order_relaxed) ) { - break; - } - } else if ( 0 > diff) { - return channel_op_status::empty; - } else { - idx = consumer_idx_.load( std::memory_order_relaxed); - } - } - // incrementing the slot cycle must be deferred till the value has been consumed - // slot cycle tells procuders that the cell can be re-used (store new value) - return channel_op_status::success; - } - - channel_op_status try_pop_( value_type & value) { - slot * s{ nullptr }; - std::size_t idx{ 0 }; - channel_op_status status{ try_value_pop_( s, idx) }; - if ( channel_op_status::success == status) { - value = std::move( * reinterpret_cast< value_type * >( std::addressof( s->storage) ) ); - s->cycle.store( idx + capacity_, std::memory_order_release); - } - return status; - } - -public: - explicit buffered_channel( std::size_t capacity) : - capacity_{ capacity } { - if ( 0 == capacity_ || 0 != ( capacity_ & (capacity_ - 1) ) ) { - throw std::runtime_error{ "boost fiber: buffer capacity is invalid" }; - } - slots_ = new slot[capacity_](); - for ( std::size_t i = 0; i < capacity_; ++i) { - slots_[i].cycle.store( i, std::memory_order_relaxed); - } - } - - ~buffered_channel() { - close(); - for (;;) { - slot * s{ nullptr }; - std::size_t idx{ 0 }; - if ( channel_op_status::success == try_value_pop_( s, idx) ) { - reinterpret_cast< value_type * >( std::addressof( s->storage) )->~value_type(); - s->cycle.store( idx + capacity_, std::memory_order_release); - } else { - break; - } - } - delete [] slots_; - } - - buffered_channel( buffered_channel const&) = delete; - buffered_channel & operator=( buffered_channel const&) = delete; - - bool is_closed() const noexcept { - return closed_.load( std::memory_order_acquire); - } - - void close() noexcept { - std::unique_lock< std::mutex > lk{ mtx_ }; - closed_.store( true, std::memory_order_release); - not_full_cnd_.notify_all(); - not_empty_cnd_.notify_all(); - } - - channel_op_status push( value_type const& value) { - for (;;) { - if ( is_closed() ) { - return channel_op_status::closed; - } - channel_op_status status{ try_push_( value) }; - if ( channel_op_status::success == status) { - std::unique_lock< std::mutex > lk{ mtx_ }; - if ( 0 < waiting_consumer_) { - not_empty_cnd_.notify_one(); - } - return status; - } else if ( channel_op_status::full == status) { - std::unique_lock< std::mutex > lk{ mtx_ }; - if ( is_closed() ) { - return channel_op_status::closed; - } - if ( ! is_full_() ) { - continue; - } - not_full_cnd_.wait( lk, [this]{ return is_closed() || ! is_full_(); }); - } else { - BOOST_ASSERT( channel_op_status::closed == status); - return status; - } - } - } - - value_type value_pop() { - for (;;) { - slot * s{ nullptr }; - std::size_t idx{ 0 }; - channel_op_status status{ try_value_pop_( s, idx) }; - if ( channel_op_status::success == status) { - value_type value{ std::move( * reinterpret_cast< value_type * >( std::addressof( s->storage) ) ) }; - s->cycle.store( idx + capacity_, std::memory_order_release); - not_full_cnd_.notify_one(); - return std::move( value); - } else if ( channel_op_status::empty == status) { - std::unique_lock< std::mutex > lk{ mtx_ }; - ++waiting_consumer_; - if ( is_closed() ) { - throw std::runtime_error{ "boost fiber: channel is closed" }; - } - if ( ! is_empty_() ) { - continue; - } - not_empty_cnd_.wait( lk, [this](){ return is_closed() || ! is_empty_(); }); - --waiting_consumer_; - } else { - BOOST_ASSERT( channel_op_status::closed == status); - throw std::runtime_error{ "boost fiber: channel is closed" }; - } - } - } -}; - -#endif // BUFFERED_CHANNEL_H diff --git a/performance/thread/skynet_async.cpp b/performance/thread/skynet_async.cpp deleted file mode 100644 index b752e020..00000000 --- a/performance/thread/skynet_async.cpp +++ /dev/null @@ -1,76 +0,0 @@ - -// Copyright Oliver Kowalke 2015. -// 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) - -// based on https://github.com/atemerev/skynet from Alexander Temerev - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "buffered_channel.hpp" - -using channel_type = buffered_channel< std::uint64_t >; -using clock_type = std::chrono::steady_clock; -using duration_type = clock_type::duration; -using time_point_type = clock_type::time_point; - -// microbenchmark -std::uint64_t skynet( std::uint64_t num, std::uint64_t size, std::uint64_t div) -{ - if ( size != 1){ - size /= div; - - std::vector > results; - results.reserve( div); - - for ( std::uint64_t i = 0; i != div; ++i) { - std::uint64_t sub_num = num + i * size; - results.emplace_back( - std::async( skynet, sub_num, size, div) ); - } - - std::uint64_t sum = 0; - for ( auto& f : results) - sum += f.get(); - - return sum; - } - - return num; -} - -int main() { - try { - std::size_t size{ 10000 }; - std::size_t div{ 10 }; - std::uint64_t result{ 0 }; - duration_type duration{ duration_type::zero() }; - time_point_type start{ clock_type::now() }; - result = skynet( 0, size, div); - duration = clock_type::now() - start; - std::cout << "Result: " << result << " in " << duration.count() / 1000000 << " ms" << std::endl; - std::cout << "done." << std::endl; - return EXIT_SUCCESS; - } catch ( std::exception const& e) { - std::cerr << "exception: " << e.what() << std::endl; - } catch (...) { - std::cerr << "unhandled exception" << std::endl; - } - return EXIT_FAILURE; -} diff --git a/performance/thread/skynet_pthread.cpp b/performance/thread/skynet_pthread.cpp deleted file mode 100644 index 43f55693..00000000 --- a/performance/thread/skynet_pthread.cpp +++ /dev/null @@ -1,90 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -extern "C" { -#include -#include -} - -#include "buffered_channel.hpp" - -using channel_type = buffered_channel< std::uint64_t >; -using clock_type = std::chrono::steady_clock; -using duration_type = clock_type::duration; -using time_point_type = clock_type::time_point; - -struct thread_args { - channel_type & c; - std::size_t num; - std::size_t size; - std::size_t div; -}; - -// microbenchmark -void * skynet( void * vargs) { - thread_args * args = static_cast< thread_args * >( vargs); - if ( 1 == args->size) { - args->c.push( args->num); - } else { - channel_type rc{ 16 }; - for ( std::size_t i = 0; i < args->div; ++i) { - auto sub_num = args->num + i * args->size / args->div; - auto sub_size = args->size / args->div; - auto size = 8 * 1024; - pthread_attr_t tattr; - if ( 0 != ::pthread_attr_init( & tattr) ) { - std::runtime_error("pthread_attr_init() failed"); - } - if ( 0 != ::pthread_attr_setstacksize( & tattr, size) ) { - std::runtime_error("pthread_attr_setstacksize() failed"); - } - thread_args * targs = new thread_args{ rc, sub_num, sub_size, args->div }; - pthread_t tid; - if ( 0 != ::pthread_create( & tid, & tattr, & skynet, targs) ) { - std::runtime_error("pthread_create() failed"); - } - if ( 0 != ::pthread_detach( tid) ) { - std::runtime_error("pthread_detach() failed"); - } - } - std::uint64_t sum{ 0 }; - for ( std::size_t i = 0; i < args->div; ++i) { - sum += rc.value_pop(); - } - args->c.push( sum); - } - delete args; - return nullptr; -} - -int main() { - try { - std::size_t size{ 10000 }; - std::size_t div{ 10 }; - std::uint64_t result{ 0 }; - duration_type duration{ duration_type::zero() }; - channel_type rc{ 2 }; - thread_args * targs = new thread_args{ rc, 0, size, div }; - time_point_type start{ clock_type::now() }; - skynet( targs); - result = rc.value_pop(); - duration = clock_type::now() - start; - std::cout << "Result: " << result << " in " << duration.count() / 1000000 << " ms" << std::endl; - std::cout << "done." << std::endl; - return EXIT_SUCCESS; - } catch ( std::exception const& e) { - std::cerr << "exception: " << e.what() << std::endl; - } catch (...) { - std::cerr << "unhandled exception" << std::endl; - } - return EXIT_FAILURE; -} diff --git a/performance/thread/skynet_std.cpp b/performance/thread/skynet_std.cpp deleted file mode 100644 index 93248f2e..00000000 --- a/performance/thread/skynet_std.cpp +++ /dev/null @@ -1,58 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "buffered_channel.hpp" - -using channel_type = buffered_channel< std::uint64_t >; -using clock_type = std::chrono::steady_clock; -using duration_type = clock_type::duration; -using time_point_type = clock_type::time_point; - -// microbenchmark -void skynet( channel_type & c, std::size_t num, std::size_t size, std::size_t div) { - if ( 1 == size) { - c.push( num); - } else { - channel_type rc{ 16 }; - for ( std::size_t i = 0; i < div; ++i) { - auto sub_num = num + i * size / div; - std::thread{ skynet, std::ref( rc), sub_num, size / div, div }.detach(); - } - std::uint64_t sum{ 0 }; - for ( std::size_t i = 0; i < div; ++i) { - sum += rc.value_pop(); - } - c.push( sum); - } -} - -int main() { - try { - std::size_t size{ 10000 }; - std::size_t div{ 10 }; - std::uint64_t result{ 0 }; - duration_type duration{ duration_type::zero() }; - channel_type rc{ 2 }; - time_point_type start{ clock_type::now() }; - skynet( rc, 0, size, div); - result = rc.value_pop(); - duration = clock_type::now() - start; - std::cout << "Result: " << result << " in " << duration.count() / 1000000 << " ms" << std::endl; - std::cout << "done." << std::endl; - return EXIT_SUCCESS; - } catch ( std::exception const& e) { - std::cerr << "exception: " << e.what() << std::endl; - } catch (...) { - std::cerr << "unhandled exception" << std::endl; - } - return EXIT_FAILURE; -} From dd5c7f3fda13f53d8b2b36fcce5b9e932736b17b Mon Sep 17 00:00:00 2001 From: James Hunsaker <18537138+jhunsaker@users.noreply.github.com> Date: Wed, 8 Apr 2026 00:46:41 -0400 Subject: [PATCH 11/15] Remove asio examples Co-Authored-By: Claude Opus 4.6 --- examples/asio/autoecho.cpp | 261 ---------------------- examples/asio/detail/yield.hpp | 297 ------------------------- examples/asio/ps/publisher.cpp | 52 ----- examples/asio/ps/server.cpp | 381 -------------------------------- examples/asio/ps/subscriber.cpp | 53 ----- examples/asio/round_robin.hpp | 194 ---------------- examples/asio/yield.hpp | 63 ------ 7 files changed, 1301 deletions(-) delete mode 100644 examples/asio/autoecho.cpp delete mode 100644 examples/asio/detail/yield.hpp delete mode 100644 examples/asio/ps/publisher.cpp delete mode 100644 examples/asio/ps/server.cpp delete mode 100644 examples/asio/ps/subscriber.cpp delete mode 100644 examples/asio/round_robin.hpp delete mode 100644 examples/asio/yield.hpp diff --git a/examples/asio/autoecho.cpp b/examples/asio/autoecho.cpp deleted file mode 100644 index ace251b1..00000000 --- a/examples/asio/autoecho.cpp +++ /dev/null @@ -1,261 +0,0 @@ -// Copyright 2003-2013 Christopher M. Kohlhoff -// Copyright Oliver Kowalke, Nat Goodspeed 2015. -// 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 -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include "round_robin.hpp" -#include "yield.hpp" - -using boost::asio::ip::tcp; - -const int max_length = 1024; - -typedef boost::shared_ptr< tcp::socket > socket_ptr; - -const char* const alpha = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; - -/***************************************************************************** -* thread names -*****************************************************************************/ -class ThreadNames { -private: - std::map names_{}; - const char* next_{ alpha }; - std::mutex mtx_{}; - -public: - ThreadNames() = default; - - std::string lookup() { - std::unique_lock lk( mtx_); - auto this_id( std::this_thread::get_id() ); - auto found = names_.find( this_id ); - if ( found != names_.end() ) { - return found->second; - } - BOOST_ASSERT( *next_); - std::string name(1, *next_++ ); - names_[ this_id ] = name; - return name; - } -}; - -ThreadNames thread_names; - -/***************************************************************************** -* fiber names -*****************************************************************************/ -class FiberNames { -private: - std::map names_{}; - unsigned next_{ 0 }; - boost::fibers::mutex mtx_{}; - -public: - FiberNames() = default; - - std::string lookup() { - std::unique_lock lk( mtx_); - auto this_id( boost::this_fiber::get_id() ); - auto found = names_.find( this_id ); - if ( found != names_.end() ) { - return found->second; - } - std::ostringstream out; - // Bake into the fiber's name the thread name on which we first - // lookup() its ID, to be able to spot when a fiber hops between - // threads. - out << thread_names.lookup() << next_++; - std::string name( out.str() ); - names_[ this_id ] = name; - return name; - } -}; - -FiberNames fiber_names; - -std::string tag() { - std::ostringstream out; - out << "Thread " << thread_names.lookup() << ": " - << std::setw(4) << fiber_names.lookup() << std::setw(0); - return out.str(); -} - -/***************************************************************************** -* message printing -*****************************************************************************/ -void print_( std::ostream& out) { - out << '\n'; -} - -template < typename T, typename... Ts > -void print_( std::ostream& out, T const& arg, Ts const&... args) { - out << arg; - print_(out, args...); -} - -template < typename... T > -void print( T const&... args ) { - std::ostringstream buffer; - print_( buffer, args...); - std::cout << buffer.str() << std::flush; -} - -/***************************************************************************** -* fiber function per server connection -*****************************************************************************/ -void session( socket_ptr sock) { - try { - for (;;) { - char data[max_length]; - boost::system::error_code ec; - std::size_t length = sock->async_read_some( - boost::asio::buffer( data), - boost::fibers::asio::yield[ec]); - if ( ec == boost::asio::error::eof) { - break; //connection closed cleanly by peer - } else if ( ec) { - throw boost::system::system_error( ec); //some other error - } - print( tag(), ": handled: ", std::string(data, length)); - boost::asio::async_write( - * sock, - boost::asio::buffer( data, length), - boost::fibers::asio::yield[ec]); - if ( ec == boost::asio::error::eof) { - break; //connection closed cleanly by peer - } else if ( ec) { - throw boost::system::system_error( ec); //some other error - } - } - print( tag(), ": connection closed"); - } catch ( std::exception const& ex) { - print( tag(), ": caught exception : ", ex.what()); - } -} - -/***************************************************************************** -* listening server -*****************************************************************************/ -void server( std::shared_ptr< boost::asio::io_context > const& io_ctx, tcp::acceptor & a) { - print( tag(), ": echo-server started"); - try { - for (;;) { - socket_ptr socket( new tcp::socket( * io_ctx) ); - boost::system::error_code ec; - a.async_accept( - * socket, - boost::fibers::asio::yield[ec]); - if ( ec) { - throw boost::system::system_error( ec); //some other error - } else { - boost::fibers::fiber( session, socket).detach(); - } - } - } catch ( std::exception const& ex) { - print( tag(), ": caught exception : ", ex.what()); - } - io_ctx->stop(); - print( tag(), ": echo-server stopped"); -} - -/***************************************************************************** -* fiber function per client -*****************************************************************************/ -void client( std::shared_ptr< boost::asio::io_context > const& io_ctx, tcp::acceptor & a, - boost::fibers::barrier& barrier, unsigned iterations) { - print( tag(), ": echo-client started"); - for (unsigned count = 0; count < iterations; ++count) { - tcp::resolver resolver( * io_ctx); - tcp::resolver::query query( tcp::v4(), "127.0.0.1", "9999"); - tcp::resolver::iterator iterator = resolver.resolve( query); - tcp::socket s( * io_ctx); - boost::asio::connect( s, iterator); - for (unsigned msg = 0; msg < 1; ++msg) { - std::ostringstream msgbuf; - msgbuf << "from " << fiber_names.lookup() << " " << count << "." << msg; - std::string message(msgbuf.str()); - print( tag(), ": Sending: ", message); - boost::system::error_code ec; - boost::asio::async_write( - s, - boost::asio::buffer( message), - boost::fibers::asio::yield[ec]); - if ( ec == boost::asio::error::eof) { - return; //connection closed cleanly by peer - } else if ( ec) { - throw boost::system::system_error( ec); //some other error - } - char reply[max_length]; - size_t reply_length = s.async_read_some( - boost::asio::buffer( reply, max_length), - boost::fibers::asio::yield[ec]); - if ( ec == boost::asio::error::eof) { - return; //connection closed cleanly by peer - } else if ( ec) { - throw boost::system::system_error( ec); //some other error - } - print( tag(), ": Reply : ", std::string( reply, reply_length)); - } - } - // done with all iterations, wait for rest of client fibers - if ( barrier.wait()) { - // exactly one barrier.wait() call returns true - // we're the lucky one - a.close(); - print( tag(), ": acceptor stopped"); - } - print( tag(), ": echo-client stopped"); -} - -/***************************************************************************** -* main -*****************************************************************************/ -int main( int argc, char* argv[]) { - try { -//[asio_rr_setup - std::shared_ptr< boost::asio::io_context > io_ctx = std::make_shared< boost::asio::io_context >(); - boost::fibers::use_scheduling_algorithm< boost::fibers::asio::round_robin >( io_ctx); -//] - print( "Thread ", thread_names.lookup(), ": started"); -//[asio_rr_launch_fibers - // server - tcp::acceptor a( * io_ctx, tcp::endpoint( tcp::v4(), 9999) ); - boost::fibers::fiber( server, io_ctx, std::ref( a) ).detach(); - // client - const unsigned iterations = 2; - const unsigned clients = 3; - boost::fibers::barrier b( clients); - for ( unsigned i = 0; i < clients; ++i) { - boost::fibers::fiber( - client, io_ctx, std::ref( a), std::ref( b), iterations).detach(); - } -//] -//[asio_rr_run - io_ctx->run(); -//] - print( tag(), ": io_context returned"); - print( "Thread ", thread_names.lookup(), ": stopping"); - std::cout << "done." << std::endl; - return EXIT_SUCCESS; - } catch ( std::exception const& e) { - print("Exception: ", e.what(), "\n"); - } - return EXIT_FAILURE; -} diff --git a/examples/asio/detail/yield.hpp b/examples/asio/detail/yield.hpp deleted file mode 100644 index 7bf3a261..00000000 --- a/examples/asio/detail/yield.hpp +++ /dev/null @@ -1,297 +0,0 @@ -// Copyright Oliver Kowalke, Nat Goodspeed 2015. -// 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) - -// modified for boost.asio >= 1.70 - -#ifndef BOOST_FIBERS_ASIO_DETAIL_YIELD_HPP -#define BOOST_FIBERS_ASIO_DETAIL_YIELD_HPP - -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include // std::unique_lock - -#ifdef BOOST_HAS_ABI_HEADERS -# include BOOST_ABI_PREFIX -#endif - -namespace boost { -namespace fibers { -namespace asio { -namespace detail { - -//[fibers_asio_yield_completion -// Bundle a completion bool flag with a spinlock to protect it. -struct yield_completion { - enum state_t { - init, - waiting, - complete - }; - - typedef fibers::detail::spinlock mutex_t; - typedef std::unique_lock< mutex_t > lock_t; - typedef boost::intrusive_ptr< yield_completion > ptr_t; - - std::atomic< std::size_t > use_count_{ 0 }; - mutex_t mtx_{}; - state_t state_{ init }; - - void wait() { - // yield_handler_base::operator()() will set state_ `complete` and - // attempt to wake a suspended fiber. It would be Bad if that call - // happened between our detecting (complete != state_) and suspending. - lock_t lk{ mtx_ }; - // If state_ is already set, we're done here: don't suspend. - if ( complete != state_) { - state_ = waiting; - // suspend(unique_lock) unlocks the lock in the act of - // resuming another fiber - fibers::context::active()->suspend( lk); - } - } - - friend void intrusive_ptr_add_ref( yield_completion * yc) noexcept { - BOOST_ASSERT( nullptr != yc); - yc->use_count_.fetch_add( 1, std::memory_order_relaxed); - } - - friend void intrusive_ptr_release( yield_completion * yc) noexcept { - BOOST_ASSERT( nullptr != yc); - if ( 1 == yc->use_count_.fetch_sub( 1, std::memory_order_release) ) { - std::atomic_thread_fence( std::memory_order_acquire); - delete yc; - } - } -}; -//] - -//[fibers_asio_yield_handler_base -// This class encapsulates common elements between yield_handler (capturing -// a value to return from asio async function) and yield_handler (no -// such value). See yield_handler and its specialization below. Both -// yield_handler and yield_handler are passed by value through -// various layers of asio functions. In other words, they're potentially -// copied multiple times. So key data such as the yield_completion instance -// must be stored in our async_result> specialization, which -// should be instantiated only once. -class yield_handler_base { -public: - yield_handler_base( yield_t const& y) : - // capture the context* associated with the running fiber - ctx_{ boost::fibers::context::active() }, - // capture the passed yield_t - yt_( y ) { - } - - // completion callback passing only (error_code) - void operator()( boost::system::error_code const& ec) { - BOOST_ASSERT_MSG( ycomp_, - "Must inject yield_completion* " - "before calling yield_handler_base::operator()()"); - BOOST_ASSERT_MSG( yt_.ec_, - "Must inject boost::system::error_code* " - "before calling yield_handler_base::operator()()"); - // If originating fiber is busy testing state_ flag, wait until it - // has observed (completed != state_). - yield_completion::lock_t lk{ ycomp_->mtx_ }; - yield_completion::state_t state = ycomp_->state_; - // Notify a subsequent yield_completion::wait() call that it need not - // suspend. - ycomp_->state_ = yield_completion::complete; - // set the error_code bound by yield_t - * yt_.ec_ = ec; - // unlock the lock that protects state_ - lk.unlock(); - // If ctx_ is still active, e.g. because the async operation - // immediately called its callback (this method!) before the asio - // async function called async_result_base::get(), we must not set it - // ready. - if ( yield_completion::waiting == state) { - // wake the fiber - fibers::context::active()->schedule( ctx_); - } - } - -//private: - boost::fibers::context * ctx_; - yield_t yt_; - // We depend on this pointer to yield_completion, which will be injected - // by async_result. - yield_completion::ptr_t ycomp_{}; -}; -//] - -//[fibers_asio_yield_handler_T -// asio uses handler_type::type to decide -// what to instantiate as the actual handler. Below, we specialize -// handler_type< yield_t, ... > to indicate yield_handler<>. So when you pass -// an instance of yield_t as an asio completion token, asio selects -// yield_handler<> as the actual handler class. -template< typename T > -class yield_handler: public yield_handler_base { -public: - // asio passes the completion token to the handler constructor - explicit yield_handler( yield_t const& y) : - yield_handler_base{ y } { - } - - // completion callback passing only value (T) - void operator()( T t) { - // just like callback passing success error_code - (*this)( boost::system::error_code(), std::move(t) ); - } - - // completion callback passing (error_code, T) - void operator()( boost::system::error_code const& ec, T t) { - BOOST_ASSERT_MSG( value_, - "Must inject value ptr " - "before caling yield_handler::operator()()"); - // move the value to async_result<> instance BEFORE waking up a - // suspended fiber - * value_ = std::move( t); - // forward the call to base-class completion handler - yield_handler_base::operator()( ec); - } - -//private: - // pointer to destination for eventual value - // this must be injected by async_result before operator()() is called - T * value_{ nullptr }; -}; -//] - -//[fibers_asio_yield_handler_void -// yield_handler is like yield_handler without value_. In fact it's -// just like yield_handler_base. -template<> -class yield_handler< void >: public yield_handler_base { -public: - explicit yield_handler( yield_t const& y) : - yield_handler_base{ y } { - } - - // nullary completion callback - void operator()() { - ( * this)( boost::system::error_code() ); - } - - // inherit operator()(error_code) overload from base class - using yield_handler_base::operator(); -}; -//] - -// Specialize asio_handler_invoke hook to ensure that any exceptions thrown -// from the handler are propagated back to the caller -template< typename Fn, typename T > -void asio_handler_invoke( Fn&& fn, yield_handler< T > *) { - fn(); -} - -//[fibers_asio_async_result_base -// Factor out commonality between async_result> and -// async_result> -class async_result_base { -public: - explicit async_result_base( yield_handler_base & h) : - ycomp_{ new yield_completion{} } { - // Inject ptr to our yield_completion instance into this - // yield_handler<>. - h.ycomp_ = this->ycomp_; - // if yield_t didn't bind an error_code, make yield_handler_base's - // error_code* point to an error_code local to this object so - // yield_handler_base::operator() can unconditionally store through - // its error_code* - if ( ! h.yt_.ec_) { - h.yt_.ec_ = & ec_; - } - } - - void get() { - // Unless yield_handler_base::operator() has already been called, - // suspend the calling fiber until that call. - ycomp_->wait(); - // The only way our own ec_ member could have a non-default value is - // if our yield_handler did not have a bound error_code AND the - // completion callback passed a non-default error_code. - if ( ec_) { - throw_exception( boost::system::system_error{ ec_ } ); - } - } - -private: - // If yield_t does not bind an error_code instance, store into here. - boost::system::error_code ec_{}; - yield_completion::ptr_t ycomp_; -}; -//] - -}}}} - -namespace boost { -namespace asio { - -//[fibers_asio_async_result_T -// asio constructs an async_result<> instance from the yield_handler specified -// by handler_type<>::type. A particular asio async method constructs the -// yield_handler, constructs this async_result specialization from it, then -// returns the result of calling its get() method. -template< typename ReturnType, typename T > -class async_result< boost::fibers::asio::yield_t, ReturnType(boost::system::error_code, T) > : - public boost::fibers::asio::detail::async_result_base { -public: - // type returned by get() - using return_type = T; - using completion_handler_type = fibers::asio::detail::yield_handler; - - explicit async_result( boost::fibers::asio::detail::yield_handler< T > & h) : - boost::fibers::asio::detail::async_result_base{ h } { - // Inject ptr to our value_ member into yield_handler<>: result will - // be stored here. - h.value_ = & value_; - } - - // asio async method returns result of calling get() - return_type get() { - boost::fibers::asio::detail::async_result_base::get(); - return std::move( value_); - } - -private: - return_type value_{}; -}; -//] - -//[fibers_asio_async_result_void -// Without the need to handle a passed value, our yield_handler -// specialization is just like async_result_base. -template<> -class async_result< boost::fibers::asio::yield_t, void(boost::system::error_code) > : - public boost::fibers::asio::detail::async_result_base { -public: - using return_type = void; - using completion_handler_type = fibers::asio::detail::yield_handler; - - explicit async_result( boost::fibers::asio::detail::yield_handler< void > & h): - boost::fibers::asio::detail::async_result_base{ h } { - } -}; -//] - -}} - -#ifdef BOOST_HAS_ABI_HEADERS -# include BOOST_ABI_SUFFIX -#endif - -#endif // BOOST_FIBERS_ASIO_DETAIL_YIELD_HPP diff --git a/examples/asio/ps/publisher.cpp b/examples/asio/ps/publisher.cpp deleted file mode 100644 index 245e56cc..00000000 --- a/examples/asio/ps/publisher.cpp +++ /dev/null @@ -1,52 +0,0 @@ -// -// blocking_tcp_echo_client.cpp -// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// -// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com) -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -// - -#include -#include -#include - -#include - -using boost::asio::ip::tcp; - -enum { - max_length = 1024 -}; - -int main( int argc, char* argv[]) { - try { - if ( 3 != argc) { - std::cerr << "Usage: publisher \n"; - return EXIT_FAILURE; - } - boost::asio::io_context io_context; - tcp::resolver resolver( io_context); - tcp::resolver::query query( tcp::v4(), argv[1], "9997"); - tcp::resolver::iterator iterator = resolver.resolve(query); - tcp::socket s( io_context); - boost::asio::connect( s, iterator); - char msg[max_length]; - std::string queue( argv[2]); - std::memset( msg, '\0', max_length); - std::memcpy( msg, queue.c_str(), queue.size() ); - boost::asio::write( s, boost::asio::buffer( msg, max_length) ); - for (;;) { - std::cout << "publish: "; - char request[max_length]; - std::cin.getline( request, max_length); - boost::asio::write( s, boost::asio::buffer( request, max_length) ); - } - return EXIT_SUCCESS; - } catch ( std::exception const& e) { - std::cerr << "Exception: " << e.what() << "\n"; - } - - return EXIT_FAILURE; -} diff --git a/examples/asio/ps/server.cpp b/examples/asio/ps/server.cpp deleted file mode 100644 index f4496f80..00000000 --- a/examples/asio/ps/server.cpp +++ /dev/null @@ -1,381 +0,0 @@ -// Copyright Oliver Kowalke 2015. -// 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 -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include "../round_robin.hpp" -#include "../yield.hpp" - -using boost::asio::ip::tcp; - -const std::size_t max_length = 1024; - -class subscriber_session; -typedef std::shared_ptr< subscriber_session > subscriber_session_ptr; - -// a queue has n subscribers (subscriptions) -// this class holds a list of subcribers for one queue -class subscriptions { -public: - ~subscriptions(); - - // subscribe to this queue - void subscribe( subscriber_session_ptr const& s) { - subscribers_.insert( s); - } - - // unsubscribe from this queue - void unsubscribe( subscriber_session_ptr const& s) { - subscribers_.erase(s); - } - - // publish a message, e.g. push this message to all subscribers - void publish( std::string const& msg); - -private: - // list of subscribers - std::set< subscriber_session_ptr > subscribers_; -}; - -// a class to register queues and to subsribe clients to this queues -class registry : private boost::noncopyable { -private: - typedef std::map< std::string, std::shared_ptr< subscriptions > > queues_cont; - typedef queues_cont::iterator queues_iter; - - boost::fibers::mutex mtx_; - queues_cont queues_; - - void register_queue_( std::string const& queue) { - if ( queues_.end() != queues_.find( queue) ) { - throw std::runtime_error("queue already exists"); - } - queues_[queue] = std::make_shared< subscriptions >(); - std::cout << "new queue '" << queue << "' registered" << std::endl; - } - - void unregister_queue_( std::string const& queue) { - queues_.erase( queue); - std::cout << "queue '" << queue << "' unregistered" << std::endl; - } - - void subscribe_( std::string const& queue, subscriber_session_ptr s) { - queues_iter iter = queues_.find( queue); - if ( queues_.end() == iter ) { - throw std::runtime_error("queue does not exist"); - } - iter->second->subscribe( s); - std::cout << "new subscription to queue '" << queue << "'" << std::endl; - } - - void unsubscribe_( std::string const& queue, subscriber_session_ptr s) { - queues_iter iter = queues_.find( queue); - if ( queues_.end() != iter ) { - iter->second->unsubscribe( s); - } - } - - void publish_( std::string const& queue, std::string const& msg) { - queues_iter iter = queues_.find( queue); - if ( queues_.end() == iter ) { - throw std::runtime_error("queue does not exist"); - } - iter->second->publish( msg); - std::cout << "message '" << msg << "' to publish on queue '" << queue << "'" << std::endl; - } - -public: - // add a queue to registry - void register_queue( std::string const& queue) { - std::unique_lock< boost::fibers::mutex > lk( mtx_); - register_queue_( queue); - } - - // remove a queue from registry - void unregister_queue( std::string const& queue) { - std::unique_lock< boost::fibers::mutex > lk( mtx_); - unregister_queue_( queue); - } - - // subscribe to a queue - void subscribe( std::string const& queue, subscriber_session_ptr s) { - std::unique_lock< boost::fibers::mutex > lk( mtx_); - subscribe_( queue, s); - } - - // unsubscribe from a queue - void unsubscribe( std::string const& queue, subscriber_session_ptr s) { - std::unique_lock< boost::fibers::mutex > lk( mtx_); - unsubscribe_( queue, s); - } - - // publish a message to all subscribers registerd to the queue - void publish( std::string const& queue, std::string const& msg) { - std::unique_lock< boost::fibers::mutex > lk( mtx_); - publish_( queue, msg); - } -}; - -// a subscriber subscribes to a given queue in order to receive messages published on this queue -class subscriber_session : public std::enable_shared_from_this< subscriber_session > { -public: - explicit subscriber_session( std::shared_ptr< boost::asio::io_context > const& io_context, registry & reg) : - socket_( * io_context), - reg_( reg) { - } - - tcp::socket& socket() { - return socket_; - } - - // this function is executed inside the fiber - void run() { - std::string queue; - try { - boost::system::error_code ec; - // read first message == queue name - // async_ready() returns if the the complete message is read - // until this the fiber is suspended until the complete message - // is read int the given buffer 'data' - boost::asio::async_read( - socket_, - boost::asio::buffer( data_), - boost::fibers::asio::yield[ec]); - if ( ec) { - throw std::runtime_error("no queue from subscriber"); - } - // first message ist equal to the queue name the publisher - // publishes to - queue = data_; - // subscribe to new queue - reg_.subscribe( queue, shared_from_this() ); - // read published messages - for (;;) { - // wait for a conditon-variable for new messages - // the fiber will be suspended until the condtion - // becomes true and the fiber is resumed - // published message is stored in buffer 'data_' - std::unique_lock< boost::fibers::mutex > lk( mtx_); - cond_.wait( lk); - std::string data( data_); - lk.unlock(); - // message '' terminates subscription - if ( "" == data) { - break; - } - // async. write message to socket connected with - // subscriber - // async_write() returns if the complete message was writen - // the fiber is suspended in the meanwhile - boost::asio::async_write( - socket_, - boost::asio::buffer( data, data.size() ), - boost::fibers::asio::yield[ec]); - if ( ec == boost::asio::error::eof) { - break; //connection closed cleanly by peer - } else if ( ec) { - throw boost::system::system_error( ec); //some other error - } - std::cout << "subscriber::run(): '" << data << "' written" << std::endl; - } - } catch ( std::exception const& e) { - std::cerr << "subscriber [" << queue << "] failed: " << e.what() << std::endl; - } - // close socket - socket_.close(); - // unregister queue - reg_.unsubscribe( queue, shared_from_this() ); - } - - // called from publisher_session (running in other fiber) - void publish( std::string const& msg) { - std::unique_lock< boost::fibers::mutex > lk( mtx_); - std::memset( data_, '\0', sizeof( data_)); - std::memcpy( data_, msg.c_str(), (std::min)(max_length, msg.size())); - cond_.notify_one(); - } - -private: - tcp::socket socket_; - registry & reg_; - boost::fibers::mutex mtx_; - boost::fibers::condition_variable cond_; - // fixed size message - char data_[max_length]; -}; - - -subscriptions::~subscriptions() { - for ( subscriber_session_ptr s : subscribers_) { - s->publish(""); - } -} - -void -subscriptions::publish( std::string const& msg) { - for ( subscriber_session_ptr s : subscribers_) { - s->publish( msg); - } -} - -// a publisher publishes messages on its queue -// subscriber might register to this queue to get the published messages -class publisher_session : public std::enable_shared_from_this< publisher_session > { -public: - explicit publisher_session( std::shared_ptr< boost::asio::io_context > const& io_context, registry & reg) : - socket_( * io_context), - reg_( reg) { - } - - tcp::socket& socket() { - return socket_; - } - - // this function is executed inside the fiber - void run() { - std::string queue; - try { - boost::system::error_code ec; - // fixed size message - char data[max_length]; - // read first message == queue name - // async_ready() returns if the the complete message is read - // until this the fiber is suspended until the complete message - // is read int the given buffer 'data' - boost::asio::async_read( - socket_, - boost::asio::buffer( data), - boost::fibers::asio::yield[ec]); - if ( ec) { - throw std::runtime_error("no queue from publisher"); - } - // first message ist equal to the queue name the publisher - // publishes to - queue = data; - // register the new queue - reg_.register_queue( queue); - // start publishing messages - for (;;) { - // read message from publisher asyncronous - // async_read() suspends this fiber until the complete emssage is read - // and stored in the given buffer 'data' - boost::asio::async_read( - socket_, - boost::asio::buffer( data), - boost::fibers::asio::yield[ec]); - if ( ec == boost::asio::error::eof) { - break; //connection closed cleanly by peer - } else if ( ec) { - throw boost::system::system_error( ec); //some other error - } - // publish message to all subscribers - reg_.publish( queue, std::string( data) ); - } - } catch ( std::exception const& e) { - std::cerr << "publisher [" << queue << "] failed: " << e.what() << std::endl; - } - // close socket - socket_.close(); - // unregister queue - reg_.unregister_queue( queue); - } - -private: - tcp::socket socket_; - registry & reg_; -}; - -typedef std::shared_ptr< publisher_session > publisher_session_ptr; - -// function accepts connections requests from clients acting as a publisher -void accept_publisher( std::shared_ptr< boost::asio::io_context > const& io_context, - unsigned short port, - registry & reg) { - // create TCP-acceptor - tcp::acceptor acceptor( * io_context, tcp::endpoint( tcp::v4(), port) ); - // loop for accepting connection requests - for (;;) { - boost::system::error_code ec; - // create new publisher-session - // this instance will be associated with one publisher - publisher_session_ptr new_publisher_session = - std::make_shared< publisher_session >( io_context, std::ref( reg) ); - // async. accept of new connection request - // this function will suspend this execution context (fiber) until a - // connection was established, after returning from this function a new client (publisher) - // is connected - acceptor.async_accept( - new_publisher_session->socket(), - boost::fibers::asio::yield[ec]); - if ( ! ec) { - // run the new publisher in its own fiber (one fiber for one client) - boost::fibers::fiber( - std::bind( & publisher_session::run, new_publisher_session) ).detach(); - } - } -} - -// function accepts connections requests from clients acting as a subscriber -void accept_subscriber( std::shared_ptr< boost::asio::io_context > const& io_context, - unsigned short port, - registry & reg) { - // create TCP-acceptor - tcp::acceptor acceptor( * io_context, tcp::endpoint( tcp::v4(), port) ); - // loop for accepting connection requests - for (;;) { - boost::system::error_code ec; - // create new subscriber-session - // this instance will be associated with one subscriber - subscriber_session_ptr new_subscriber_session = - std::make_shared< subscriber_session >( io_context, std::ref( reg) ); - // async. accept of new connection request - // this function will suspend this execution context (fiber) until a - // connection was established, after returning from this function a new client (subscriber) - // is connected - acceptor.async_accept( - new_subscriber_session->socket(), - boost::fibers::asio::yield[ec]); - if ( ! ec) { - // run the new subscriber in its own fiber (one fiber for one client) - boost::fibers::fiber( - std::bind( & subscriber_session::run, new_subscriber_session) ).detach(); - } - } -} - - -int main( int argc, char* argv[]) { - try { - // create io_context for async. I/O - std::shared_ptr< boost::asio::io_context > io_context = std::make_shared< boost::asio::io_context >(); - // register asio scheduler - boost::fibers::use_scheduling_algorithm< boost::fibers::asio::round_robin >( io_context); - // registry for queues and its subscription - registry reg; - // create an acceptor for publishers, run it as fiber - boost::fibers::fiber( - accept_publisher, std::ref( io_context), 9997, std::ref( reg) ).detach(); - // create an acceptor for subscribers, run it as fiber - boost::fibers::fiber( - accept_subscriber, std::ref( io_context), 9998, std::ref( reg) ).detach(); - // dispatch - io_context->run(); - return EXIT_SUCCESS; - } catch ( std::exception const& e) { - std::cerr << "Exception: " << e.what() << "\n"; - } - - return EXIT_FAILURE; -} diff --git a/examples/asio/ps/subscriber.cpp b/examples/asio/ps/subscriber.cpp deleted file mode 100644 index 83b5e8b3..00000000 --- a/examples/asio/ps/subscriber.cpp +++ /dev/null @@ -1,53 +0,0 @@ -// -// blocking_tcp_echo_client.cpp -// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// -// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com) -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -// - -#include -#include -#include - -#include - -using boost::asio::ip::tcp; - -enum { - max_length = 1024 -}; - -int main( int argc, char* argv[]) { - try { - if ( 3 != argc) { - std::cerr << "Usage: subscriber \n"; - return EXIT_FAILURE; - } - boost::asio::io_context io_context; - tcp::resolver resolver( io_context); - tcp::resolver::query query( tcp::v4(), argv[1], "9998"); - tcp::resolver::iterator iterator = resolver.resolve( query); - tcp::socket s( io_context); - boost::asio::connect( s, iterator); - char msg[max_length]; - std::string queue( argv[2]); - std::memset( msg, '\0', max_length); - std::memcpy( msg, queue.c_str(), queue.size() ); - boost::asio::write( s, boost::asio::buffer( msg, max_length) ); - for (;;) { - char reply[max_length]; - size_t reply_length = s.read_some( boost::asio::buffer( reply, max_length) ); - std::cout << "published: "; - std::cout.write( reply, reply_length); - std::cout << std::endl; - } - return EXIT_SUCCESS; - } catch ( std::exception const& e) { - std::cerr << "Exception: " << e.what() << "\n"; - } - - return EXIT_FAILURE; -} diff --git a/examples/asio/round_robin.hpp b/examples/asio/round_robin.hpp deleted file mode 100644 index 02b3fbdb..00000000 --- a/examples/asio/round_robin.hpp +++ /dev/null @@ -1,194 +0,0 @@ -// 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) - -#ifndef BOOST_FIBERS_ASIO_ROUND_ROBIN_H -#define BOOST_FIBERS_ASIO_ROUND_ROBIN_H - -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include "yield.hpp" - -#ifdef BOOST_HAS_ABI_HEADERS -# include BOOST_ABI_PREFIX -#endif - -namespace boost { -namespace fibers { -namespace asio { - -class round_robin : public algo::algorithm { -private: -//[asio_rr_suspend_timer - std::shared_ptr< boost::asio::io_context > io_ctx_; - boost::asio::steady_timer suspend_timer_; -//] - boost::fibers::scheduler::ready_queue_type rqueue_{}; - boost::fibers::mutex mtx_{}; - boost::fibers::condition_variable cnd_{}; - std::size_t counter_{ 0 }; - -public: -//[asio_rr_service_top - struct service : public boost::asio::io_context::service { - static boost::asio::io_context::id id; - - std::unique_ptr< boost::asio::io_context::work > work_; - - service( boost::asio::io_context & io_ctx) : - boost::asio::io_context::service( io_ctx), - work_{ new boost::asio::io_context::work( io_ctx) } { - } - - virtual ~service() {} - - service( service const&) = delete; - service & operator=( service const&) = delete; - - void shutdown_service() override final { - work_.reset(); - } - }; -//] - -//[asio_rr_ctor - round_robin( std::shared_ptr< boost::asio::io_context > const& io_ctx) : - io_ctx_( io_ctx), - suspend_timer_( * io_ctx_) { - // We use add_service() very deliberately. This will throw - // service_already_exists if you pass the same io_context instance to - // more than one round_robin instance. - boost::asio::add_service( * io_ctx_, new service( * io_ctx_) ); - boost::asio::post( * io_ctx_, [this]() mutable { -//] -//[asio_rr_service_lambda - while ( ! io_ctx_->stopped() ) { - if ( has_ready_fibers() ) { - // run all pending handlers in round_robin - while ( io_ctx_->poll() ); - // block this fiber till all pending (ready) fibers are processed - // == round_robin::suspend_until() has been called - std::unique_lock< boost::fibers::mutex > lk( mtx_); - cnd_.wait( lk); - } else { - // run one handler inside io_context - // if no handler available, block this thread - if ( ! io_ctx_->run_one() ) { - break; - } - } - } -//] - }); - } - - void awakened( context * ctx) noexcept { - BOOST_ASSERT( nullptr != ctx); - BOOST_ASSERT( ! ctx->ready_is_linked() ); - ctx->ready_link( rqueue_); /*< fiber, enqueue on ready queue >*/ - if ( ! ctx->is_context( boost::fibers::type::dispatcher_context) ) { - ++counter_; - } - } - - context * pick_next() noexcept { - context * ctx( nullptr); - if ( ! rqueue_.empty() ) { /*< - pop an item from the ready queue - >*/ - ctx = & rqueue_.front(); - rqueue_.pop_front(); - BOOST_ASSERT( nullptr != ctx); - BOOST_ASSERT( context::active() != ctx); - if ( ! ctx->is_context( boost::fibers::type::dispatcher_context) ) { - --counter_; - } - } - return ctx; - } - - bool has_ready_fibers() const noexcept { - return 0 < counter_; - } - -//[asio_rr_suspend_until - void suspend_until( std::chrono::steady_clock::time_point const& abs_time) noexcept { - // Set a timer so at least one handler will eventually fire, causing - // run_one() to eventually return. - if ( (std::chrono::steady_clock::time_point::max)() != abs_time) { - // Each expires_at(time_point) call cancels any previous pending - // call. We could inadvertently spin like this: - // dispatcher calls suspend_until() with earliest wake time - // suspend_until() sets suspend_timer_ - // lambda loop calls run_one() - // some other asio handler runs before timer expires - // run_one() returns to lambda loop - // lambda loop yields to dispatcher - // dispatcher finds no ready fibers - // dispatcher calls suspend_until() with SAME wake time - // suspend_until() sets suspend_timer_ to same time, canceling - // previous async_wait() - // lambda loop calls run_one() - // asio calls suspend_timer_ handler with operation_aborted - // run_one() returns to lambda loop... etc. etc. - // So only actually set the timer when we're passed a DIFFERENT - // abs_time value. - suspend_timer_.expires_at( abs_time); - suspend_timer_.async_wait([](boost::system::error_code const&){ - this_fiber::yield(); - }); - } - cnd_.notify_one(); - } -//] - -//[asio_rr_notify - void notify() noexcept { - // Something has happened that should wake one or more fibers BEFORE - // suspend_timer_ expires. Reset the timer to cause it to fire - // immediately, causing the run_one() call to return. In theory we - // could use cancel() because we don't care whether suspend_timer_'s - // handler is called with operation_aborted or success. However -- - // cancel() doesn't change the expiration time, and we use - // suspend_timer_'s expiration time to decide whether it's already - // set. If suspend_until() set some specific wake time, then notify() - // canceled it, then suspend_until() was called again with the same - // wake time, it would match suspend_timer_'s expiration time and we'd - // refrain from setting the timer. So instead of simply calling - // cancel(), reset the timer, which cancels the pending sleep AND sets - // a new expiration time. This will cause us to spin the loop twice -- - // once for the operation_aborted handler, once for timer expiration - // -- but that shouldn't be a big problem. - suspend_timer_.async_wait([](boost::system::error_code const&){ - this_fiber::yield(); - }); - suspend_timer_.expires_at( std::chrono::steady_clock::now() ); - } -//] -}; - -boost::asio::io_context::id round_robin::service::id; - -}}} - -#ifdef BOOST_HAS_ABI_HEADERS -# include BOOST_ABI_SUFFIX -#endif - -#endif // BOOST_FIBERS_ASIO_ROUND_ROBIN_H diff --git a/examples/asio/yield.hpp b/examples/asio/yield.hpp deleted file mode 100644 index d76467f9..00000000 --- a/examples/asio/yield.hpp +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright 2003-2013 Christopher M. Kohlhoff -// Copyright Oliver Kowalke, Nat Goodspeed 2015. -// 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) - - -#ifndef BOOST_FIBERS_ASIO_YIELD_HPP -#define BOOST_FIBERS_ASIO_YIELD_HPP - -#include - -#ifdef BOOST_HAS_ABI_HEADERS -# include BOOST_ABI_PREFIX -#endif - -namespace boost { -namespace fibers { -namespace asio { - -//[fibers_asio_yield_t -class yield_t { -public: - yield_t() = default; - - /** - * @code - * static yield_t yield; - * boost::system::error_code myec; - * func(yield[myec]); - * @endcode - * @c yield[myec] returns an instance of @c yield_t whose @c ec_ points - * to @c myec. The expression @c yield[myec] "binds" @c myec to that - * (anonymous) @c yield_t instance, instructing @c func() to store any - * @c error_code it might produce into @c myec rather than throwing @c - * boost::system::system_error. - */ - yield_t operator[]( boost::system::error_code & ec) const { - yield_t tmp; - tmp.ec_ = & ec; - return tmp; - } - -//private: - // ptr to bound error_code instance if any - boost::system::error_code * ec_{ nullptr }; -}; -//] - -//[fibers_asio_yield -// canonical instance -thread_local yield_t yield{}; -//] - -}}} - -#ifdef BOOST_HAS_ABI_HEADERS -# include BOOST_ABI_SUFFIX -#endif - -#include "detail/yield.hpp" - -#endif // BOOST_FIBERS_ASIO_YIELD_HPP From 952434c8d43fd0ec2eef292f4e9de37901988b9b Mon Sep 17 00:00:00 2001 From: James Hunsaker <18537138+jhunsaker@users.noreply.github.com> Date: Wed, 8 Apr 2026 00:51:25 -0400 Subject: [PATCH 12/15] Remove RTM (Intel TSX) spinlock support Unused by the top-level project. Removes rtm.hpp, spinlock_rtm.hpp, and strips BOOST_USE_TSX branches from spinlock.hpp. Co-Authored-By: Claude Opus 4.6 --- include/boost/fiber/detail/rtm.hpp | 94 --------------- include/boost/fiber/detail/spinlock.hpp | 19 --- include/boost/fiber/detail/spinlock_rtm.hpp | 127 -------------------- 3 files changed, 240 deletions(-) delete mode 100644 include/boost/fiber/detail/rtm.hpp delete mode 100644 include/boost/fiber/detail/spinlock_rtm.hpp diff --git a/include/boost/fiber/detail/rtm.hpp b/include/boost/fiber/detail/rtm.hpp deleted file mode 100644 index 5188b0d2..00000000 --- a/include/boost/fiber/detail/rtm.hpp +++ /dev/null @@ -1,94 +0,0 @@ - -// Copyright Oliver Kowalke 2017. -// 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) -// - -#ifndef BOOST_FIBER_DETAIL_RTM_H -#define BOOST_FIBER_DETAIL_RTM_H - -#include - -#include -#include - -#include - -#ifdef BOOST_HAS_ABI_HEADERS -# include BOOST_ABI_PREFIX -#endif - -namespace boost { -namespace fibers { -namespace detail { - -struct rtm_status { - enum { - none = 0, - explicit_abort = 1 << 0, - may_retry = 1 << 1, - memory_conflict = 1 << 2, - buffer_overflow = 1 << 3, - debug_hit = 1 << 4, - nested_abort = 1 << 5 - }; - - static constexpr std::uint32_t success = ~std::uint32_t{ 0 }; -}; - -static BOOST_FORCEINLINE -std::uint32_t rtm_begin() noexcept { - std::uint32_t result = rtm_status::success; - __asm__ __volatile__ - ( - ".byte 0xc7,0xf8 ; .long 0" - : "+a" (result) - : - : "memory" - ); - return result; -} - -static BOOST_FORCEINLINE -void rtm_end() noexcept { - __asm__ __volatile__ - ( - ".byte 0x0f,0x01,0xd5" - : - : - : "memory" - ); -} - -static BOOST_FORCEINLINE -void rtm_abort_lock_not_free() noexcept { - __asm__ __volatile__ - ( - ".byte 0xc6,0xf8,0xff" - : - : - : "memory" - ); -} - -static BOOST_FORCEINLINE -bool rtm_test() noexcept { - bool result; - __asm__ __volatile__ - ( - ".byte 0x0f,0x01,0xd6; setz %0" - : "=q" (result) - : - : "memory" - ); - return result; -} - -}}} - -#ifdef BOOST_HAS_ABI_HEADERS -# include BOOST_ABI_SUFFIX -#endif - -#endif // BOOST_FIBER_DETAIL_RTM_H diff --git a/include/boost/fiber/detail/spinlock.hpp b/include/boost/fiber/detail/spinlock.hpp index 59d2a5cd..e4600a7f 100644 --- a/include/boost/fiber/detail/spinlock.hpp +++ b/include/boost/fiber/detail/spinlock.hpp @@ -19,9 +19,6 @@ # include # include # endif -# if defined(BOOST_USE_TSX) -# include -# endif #endif #ifdef BOOST_HAS_ABI_HEADERS @@ -48,29 +45,13 @@ struct spinlock_lock { # if defined(BOOST_FIBERS_SPINLOCK_STD_MUTEX) using spinlock = std::mutex; # elif defined(BOOST_FIBERS_SPINLOCK_TTAS_FUTEX) -# if defined(BOOST_USE_TSX) -using spinlock = spinlock_rtm< spinlock_ttas_futex >; -# else using spinlock = spinlock_ttas_futex; -# endif # elif defined(BOOST_FIBERS_SPINLOCK_TTAS_ADAPTIVE_FUTEX) -# if defined(BOOST_USE_TSX) -using spinlock = spinlock_rtm< spinlock_ttas_adaptive_futex >; -# else using spinlock = spinlock_ttas_adaptive_futex; -# endif # elif defined(BOOST_FIBERS_SPINLOCK_TTAS_ADAPTIVE) -# if defined(BOOST_USE_TSX) -using spinlock = spinlock_rtm< spinlock_ttas_adaptive >; -# else using spinlock = spinlock_ttas_adaptive; -# endif # else -# if defined(BOOST_USE_TSX) -using spinlock = spinlock_rtm< spinlock_ttas >; -# else using spinlock = spinlock_ttas; -# endif # endif using spinlock_lock = std::unique_lock< spinlock >; #endif diff --git a/include/boost/fiber/detail/spinlock_rtm.hpp b/include/boost/fiber/detail/spinlock_rtm.hpp deleted file mode 100644 index a38f4e7b..00000000 --- a/include/boost/fiber/detail/spinlock_rtm.hpp +++ /dev/null @@ -1,127 +0,0 @@ - -// Copyright Oliver Kowalke 2017. -// 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) - -#ifndef BOOST_FIBERS_SPINLOCK_RTM_H -#define BOOST_FIBERS_SPINLOCK_RTM_H - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -namespace boost { -namespace fibers { -namespace detail { - -template< typename FBSplk > -class spinlock_rtm { -private: - FBSplk splk_{}; - -public: - spinlock_rtm() = default; - - spinlock_rtm( spinlock_rtm const&) = delete; - spinlock_rtm & operator=( spinlock_rtm const&) = delete; - - void lock() noexcept { - static thread_local std::minstd_rand generator{ std::random_device{}() }; - std::size_t collisions = 0 ; - for ( std::size_t retries = 0; retries < BOOST_FIBERS_RETRY_THRESHOLD; ++retries) { - std::uint32_t status; - if ( rtm_status::success == ( status = rtm_begin() ) ) { - // add lock to read-set - if ( spinlock_status::unlocked == splk_.state_.load( std::memory_order_relaxed) ) { - // lock is free, enter critical section - return; - } - // lock was acquired by another thread - // explicit abort of transaction with abort argument 'lock not free' - rtm_abort_lock_not_free(); - } - // transaction aborted - if ( rtm_status::none != (status & rtm_status::may_retry) || - rtm_status::none != (status & rtm_status::memory_conflict) ) { - // another logical processor conflicted with a memory address that was - // part or the read-/write-set - if ( BOOST_FIBERS_CONTENTION_WINDOW_THRESHOLD > collisions) { - std::uniform_int_distribution< std::size_t > distribution{ - 0, static_cast< std::size_t >( 1) << (std::min)(collisions, static_cast< std::size_t >( BOOST_FIBERS_CONTENTION_WINDOW_THRESHOLD)) }; - const std::size_t z = distribution( generator); - ++collisions; - for ( std::size_t i = 0; i < z; ++i) { - cpu_relax(); - } - } else { - std::this_thread::yield(); - } - } else if ( rtm_status::none != (status & rtm_status::explicit_abort) && - rtm_status::none == (status & rtm_status::nested_abort) ) { - // another logical processor has acquired the lock and - // abort was not caused by a nested transaction - // wait till lock becomes free again - std::size_t count = 0; - while ( spinlock_status::locked == splk_.state_.load( std::memory_order_relaxed) ) { - if ( BOOST_FIBERS_SPIN_BEFORE_SLEEP0 > count) { - ++count; - cpu_relax(); - } else if ( BOOST_FIBERS_SPIN_BEFORE_YIELD > count) { - ++count; - static constexpr std::chrono::microseconds us0{ 0 }; - std::this_thread::sleep_for( us0); -#if 0 - using namespace std::chrono_literals; - std::this_thread::sleep_for( 0ms); -#endif - } else { - std::this_thread::yield(); - } - } - } else { - // transaction aborted due: - // - internal buffer to track transactional state overflowed - // - debug exception or breakpoint exception was hit - // - abort during execution of nested transactions (max nesting limit exceeded) - // -> use fallback path - break; - } - } - splk_.lock(); - } - - bool try_lock() noexcept { - if ( rtm_status::success != rtm_begin() ) { - return false; - } - - // add lock to read-set - if ( spinlock_status::unlocked != splk_.state_.load( std::memory_order_relaxed) ) { - // lock was acquired by another thread - // explicit abort of transaction with abort argument 'lock not free' - rtm_abort_lock_not_free(); - } - return true; - } - - void unlock() noexcept { - if ( spinlock_status::unlocked == splk_.state_.load( std::memory_order_acquire) ) { - rtm_end(); - } else { - splk_.unlock(); - } - } -}; - -}}} - -#endif // BOOST_FIBERS_SPINLOCK_RTM_H From 24ef24e0dd0ee5f0cd7953bc770406edf1bf8604 Mon Sep 17 00:00:00 2001 From: James Hunsaker <18537138+jhunsaker@users.noreply.github.com> Date: Wed, 8 Apr 2026 00:53:10 -0400 Subject: [PATCH 13/15] Remove unused thread_barrier Co-Authored-By: Claude Opus 4.6 --- include/boost/fiber/detail/thread_barrier.hpp | 62 ------------------- 1 file changed, 62 deletions(-) delete mode 100644 include/boost/fiber/detail/thread_barrier.hpp diff --git a/include/boost/fiber/detail/thread_barrier.hpp b/include/boost/fiber/detail/thread_barrier.hpp deleted file mode 100644 index 207191c3..00000000 --- a/include/boost/fiber/detail/thread_barrier.hpp +++ /dev/null @@ -1,62 +0,0 @@ - -// 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) - -#ifndef BOOST_FIBER_DETAIL_THREAD_BARRIER_H -#define BOOST_FIBER_DETAIL_THREAD_BARRIER_H - -#include -#include -#include - -#include -#include - -#include - -#ifdef BOOST_HAS_ABI_HEADERS -# include BOOST_ABI_PREFIX -#endif - -namespace boost { -namespace fibers { -namespace detail { - -class thread_barrier { -private: - std::size_t initial_; - std::size_t current_; - bool cycle_{ true }; - std::mutex mtx_{}; - std::condition_variable cond_{}; - -public: - explicit thread_barrier( std::size_t initial) : - initial_{ initial }, - current_{ initial_ } { - BOOST_ASSERT ( 0 != initial); - } - - thread_barrier( thread_barrier const&) = delete; - thread_barrier & operator=( thread_barrier const&) = delete; - - bool wait() { - std::unique_lock< std::mutex > lk( mtx_); - const bool cycle = cycle_; - if ( 0 == --current_) { - cycle_ = ! cycle_; - current_ = initial_; - lk.unlock(); // no pessimization - cond_.notify_all(); - return true; - } - cond_.wait( lk, [&](){ return cycle != cycle_; }); - return false; - } -}; - -}}} - -#endif // BOOST_FIBER_DETAIL_THREAD_BARRIER_H From a7c027397060ad5cb2f1b2b8a60bbc4f4d9eff6b Mon Sep 17 00:00:00 2001 From: James Hunsaker <18537138+jhunsaker@users.noreply.github.com> Date: Wed, 13 May 2026 16:50:34 -0400 Subject: [PATCH 14/15] Remove sleep/timed-wait support Removes the sleep queue from the scheduler (sleep2ready_, wait_until, sleep_hook, sleep_waker_, tp_), and all timed-wait variants from condition_variable, buffered_channel, future, and operations.hpp. Co-Authored-By: Claude Sonnet 4.6 --- include/boost/fiber/algo/algorithm.hpp | 3 +- include/boost/fiber/algo/round_robin.hpp | 3 +- include/boost/fiber/buffered_channel.hpp | 93 --------------- include/boost/fiber/condition_variable.hpp | 104 ----------------- include/boost/fiber/context.hpp | 30 ----- .../fiber/future/detail/shared_state.hpp | 31 ----- include/boost/fiber/future/future.hpp | 29 ----- include/boost/fiber/operations.hpp | 18 +-- include/boost/fiber/scheduler.hpp | 28 ----- include/boost/fiber/waker.hpp | 3 - src/algo/round_robin.cpp | 14 +-- src/context.cpp | 29 ----- src/scheduler.cpp | 107 +----------------- src/waker.cpp | 20 ---- 14 files changed, 8 insertions(+), 504 deletions(-) diff --git a/include/boost/fiber/algo/algorithm.hpp b/include/boost/fiber/algo/algorithm.hpp index cedefdb2..6c399573 100644 --- a/include/boost/fiber/algo/algorithm.hpp +++ b/include/boost/fiber/algo/algorithm.hpp @@ -7,7 +7,6 @@ #define BOOST_FIBERS_ALGO_ALGORITHM_H #include -#include #include #include @@ -43,7 +42,7 @@ class BOOST_FIBERS_DECL algorithm { virtual bool has_ready_fibers() const noexcept = 0; - virtual void suspend_until( std::chrono::steady_clock::time_point const&) noexcept = 0; + virtual void suspend() noexcept = 0; virtual void notify() noexcept = 0; diff --git a/include/boost/fiber/algo/round_robin.hpp b/include/boost/fiber/algo/round_robin.hpp index 43044ad4..f4ee1428 100644 --- a/include/boost/fiber/algo/round_robin.hpp +++ b/include/boost/fiber/algo/round_robin.hpp @@ -7,7 +7,6 @@ #define BOOST_FIBERS_ALGO_ROUND_ROBIN_H #include -#include #include #include @@ -51,7 +50,7 @@ class BOOST_FIBERS_DECL round_robin : public algorithm { bool has_ready_fibers() const noexcept override; - void suspend_until( std::chrono::steady_clock::time_point const&) noexcept override; + void suspend() noexcept override; void notify() noexcept override; }; diff --git a/include/boost/fiber/buffered_channel.hpp b/include/boost/fiber/buffered_channel.hpp index 7ff7d5b7..1ac58df2 100644 --- a/include/boost/fiber/buffered_channel.hpp +++ b/include/boost/fiber/buffered_channel.hpp @@ -9,7 +9,6 @@ #define BOOST_FIBERS_BUFFERED_CHANNEL_H #include -#include #include #include #include @@ -21,7 +20,6 @@ #include #include #include -#include #include #include @@ -158,67 +156,6 @@ class buffered_channel { } } - template< typename Rep, typename Period > - channel_op_status push_wait_for( value_type const& value, - std::chrono::duration< Rep, Period > const& timeout_duration) { - return push_wait_until( value, - std::chrono::steady_clock::now() + timeout_duration); - } - - template< typename Rep, typename Period > - channel_op_status push_wait_for( value_type && value, - std::chrono::duration< Rep, Period > const& timeout_duration) { - return push_wait_until( std::forward< value_type >( value), - std::chrono::steady_clock::now() + timeout_duration); - } - - template< typename Clock, typename Duration > - channel_op_status push_wait_until( value_type const& value, - std::chrono::time_point< Clock, Duration > const& timeout_time_) { - context * active_ctx = context::active(); - std::chrono::steady_clock::time_point timeout_time = detail::convert( timeout_time_); - for (;;) { - detail::spinlock_lock lk{ splk_ }; - if ( BOOST_UNLIKELY( is_closed_() ) ) { - return channel_op_status::closed; - } - if ( is_full_() ) { - if ( ! waiting_producers_.suspend_and_wait_until( lk, active_ctx, timeout_time)) { - return channel_op_status::timeout; - } - } else { - slots_[pidx_] = value; - pidx_ = (pidx_ + 1) % capacity_; - waiting_consumers_.notify_one(); - return channel_op_status::success; - } - } - } - - template< typename Clock, typename Duration > - channel_op_status push_wait_until( value_type && value, - std::chrono::time_point< Clock, Duration > const& timeout_time_) { - context * active_ctx = context::active(); - std::chrono::steady_clock::time_point timeout_time = detail::convert( timeout_time_); - for (;;) { - detail::spinlock_lock lk{ splk_ }; - if ( BOOST_UNLIKELY( is_closed_() ) ) { - return channel_op_status::closed; - } - if ( is_full_() ) { - if ( ! waiting_producers_.suspend_and_wait_until( lk, active_ctx, timeout_time)) { - return channel_op_status::timeout; - } - } else { - slots_[pidx_] = std::move( value); - pidx_ = (pidx_ + 1) % capacity_; - // notify one waiting consumer - waiting_consumers_.notify_one(); - return channel_op_status::success; - } - } - } - channel_op_status try_pop( value_type & value) { detail::spinlock_lock lk{ splk_ }; if ( is_empty_() ) { @@ -270,36 +207,6 @@ class buffered_channel { } } - template< typename Rep, typename Period > - channel_op_status pop_wait_for( value_type & value, - std::chrono::duration< Rep, Period > const& timeout_duration) { - return pop_wait_until( value, - std::chrono::steady_clock::now() + timeout_duration); - } - - template< typename Clock, typename Duration > - channel_op_status pop_wait_until( value_type & value, - std::chrono::time_point< Clock, Duration > const& timeout_time_) { - context * active_ctx = context::active(); - std::chrono::steady_clock::time_point timeout_time = detail::convert( timeout_time_); - for (;;) { - detail::spinlock_lock lk{ splk_ }; - if ( is_empty_() ) { - if ( BOOST_UNLIKELY( is_closed_() ) ) { - return channel_op_status::closed; - } - if ( ! waiting_consumers_.suspend_and_wait_until( lk, active_ctx, timeout_time)) { - return channel_op_status::timeout; - } - } else { - value = std::move( slots_[cidx_]); - cidx_ = (cidx_ + 1) % capacity_; - waiting_producers_.notify_one(); - return channel_op_status::success; - } - } - } - class iterator { private: typedef typename std::aligned_storage< sizeof( value_type), alignof( value_type) >::type storage_type; diff --git a/include/boost/fiber/condition_variable.hpp b/include/boost/fiber/condition_variable.hpp index 2bd8157e..478db80b 100644 --- a/include/boost/fiber/condition_variable.hpp +++ b/include/boost/fiber/condition_variable.hpp @@ -9,7 +9,6 @@ #include #include -#include #include #include @@ -19,7 +18,6 @@ #include #include -#include #include #include #include @@ -89,56 +87,6 @@ class BOOST_FIBERS_DECL condition_variable_any { wait( lt); } } - - template< typename LockType, typename Clock, typename Duration > - cv_status wait_until( LockType & lt, std::chrono::time_point< Clock, Duration > const& timeout_time_) { - context * active_ctx = context::active(); - cv_status status = cv_status::no_timeout; - std::chrono::steady_clock::time_point timeout_time = detail::convert( timeout_time_); - // atomically call lt.unlock() and block on *this - // store this fiber in waiting-queue - detail::spinlock_lock lk{ wait_queue_splk_ }; - // unlock external lt - lt.unlock(); - if ( ! wait_queue_.suspend_and_wait_until( lk, active_ctx, timeout_time)) { - status = cv_status::timeout; - } - // relock external again before returning - try { - lt.lock(); -#if defined(BOOST_CONTEXT_HAS_CXXABI_H) - } catch ( abi::__forced_unwind const&) { - throw; -#endif - } catch (...) { - std::terminate(); - } - return status; - } - - template< typename LockType, typename Clock, typename Duration, typename Pred > - bool wait_until( LockType & lt, - std::chrono::time_point< Clock, Duration > const& timeout_time, Pred pred) { - while ( ! pred() ) { - if ( cv_status::timeout == wait_until( lt, timeout_time) ) { - return pred(); - } - } - return true; - } - - template< typename LockType, typename Rep, typename Period > - cv_status wait_for( LockType & lt, std::chrono::duration< Rep, Period > const& timeout_duration) { - return wait_until( lt, - std::chrono::steady_clock::now() + timeout_duration); - } - - template< typename LockType, typename Rep, typename Period, typename Pred > - bool wait_for( LockType & lt, std::chrono::duration< Rep, Period > const& timeout_duration, Pred pred) { - return wait_until( lt, - std::chrono::steady_clock::now() + timeout_duration, - pred); - } }; class BOOST_FIBERS_DECL condition_variable { @@ -179,58 +127,6 @@ class BOOST_FIBERS_DECL condition_variable { BOOST_ASSERT( lt.owns_lock() ); BOOST_ASSERT( context::active() == lt.mutex()->owner_); } - - template< typename Clock, typename Duration > - cv_status wait_until( std::unique_lock< mutex > & lt, - std::chrono::time_point< Clock, Duration > const& timeout_time) { - // pre-condition - BOOST_ASSERT( lt.owns_lock() ); - BOOST_ASSERT( context::active() == lt.mutex()->owner_); - cv_status result = cnd_.wait_until( lt, timeout_time); - // post-condition - BOOST_ASSERT( lt.owns_lock() ); - BOOST_ASSERT( context::active() == lt.mutex()->owner_); - return result; - } - - template< typename Clock, typename Duration, typename Pred > - bool wait_until( std::unique_lock< mutex > & lt, - std::chrono::time_point< Clock, Duration > const& timeout_time, Pred pred) { - // pre-condition - BOOST_ASSERT( lt.owns_lock() ); - BOOST_ASSERT( context::active() == lt.mutex()->owner_); - bool result = cnd_.wait_until( lt, timeout_time, pred); - // post-condition - BOOST_ASSERT( lt.owns_lock() ); - BOOST_ASSERT( context::active() == lt.mutex()->owner_); - return result; - } - - template< typename Rep, typename Period > - cv_status wait_for( std::unique_lock< mutex > & lt, - std::chrono::duration< Rep, Period > const& timeout_duration) { - // pre-condition - BOOST_ASSERT( lt.owns_lock() ); - BOOST_ASSERT( context::active() == lt.mutex()->owner_); - cv_status result = cnd_.wait_for( lt, timeout_duration); - // post-condition - BOOST_ASSERT( lt.owns_lock() ); - BOOST_ASSERT( context::active() == lt.mutex()->owner_); - return result; - } - - template< typename Rep, typename Period, typename Pred > - bool wait_for( std::unique_lock< mutex > & lt, - std::chrono::duration< Rep, Period > const& timeout_duration, Pred pred) { - // pre-condition - BOOST_ASSERT( lt.owns_lock() ); - BOOST_ASSERT( context::active() == lt.mutex()->owner_); - bool result = cnd_.wait_for( lt, timeout_duration, pred); - // post-condition - BOOST_ASSERT( lt.owns_lock() ); - BOOST_ASSERT( context::active() == lt.mutex()->owner_); - return result; - } }; }} diff --git a/include/boost/fiber/context.hpp b/include/boost/fiber/context.hpp index 62d1cb1b..c19859b6 100644 --- a/include/boost/fiber/context.hpp +++ b/include/boost/fiber/context.hpp @@ -8,7 +8,6 @@ #define BOOST_FIBERS_CONTEXT_H #include -#include #include #include #include @@ -29,7 +28,6 @@ #include #include #include -#include #include #include @@ -70,14 +68,6 @@ typedef intrusive::list_member_hook< > > ready_hook; -struct sleep_tag; -typedef intrusive::set_member_hook< - intrusive::tag< sleep_tag >, - intrusive::link_mode< - intrusive::auto_unlink - > -> sleep_hook; - struct worker_tag; typedef intrusive::list_member_hook< intrusive::tag< worker_tag >, @@ -129,20 +119,16 @@ class BOOST_FIBERS_DECL context { #endif private: scheduler * scheduler_{ nullptr }; - detail::sleep_hook sleep_hook_{}; - waker sleep_waker_{}; detail::ready_hook ready_hook_{}; detail::terminated_hook terminated_hook_{}; detail::worker_hook worker_hook_{}; fiber_properties * properties_{ nullptr }; boost::context::fiber c_{}; - std::chrono::steady_clock::time_point tp_; type type_; launch policy_; context( std::size_t initial_count, type t, launch policy) noexcept : use_count_{ initial_count }, - tp_{ (std::chrono::steady_clock::time_point::max)() }, type_{ t }, policy_{ policy } { } @@ -250,11 +236,6 @@ class BOOST_FIBERS_DECL context { void yield() noexcept; - bool wait_until( std::chrono::steady_clock::time_point const&) noexcept; - bool wait_until( std::chrono::steady_clock::time_point const&, - detail::spinlock_lock &, - waker &&) noexcept; - bool wake(const size_t) noexcept; waker create_waker() noexcept { @@ -284,8 +265,6 @@ class BOOST_FIBERS_DECL context { bool remote_ready_is_linked() const noexcept; - bool sleep_is_linked() const noexcept; - bool terminated_is_linked() const noexcept; template< typename List > @@ -309,13 +288,6 @@ class BOOST_FIBERS_DECL context { lst.push_back( * this); } - template< typename Set > - void sleep_link( Set & set) noexcept { - static_assert( std::is_same< typename Set::value_traits::hook_type,detail::sleep_hook >::value, "not a sleep-queue"); - BOOST_ASSERT( ! sleep_is_linked() ); - set.insert( * this); - } - template< typename List > void terminated_link( List & lst) noexcept { static_assert( std::is_same< typename List::value_traits::hook_type, detail::terminated_hook >::value, "not a terminated-queue"); @@ -327,8 +299,6 @@ class BOOST_FIBERS_DECL context { void ready_unlink() noexcept; - void sleep_unlink() noexcept; - void detach() noexcept; void attach( context *) noexcept; diff --git a/include/boost/fiber/future/detail/shared_state.hpp b/include/boost/fiber/future/detail/shared_state.hpp index 28e0e3cf..c2c98e65 100644 --- a/include/boost/fiber/future/detail/shared_state.hpp +++ b/include/boost/fiber/future/detail/shared_state.hpp @@ -9,7 +9,6 @@ #include #include -#include #include #include #include @@ -80,24 +79,6 @@ class shared_state_base { waiters_.wait( lk, [this](){ return ready_; }); } - template< typename Rep, typename Period > - future_status wait_for_( std::unique_lock< mutex > & lk, - std::chrono::duration< Rep, Period > const& timeout_duration) const { - BOOST_ASSERT( lk.owns_lock() ); - return waiters_.wait_for( lk, timeout_duration, [this](){ return ready_; }) - ? future_status::ready - : future_status::timeout; - } - - template< typename Clock, typename Duration > - future_status wait_until_( std::unique_lock< mutex > & lk, - std::chrono::time_point< Clock, Duration > const& timeout_time) const { - BOOST_ASSERT( lk.owns_lock() ); - return waiters_.wait_until( lk, timeout_time, [this](){ return ready_; }) - ? future_status::ready - : future_status::timeout; - } - virtual void deallocate_future() noexcept = 0; public: @@ -128,18 +109,6 @@ class shared_state_base { wait_( lk); } - template< typename Rep, typename Period > - future_status wait_for( std::chrono::duration< Rep, Period > const& timeout_duration) const { - std::unique_lock< mutex > lk{ mtx_ }; - return wait_for_( lk, timeout_duration); - } - - template< typename Clock, typename Duration > - future_status wait_until( std::chrono::time_point< Clock, Duration > const& timeout_time) const { - std::unique_lock< mutex > lk{ mtx_ }; - return wait_until_( lk, timeout_time); - } - friend inline void intrusive_ptr_add_ref( shared_state_base * p) noexcept { p->use_count_.fetch_add( 1, std::memory_order_relaxed); diff --git a/include/boost/fiber/future/future.hpp b/include/boost/fiber/future/future.hpp index bd518200..b5a72a97 100644 --- a/include/boost/fiber/future/future.hpp +++ b/include/boost/fiber/future/future.hpp @@ -8,7 +8,6 @@ #define BOOST_FIBERS_FUTURE_HPP #include -#include #include #include @@ -78,22 +77,6 @@ struct future_base { } state_->wait(); } - - template< typename Rep, typename Period > - future_status wait_for( std::chrono::duration< Rep, Period > const& timeout_duration) const { - if ( BOOST_UNLIKELY( ! valid() ) ) { - throw future_uninitialized{}; - } - return state_->wait_for( timeout_duration); - } - - template< typename Clock, typename Duration > - future_status wait_until( std::chrono::time_point< Clock, Duration > const& timeout_time) const { - if ( BOOST_UNLIKELY( ! valid() ) ) { - throw future_uninitialized{}; - } - return state_->wait_until( timeout_time); - } }; template< typename R > @@ -152,8 +135,6 @@ class future : private detail::future_base< R > { using base_type::valid; using base_type::get_exception_ptr; using base_type::wait; - using base_type::wait_for; - using base_type::wait_until; }; template< typename R > @@ -201,8 +182,6 @@ class future< R & > : private detail::future_base< R & > { using base_type::valid; using base_type::get_exception_ptr; using base_type::wait; - using base_type::wait_for; - using base_type::wait_until; }; template<> @@ -253,8 +232,6 @@ class future< void > : private detail::future_base< void > { using base_type::valid; using base_type::get_exception_ptr; using base_type::wait; - using base_type::wait_for; - using base_type::wait_until; }; @@ -313,8 +290,6 @@ class shared_future : private detail::future_base< R > { using base_type::valid; using base_type::get_exception_ptr; using base_type::wait; - using base_type::wait_for; - using base_type::wait_until; }; template< typename R > @@ -372,8 +347,6 @@ class shared_future< R & > : private detail::future_base< R & > { using base_type::valid; using base_type::get_exception_ptr; using base_type::wait; - using base_type::wait_for; - using base_type::wait_until; }; template<> @@ -438,8 +411,6 @@ class shared_future< void > : private detail::future_base< void > { using base_type::valid; using base_type::get_exception_ptr; using base_type::wait; - using base_type::wait_for; - using base_type::wait_until; }; diff --git a/include/boost/fiber/operations.hpp b/include/boost/fiber/operations.hpp index b03deeba..06e7a4cb 100644 --- a/include/boost/fiber/operations.hpp +++ b/include/boost/fiber/operations.hpp @@ -6,14 +6,11 @@ #ifndef BOOST_THIS_FIBER_OPERATIONS_H #define BOOST_THIS_FIBER_OPERATIONS_H -#include - -#include +#include #include #include #include -#include #include #include @@ -34,19 +31,6 @@ void yield() noexcept { fibers::context::active()->yield(); } -template< typename Clock, typename Duration > -void sleep_until( std::chrono::time_point< Clock, Duration > const& sleep_time_) { - std::chrono::steady_clock::time_point sleep_time = boost::fibers::detail::convert( sleep_time_); - fibers::context * active_ctx = fibers::context::active(); - active_ctx->wait_until( sleep_time); -} - -template< typename Rep, typename Period > -void sleep_for( std::chrono::duration< Rep, Period > const& timeout_duration) { - fibers::context * active_ctx = fibers::context::active(); - active_ctx->wait_until( std::chrono::steady_clock::now() + timeout_duration); -} - template< typename PROPS > PROPS & properties() { fibers::fiber_properties * props = fibers::context::active()->get_properties(); diff --git a/include/boost/fiber/scheduler.hpp b/include/boost/fiber/scheduler.hpp index 8a32fab2..3449b104 100644 --- a/include/boost/fiber/scheduler.hpp +++ b/include/boost/fiber/scheduler.hpp @@ -6,7 +6,6 @@ #ifndef BOOST_FIBERS_FIBER_MANAGER_H #define BOOST_FIBERS_FIBER_MANAGER_H -#include #include #include #include @@ -16,7 +15,6 @@ #include #include #include -#include #include #include @@ -39,12 +37,6 @@ namespace fibers { class BOOST_FIBERS_DECL scheduler { public: - struct timepoint_less { - bool operator()( context const& l, context const& r) const noexcept { - return l.tp_ < r.tp_; - } - }; - typedef intrusive::list< context, intrusive::member_hook< @@ -52,13 +44,6 @@ class BOOST_FIBERS_DECL scheduler { intrusive::constant_time_size< false > > ready_queue_type; private: - typedef intrusive::multiset< - context, - intrusive::member_hook< - context, detail::sleep_hook, & context::sleep_hook_ >, - intrusive::constant_time_size< false >, - intrusive::compare< timepoint_less > - > sleep_queue_type; typedef intrusive::list< context, intrusive::member_hook< @@ -87,9 +72,6 @@ class BOOST_FIBERS_DECL scheduler { remote_ready_queue_type remote_ready_queue_{}; #endif algo::algorithm::ptr_t algo_; - // sleep-queue contains context' which have been called - // scheduler::wait_until() - sleep_queue_type sleep_queue_{}; // worker-queue contains all context' managed by this scheduler // except main-context and dispatcher-context // unlink happens on destruction of a context @@ -106,8 +88,6 @@ class BOOST_FIBERS_DECL scheduler { void remote_ready2ready_() noexcept; #endif - void sleep2ready_() noexcept; - public: scheduler() noexcept; @@ -128,14 +108,6 @@ class BOOST_FIBERS_DECL scheduler { void yield( context *) noexcept; - bool wait_until( context *, - std::chrono::steady_clock::time_point const&) noexcept; - - bool wait_until( context *, - std::chrono::steady_clock::time_point const&, - detail::spinlock_lock &, - waker &&) noexcept; - void suspend() noexcept; void suspend( detail::spinlock_lock &) noexcept; diff --git a/include/boost/fiber/waker.hpp b/include/boost/fiber/waker.hpp index 7ee8459d..baf6a13d 100644 --- a/include/boost/fiber/waker.hpp +++ b/include/boost/fiber/waker.hpp @@ -74,9 +74,6 @@ class BOOST_FIBERS_DECL wait_queue { public: void suspend_and_wait( detail::spinlock_lock &, context *); - bool suspend_and_wait_until( detail::spinlock_lock &, - context *, - std::chrono::steady_clock::time_point const&); void notify_one(); void notify_all(); diff --git a/src/algo/round_robin.cpp b/src/algo/round_robin.cpp index 5ff1af2b..28c72860 100644 --- a/src/algo/round_robin.cpp +++ b/src/algo/round_robin.cpp @@ -45,16 +45,10 @@ round_robin::has_ready_fibers() const noexcept { } void -round_robin::suspend_until( std::chrono::steady_clock::time_point const& time_point) noexcept { - if ( (std::chrono::steady_clock::time_point::max)() == time_point) { - std::unique_lock< std::mutex > lk{ mtx_ }; - cnd_.wait( lk, [&](){ return flag_; }); - flag_ = false; - } else { - std::unique_lock< std::mutex > lk{ mtx_ }; - cnd_.wait_until( lk, time_point, [&](){ return flag_; }); - flag_ = false; - } +round_robin::suspend() noexcept { + std::unique_lock< std::mutex > lk{ mtx_ }; + cnd_.wait( lk, [&](){ return flag_; }); + flag_ = false; } void diff --git a/src/context.cpp b/src/context.cpp index 4254eb6c..2e7611dc 100644 --- a/src/context.cpp +++ b/src/context.cpp @@ -119,7 +119,6 @@ context::~context() { std::unique_lock< detail::spinlock > lk{ splk_ }; BOOST_ASSERT( ! ready_is_linked() ); BOOST_ASSERT( ! remote_ready_is_linked() ); - BOOST_ASSERT( ! sleep_is_linked() ); if ( is_context( type::dispatcher_context) ) { BOOST_ASSERT( nullptr == active() ); } @@ -232,23 +231,6 @@ context::terminate() noexcept { return get_scheduler()->terminate( lk, this); } -bool -context::wait_until( std::chrono::steady_clock::time_point const& tp) noexcept { - BOOST_ASSERT( nullptr != get_scheduler() ); - BOOST_ASSERT( this == active() ); - return get_scheduler()->wait_until( this, tp); -} - -bool -context::wait_until( std::chrono::steady_clock::time_point const& tp, - detail::spinlock_lock & lk, - waker && w) noexcept { - BOOST_ASSERT( nullptr != get_scheduler() ); - BOOST_ASSERT( this == active() ); - return get_scheduler()->wait_until( this, tp, lk, std::move(w)); -} - - bool context::wake(const size_t epoch) noexcept { size_t expected = epoch; @@ -313,11 +295,6 @@ context::remote_ready_is_linked() const noexcept { return remote_ready_hook_.is_linked(); } -bool -context::sleep_is_linked() const noexcept { - return sleep_hook_.is_linked(); -} - bool context::terminated_is_linked() const noexcept { return terminated_hook_.is_linked(); @@ -335,12 +312,6 @@ context::ready_unlink() noexcept { ready_hook_.unlink(); } -void -context::sleep_unlink() noexcept { - BOOST_ASSERT( sleep_is_linked() ); - sleep_hook_.unlink(); -} - void context::detach() noexcept { BOOST_ASSERT( context::active() != this); diff --git a/src/scheduler.cpp b/src/scheduler.cpp index 090ec69d..b85c24d7 100644 --- a/src/scheduler.cpp +++ b/src/scheduler.cpp @@ -6,7 +6,6 @@ #include "boost/fiber/scheduler.hpp" -#include #include #include @@ -36,7 +35,6 @@ scheduler::release_terminated_() noexcept { #if ! defined(BOOST_FIBERS_NO_ATOMICS) BOOST_ASSERT( ! ctx->remote_ready_is_linked() ); #endif - BOOST_ASSERT( ! ctx->sleep_is_linked() ); BOOST_ASSERT( ctx->wait_queue_.empty() ); BOOST_ASSERT( ctx->terminated_); // if last reference, e.g. fiber::join() or fiber::detach() @@ -63,37 +61,6 @@ scheduler::remote_ready2ready_() noexcept { } #endif -void -scheduler::sleep2ready_() noexcept { - // move context which the deadline has reached - // to ready-queue - // sleep-queue is sorted (ascending) - std::chrono::steady_clock::time_point now = std::chrono::steady_clock::now(); - sleep_queue_type::iterator e = sleep_queue_.end(); - for ( sleep_queue_type::iterator i = sleep_queue_.begin(); i != e;) { - context * ctx = & ( * i); - // dispatcher context must never be pushed to sleep-queue - BOOST_ASSERT( ! ctx->is_context( type::dispatcher_context) ); - BOOST_ASSERT( main_ctx_ == ctx || ctx->worker_is_linked() ); - BOOST_ASSERT( ! ctx->ready_is_linked() ); - // remote_ready_hook_ can be linked in that point in case when the ctx - // has been signaled concurrently when sleep2ready_ is called. In that - // case sleep_waker_.wake() is just no-op, because sleep_waker_ is - // outdated - BOOST_ASSERT( ! ctx->terminated_is_linked() ); - // set fiber to state_ready if deadline was reached - if ( ctx->tp_ <= now) { - // remove context from sleep-queue - i = sleep_queue_.erase( i); - // reset sleep-tp - ctx->tp_ = (std::chrono::steady_clock::time_point::max)(); - ctx->sleep_waker_.wake(); - } else { - break; // first context with now < deadline - } - } -} - scheduler::scheduler() noexcept : algo_{ new algo::round_robin() } { } @@ -110,7 +77,6 @@ scheduler::~scheduler() { // no context' in worker-queue BOOST_ASSERT( worker_queue_.empty() ); BOOST_ASSERT( terminated_queue_.empty() ); - BOOST_ASSERT( sleep_queue_.empty() ); // set active context to nullptr context::reset_active(); // deallocate dispatcher-context @@ -137,9 +103,6 @@ scheduler::dispatch() noexcept { // get context' from remote ready-queue remote_ready2ready_(); #endif - // get sleeping context' - // must be called after remote_ready2ready_() - sleep2ready_(); // get next ready context context * ctx = algo_->pick_next(); if ( nullptr != ctx) { @@ -148,7 +111,6 @@ scheduler::dispatch() noexcept { #if ! defined(BOOST_FIBERS_NO_ATOMICS) BOOST_ASSERT( ! ctx->remote_ready_is_linked() ); #endif - BOOST_ASSERT( ! ctx->sleep_is_linked() ); BOOST_ASSERT( ! ctx->terminated_is_linked() ); // push dispatcher-context to ready-queue // so that ready-queue never becomes empty @@ -156,16 +118,7 @@ scheduler::dispatch() noexcept { BOOST_ASSERT( context::active() == dispatcher_ctx_.get() ); } else { // no ready context, wait till signaled - // set deadline to highest value - std::chrono::steady_clock::time_point suspend_time = - (std::chrono::steady_clock::time_point::max)(); - // get lowest deadline from sleep-queue - sleep_queue_type::iterator i = sleep_queue_.begin(); - if ( sleep_queue_.end() != i) { - suspend_time = i->tp_; - } - // no ready context, wait till signaled - algo_->suspend_until( suspend_time); + algo_->suspend(); } } // release termianted context' @@ -182,12 +135,6 @@ scheduler::schedule( context * ctx) noexcept { BOOST_ASSERT( ! ctx->remote_ready_is_linked() ); #endif BOOST_ASSERT( ! ctx->terminated_is_linked() ); - // remove context ctx from sleep-queue - // (might happen if blocked in timed_mutex::try_lock_until()) - if ( ctx->sleep_is_linked() ) { - // unlink it from sleep-queue - ctx->sleep_unlink(); - } // push new context to ready-queue algo_->awakened( ctx); } @@ -226,7 +173,6 @@ scheduler::terminate( detail::spinlock_lock & lk, context * ctx) noexcept { #if ! defined(BOOST_FIBERS_NO_ATOMICS) BOOST_ASSERT( ! ctx->remote_ready_is_linked() ); #endif - BOOST_ASSERT( ! ctx->sleep_is_linked() ); BOOST_ASSERT( ! ctx->terminated_is_linked() ); BOOST_ASSERT( ctx->wait_queue_.empty() ); // store the terminated fiber in the terminated-queue @@ -249,59 +195,11 @@ scheduler::yield( context * ctx) noexcept { #if ! defined(BOOST_FIBERS_NO_ATOMICS) BOOST_ASSERT( ! ctx->remote_ready_is_linked() ); #endif - BOOST_ASSERT( ! ctx->sleep_is_linked() ); BOOST_ASSERT( ! ctx->terminated_is_linked() ); // resume another fiber algo_->pick_next()->resume( ctx); } -bool -scheduler::wait_until( context * ctx, - std::chrono::steady_clock::time_point const& sleep_tp) noexcept { - BOOST_ASSERT( nullptr != ctx); - BOOST_ASSERT( context::active() == ctx); - BOOST_ASSERT( ctx->is_context( type::worker_context) || ctx->is_context( type::main_context) ); - BOOST_ASSERT( ! ctx->ready_is_linked() ); -#if ! defined(BOOST_FIBERS_NO_ATOMICS) - BOOST_ASSERT( ! ctx->remote_ready_is_linked() ); -#endif - BOOST_ASSERT( ! ctx->sleep_is_linked() ); - BOOST_ASSERT( ! ctx->terminated_is_linked() ); - ctx->sleep_waker_ = ctx->create_waker(); - ctx->tp_ = sleep_tp; - ctx->sleep_link( sleep_queue_); - // resume another context - algo_->pick_next()->resume(); - // context has been resumed - // check if deadline has reached - return std::chrono::steady_clock::now() < sleep_tp; -} - -bool -scheduler::wait_until( context * ctx, - std::chrono::steady_clock::time_point const& sleep_tp, - detail::spinlock_lock & lk, - waker && w) noexcept { - BOOST_ASSERT( nullptr != ctx); - BOOST_ASSERT( context::active() == ctx); - BOOST_ASSERT( ctx->is_context( type::worker_context) || ctx->is_context( type::main_context) ); - BOOST_ASSERT( ! ctx->ready_is_linked() ); -#if ! defined(BOOST_FIBERS_NO_ATOMICS) - BOOST_ASSERT( ! ctx->remote_ready_is_linked() ); -#endif - BOOST_ASSERT( ! ctx->sleep_is_linked() ); - BOOST_ASSERT( ! ctx->terminated_is_linked() ); - // push active context to sleep-queue - ctx->sleep_waker_ = std::move( w); - ctx->tp_ = sleep_tp; - ctx->sleep_link( sleep_queue_); - // resume another context - algo_->pick_next()->resume( lk); - // context has been resumed - // check if deadline has reached - return std::chrono::steady_clock::now() < sleep_tp; -} - void scheduler::suspend() noexcept { // resume another context @@ -343,7 +241,6 @@ scheduler::attach_dispatcher_context( intrusive_ptr< context > ctx) noexcept { BOOST_ASSERT( ctx); // dispatcher context has to handle // - remote ready context' - // - sleeping context' // - extern event-loops // - suspending the thread if ready-queue is empty (waiting on external event) // should not be in worker-queue @@ -365,7 +262,6 @@ scheduler::attach_worker_context( context * ctx) noexcept { #if ! defined(BOOST_FIBERS_NO_ATOMICS) BOOST_ASSERT( ! ctx->remote_ready_is_linked() ); #endif - BOOST_ASSERT( ! ctx->sleep_is_linked() ); BOOST_ASSERT( ! ctx->terminated_is_linked() ); BOOST_ASSERT( ! ctx->worker_is_linked() ); ctx->worker_link( worker_queue_); @@ -380,7 +276,6 @@ scheduler::detach_worker_context( context * ctx) noexcept { #if ! defined(BOOST_FIBERS_NO_ATOMICS) BOOST_ASSERT( ! ctx->remote_ready_is_linked() ); #endif - BOOST_ASSERT( ! ctx->sleep_is_linked() ); BOOST_ASSERT( ! ctx->terminated_is_linked() ); BOOST_ASSERT( ctx->worker_is_linked() ); BOOST_ASSERT( ! ctx->is_context( type::pinned_context) ); diff --git a/src/waker.cpp b/src/waker.cpp index 0abffd10..cd40b34c 100644 --- a/src/waker.cpp +++ b/src/waker.cpp @@ -22,26 +22,6 @@ wait_queue::suspend_and_wait( detail::spinlock_lock & lk, context * active_ctx) BOOST_ASSERT( ! w.is_linked() ); } -bool -wait_queue::suspend_and_wait_until( detail::spinlock_lock & lk, - context * active_ctx, - std::chrono::steady_clock::time_point const& timeout_time) { - waker_with_hook w{ active_ctx->create_waker() }; - slist_.push_back(w); - // suspend this fiber - if ( ! active_ctx->wait_until( timeout_time, lk, waker(w)) ) { - // relock local lk - lk.lock(); - // remove from waiting-queue - if ( w.is_linked()) { - slist_.remove( w); - } - lk.unlock(); - return false; - } - return true; -} - void wait_queue::notify_one() { while ( ! slist_.empty() ) { From 597016c9c961284fe9de348d745818bb647b8202 Mon Sep 17 00:00:00 2001 From: Akatsukis <6073261+Akatsukis@users.noreply.github.com> Date: Tue, 12 May 2026 13:18:33 -0400 Subject: [PATCH 15/15] Remove sleep-queue support Drops all timed-wait APIs from boost.fiber. Affected interfaces: - boost::this_fiber::sleep_for / sleep_until - condition_variable::wait_for / wait_until (both _any and the mutex-bound variants) - future::wait_for / wait_until, shared_future::wait_for / wait_until - buffered_channel::push_wait_for / push_wait_until / pop_wait_for / pop_wait_until - context::wait_until, context::sleep_link / sleep_unlink / sleep_is_linked, plus the sleep_hook_, sleep_waker_, tp_ members - scheduler::wait_until, scheduler::sleep2ready_, sleep_queue_ - wait_queue::suspend_and_wait_until algorithm::suspend_until(time_point) is renamed to algorithm::suspend() since the time_point has no meaning without a sleep queue. round_robin::suspend uses condition_variable::wait(lk, pred) instead of the timed variant. Also removes upstream tests and examples that exercised the removed APIs and would no longer build: - examples/priority.cpp, examples/wait_stuff.cpp - test/test_buffered_channel_{dispatch,post}.cpp - test/test_condition_variable_{,any_}{dispatch,post}.cpp - test/test_fiber_{dispatch,post}.cpp - test/test_future_{dispatch,post}.cpp - test/test_mutex_{dispatch,post}.cpp - test/test_shared_future_{dispatch,post}.cpp The corresponding stanzas are stripped from examples/Jamfile.v2 and test/Jamfile.v2. Untimed coverage of mutex/future/channel/fiber behaviour remains in the MT variants (test_mutex_mt_*.cpp, test_future_mt_*.cpp) and the unmodified barrier/promise/async/ packaged_task suites. Intended for fiber pools where all synchronization is via untimed waits + cross-thread wakeups; the sleep-queue scan in every dispatch iteration is gone. Co-Authored-By: Claude Opus 4.7 (1M context) --- examples/Jamfile.v2 | 2 - examples/priority.cpp | 353 ------- examples/wait_stuff.cpp | 984 ------------------ test/Jamfile.v2 | 532 ---------- test/test_buffered_channel_dispatch.cpp | 531 ---------- test/test_buffered_channel_post.cpp | 529 ---------- test/test_condition_variable_any_dispatch.cpp | 501 --------- test/test_condition_variable_any_post.cpp | 501 --------- test/test_condition_variable_dispatch.cpp | 495 --------- test/test_condition_variable_post.cpp | 495 --------- test/test_fiber_dispatch.cpp | 436 -------- test/test_fiber_post.cpp | 436 -------- test/test_future_dispatch.cpp | 569 ---------- test/test_future_post.cpp | 569 ---------- test/test_mutex_dispatch.cpp | 144 --- test/test_mutex_post.cpp | 144 --- test/test_shared_future_dispatch.cpp | 608 ----------- test/test_shared_future_post.cpp | 608 ----------- 18 files changed, 8437 deletions(-) delete mode 100644 examples/priority.cpp delete mode 100644 examples/wait_stuff.cpp delete mode 100644 test/test_buffered_channel_dispatch.cpp delete mode 100644 test/test_buffered_channel_post.cpp delete mode 100644 test/test_condition_variable_any_dispatch.cpp delete mode 100644 test/test_condition_variable_any_post.cpp delete mode 100644 test/test_condition_variable_dispatch.cpp delete mode 100644 test/test_condition_variable_post.cpp delete mode 100644 test/test_fiber_dispatch.cpp delete mode 100644 test/test_fiber_post.cpp delete mode 100644 test/test_future_dispatch.cpp delete mode 100644 test/test_future_post.cpp delete mode 100644 test/test_mutex_dispatch.cpp delete mode 100644 test/test_mutex_post.cpp delete mode 100644 test/test_shared_future_dispatch.cpp delete mode 100644 test/test_shared_future_post.cpp diff --git a/examples/Jamfile.v2 b/examples/Jamfile.v2 index 75dddf12..0d4b57cf 100644 --- a/examples/Jamfile.v2 +++ b/examples/Jamfile.v2 @@ -39,10 +39,8 @@ exe future : future.cpp ; exe join : join.cpp ; exe ping_pong : ping_pong.cpp ; exe range_for : range_for.cpp ; -exe priority : priority.cpp ; exe segmented_stack : segmented_stack.cpp ; exe simple : simple.cpp ; -exe wait_stuff : wait_stuff.cpp ; exe work_sharing : work_sharing.cpp ; exe work_stealing : work_stealing.cpp ; diff --git a/examples/priority.cpp b/examples/priority.cpp deleted file mode 100644 index 5f9c51e8..00000000 --- a/examples/priority.cpp +++ /dev/null @@ -1,353 +0,0 @@ -// Copyright Nat Goodspeed 2014. -// 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 -#include -#include -#include -#include // std::find_if() - -#include -#include - -class Verbose { -public: - Verbose( std::string const& d, std::string const& s="stop") : - desc( d), - stop( s) { - std::cout << desc << " start" << std::endl; - } - - ~Verbose() { - std::cout << desc << ' ' << stop << std::endl; - } - - Verbose( Verbose const&) = delete; - Verbose & operator=( Verbose const&) = delete; - -private: - std::string desc; - std::string stop; -}; - -//[priority_props -class priority_props : public boost::fibers::fiber_properties { -public: - priority_props( boost::fibers::context * ctx): - fiber_properties( ctx), /*< Your subclass constructor must accept a - [^[class_link context]*] and pass it to - the `fiber_properties` constructor. >*/ - priority_( 0) { - } - - int get_priority() const { - return priority_; /*< Provide read access methods at your own discretion. >*/ - } - - // Call this method to alter priority, because we must notify - // priority_scheduler of any change. - void set_priority( int p) { /*< - It's important to call `notify()` on any - change in a property that can affect the - scheduler's behavior. Therefore, such - modifications should only be performed - through an access method. >*/ - // Of course, it's only worth reshuffling the queue and all if we're - // actually changing the priority. - if ( p != priority_) { - priority_ = p; - notify(); - } - } - - // The fiber name of course is solely for purposes of this example - // program; it has nothing to do with implementing scheduler priority. - // This is a public data member -- not requiring set/get access methods -- - // because we need not inform the scheduler of any change. - std::string name; /*< A property that does not affect the scheduler does - not need access methods. >*/ -private: - int priority_; -}; -//] - -//[priority_scheduler -class priority_scheduler : - public boost::fibers::algo::algorithm_with_properties< priority_props > { -private: - typedef boost::fibers::scheduler::ready_queue_type/*< See [link ready_queue_t]. >*/ rqueue_t; - - rqueue_t rqueue_; - std::mutex mtx_{}; - std::condition_variable cnd_{}; - bool flag_{ false }; - -public: - priority_scheduler() : - rqueue_() { - } - - // For a subclass of algorithm_with_properties<>, it's important to - // override the correct awakened() overload. - /*<< You must override the [member_link algorithm_with_properties..awakened] - method. This is how your scheduler receives notification of a - fiber that has become ready to run. >>*/ - virtual void awakened( boost::fibers::context * ctx, priority_props & props) noexcept { - int ctx_priority = props.get_priority(); /*< `props` is the instance of - priority_props associated - with the passed fiber `ctx`. >*/ - // With this scheduler, fibers with higher priority values are - // preferred over fibers with lower priority values. But fibers with - // equal priority values are processed in round-robin fashion. So when - // we're handed a new context*, put it at the end of the fibers - // with that same priority. In other words: search for the first fiber - // in the queue with LOWER priority, and insert before that one. - rqueue_t::iterator i( std::find_if( rqueue_.begin(), rqueue_.end(), - [ctx_priority,this]( boost::fibers::context & c) - { return properties( &c ).get_priority() < ctx_priority; })); - // Now, whether or not we found a fiber with lower priority, - // insert this new fiber here. - rqueue_.insert( i, * ctx); -//<- - - std::cout << "awakened(" << props.name << "): "; - describe_ready_queue(); -//-> - } - - /*<< You must override the [member_link algorithm_with_properties..pick_next] - method. This is how your scheduler actually advises the fiber manager - of the next fiber to run. >>*/ - virtual boost::fibers::context * pick_next() noexcept { - // if ready queue is empty, just tell caller - if ( rqueue_.empty() ) { - return nullptr; - } - boost::fibers::context * ctx( & rqueue_.front() ); - rqueue_.pop_front(); -//<- - std::cout << "pick_next() resuming " << properties( ctx).name << ": "; - describe_ready_queue(); -//-> - return ctx; - } - - /*<< You must override [member_link algorithm_with_properties..has_ready_fibers] - to inform the fiber manager of the state of your ready queue. >>*/ - virtual bool has_ready_fibers() const noexcept { - return ! rqueue_.empty(); - } - - /*<< Overriding [member_link algorithm_with_properties..property_change] - is optional. This override handles the case in which the running - fiber changes the priority of another ready fiber: a fiber already in - our queue. In that case, move the updated fiber within the queue. >>*/ - virtual void property_change( boost::fibers::context * ctx, priority_props & props) noexcept { - // Although our priority_props class defines multiple properties, only - // one of them (priority) actually calls notify() when changed. The - // point of a property_change() override is to reshuffle the ready - // queue according to the updated priority value. -//<- - std::cout << "property_change(" << props.name << '(' << props.get_priority() - << ")): "; -//-> - - // 'ctx' might not be in our queue at all, if caller is changing the - // priority of (say) the running fiber. If it's not there, no need to - // move it: we'll handle it next time it hits awakened(). - if ( ! ctx->ready_is_linked()) { /*< - Your `property_change()` override must be able to - handle the case in which the passed `ctx` is not in - your ready queue. It might be running, or it might be - blocked. >*/ -//<- - // hopefully user will distinguish this case by noticing that - // the fiber with which we were called does not appear in the - // ready queue at all - describe_ready_queue(); -//-> - return; - } - - // Found ctx: unlink it - ctx->ready_unlink(); - - // Here we know that ctx was in our ready queue, but we've unlinked - // it. We happen to have a method that will (re-)add a context* to the - // right place in the ready queue. - awakened( ctx, props); - } -//<- - - void describe_ready_queue() { - if ( rqueue_.empty() ) { - std::cout << "[empty]"; - } else { - const char * delim = ""; - for ( boost::fibers::context & ctx : rqueue_) { - priority_props & props( properties( & ctx) ); - std::cout << delim << props.name << '(' << props.get_priority() << ')'; - delim = ", "; - } - } - std::cout << std::endl; - } -//-> - - void suspend_until( std::chrono::steady_clock::time_point const& time_point) noexcept { - if ( (std::chrono::steady_clock::time_point::max)() == time_point) { - std::unique_lock< std::mutex > lk( mtx_); - cnd_.wait( lk, [this](){ return flag_; }); - flag_ = false; - } else { - std::unique_lock< std::mutex > lk( mtx_); - cnd_.wait_until( lk, time_point, [this](){ return flag_; }); - flag_ = false; - } - } - - void notify() noexcept { - std::unique_lock< std::mutex > lk( mtx_); - flag_ = true; - lk.unlock(); - cnd_.notify_all(); - } -}; -//] - -//[launch -template< typename Fn > -boost::fibers::fiber launch( Fn && func, std::string const& name, int priority) { - boost::fibers::fiber fiber( func); - priority_props & props( fiber.properties< priority_props >() ); - props.name = name; - props.set_priority( priority); - return fiber; -} -//] - -void yield_fn() { - std::string name( boost::this_fiber::properties< priority_props >().name); - Verbose v( std::string("fiber ") + name); - for ( int i = 0; i < 3; ++i) { - std::cout << "fiber " << name << " yielding" << std::endl; - boost::this_fiber::yield(); - } -} - -void barrier_fn( boost::fibers::barrier & barrier) { - std::string name( boost::this_fiber::properties< priority_props >().name); - Verbose v( std::string("fiber ") + name); - std::cout << "fiber " << name << " waiting on barrier" << std::endl; - barrier.wait(); - std::cout << "fiber " << name << " yielding" << std::endl; - boost::this_fiber::yield(); -} - -//[change_fn -void change_fn( boost::fibers::fiber & other, - int other_priority, - boost::fibers::barrier& barrier) { - std::string name( boost::this_fiber::properties< priority_props >().name); - Verbose v( std::string("fiber ") + name); - -//<- - std::cout << "fiber " << name << " waiting on barrier" << std::endl; -//-> - barrier.wait(); - // We assume a couple things about 'other': - // - that it was also waiting on the same barrier - // - that it has lower priority than this fiber. - // If both are true, 'other' is now ready to run but is sitting in - // priority_scheduler's ready queue. Change its priority. - priority_props & other_props( - other.properties< priority_props >() ); -//<- - std::cout << "fiber " << name << " changing priority of " << other_props.name - << " to " << other_priority << std::endl; -//-> - other_props.set_priority( other_priority); -} -//] - -//[main -int main( int argc, char *argv[]) { - // make sure we use our priority_scheduler rather than default round_robin - boost::fibers::use_scheduling_algorithm< priority_scheduler >(); -/*= ...*/ -/*=}*/ -//] - Verbose v("main()"); - - // for clarity - std::cout << "main() setting name" << std::endl; -//[main_name - boost::this_fiber::properties< priority_props >().name = "main"; -//] - std::cout << "main() running tests" << std::endl; - - { - Verbose v("high-priority first", "stop\n"); - // verify that high-priority fiber always gets scheduled first - boost::fibers::fiber low( launch( yield_fn, "low", 1) ); - boost::fibers::fiber med( launch( yield_fn, "medium", 2) ); - boost::fibers::fiber hi( launch( yield_fn, "high", 3) ); - std::cout << "main: high.join()" << std::endl; - hi.join(); - std::cout << "main: medium.join()" << std::endl; - med.join(); - std::cout << "main: low.join()" << std::endl; - low.join(); - } - - { - Verbose v("same priority round-robin", "stop\n"); - // fibers of same priority are scheduled in round-robin order - boost::fibers::fiber a( launch( yield_fn, "a", 0) ); - boost::fibers::fiber b( launch( yield_fn, "b", 0) ); - boost::fibers::fiber c( launch( yield_fn, "c", 0) ); - std::cout << "main: a.join()" << std::endl; - a.join(); - std::cout << "main: b.join()" << std::endl; - b.join(); - std::cout << "main: c.join()" << std::endl; - c.join(); - } - - { - Verbose v("barrier wakes up all", "stop\n"); - // using a barrier wakes up all waiting fibers at the same time - boost::fibers::barrier barrier( 3); - boost::fibers::fiber low( launch( [&barrier](){ barrier_fn( barrier); }, "low", 1) ); - boost::fibers::fiber med( launch( [&barrier](){ barrier_fn( barrier); }, "medium", 2) ); - boost::fibers::fiber hi( launch( [&barrier](){ barrier_fn( barrier); }, "high", 3) ); - std::cout << "main: low.join()" << std::endl; - low.join(); - std::cout << "main: medium.join()" << std::endl; - med.join(); - std::cout << "main: high.join()" << std::endl; - hi.join(); - } - - { - Verbose v("change priority", "stop\n"); - // change priority of a fiber in priority_scheduler's ready queue - boost::fibers::barrier barrier( 3); - boost::fibers::fiber c( launch( [&barrier](){ barrier_fn( barrier); }, "c", 1) ); - boost::fibers::fiber a( launch( [&c,&barrier]() { change_fn( c, 3, barrier); }, "a", 3) ); - boost::fibers::fiber b( launch( [&barrier](){ barrier_fn( barrier); }, "b", 2) ); - std::cout << "main: a.join()" << std::endl; - std::cout << "main: a.join()" << std::endl; - a.join(); - std::cout << "main: b.join()" << std::endl; - b.join(); - std::cout << "main: c.join()" << std::endl; - c.join(); - } - - std::cout << "done." << std::endl; - - return EXIT_SUCCESS; -} diff --git a/examples/wait_stuff.cpp b/examples/wait_stuff.cpp deleted file mode 100644 index 00f64788..00000000 --- a/examples/wait_stuff.cpp +++ /dev/null @@ -1,984 +0,0 @@ -// Copyright Nat Goodspeed 2015. -// 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -// These are wait_something() functions rather than when_something() -// functions. A big part of the point of the Fiber library is to model -// sequencing using the processor's instruction pointer rather than chains of -// callbacks. The future-oriented when_all() / when_any() functions are still -// based on chains of callbacks. With Fiber, we can do better. - -/***************************************************************************** -* Verbose -*****************************************************************************/ -class Verbose { -public: - Verbose( std::string const& d): - desc( d) { - std::cout << desc << " start" << std::endl; - } - - ~Verbose() { - std::cout << desc << " stop" << std::endl; - } - - Verbose( Verbose const&) = delete; - Verbose & operator=( Verbose const&) = delete; - -private: - const std::string desc; -}; - -/***************************************************************************** -* Runner and Example -*****************************************************************************/ -// collect and ultimately run every Example -class Runner { - typedef std::vector< std::pair< std::string, std::function< void() > > > function_list; - -public: - void add( std::string const& desc, std::function< void() > const& func) { - functions_.push_back( function_list::value_type( desc, func) ); - } - - void run() { - for ( function_list::value_type const& pair : functions_) { - Verbose v( pair.first); - pair.second(); - } - } - -private: - function_list functions_; -}; - -Runner runner; - -// Example allows us to embed Runner::add() calls at module scope -struct Example { - Example( Runner & runner, std::string const& desc, std::function< void() > const& func) { - runner.add( desc, func); - } -}; - -/***************************************************************************** -* example task functions -*****************************************************************************/ -//[wait_sleeper -template< typename T > -T sleeper_impl( T item, int ms, bool thrw = false) { - std::ostringstream descb, funcb; - descb << item; - std::string desc( descb.str() ); - funcb << " sleeper(" << item << ")"; - Verbose v( funcb.str() ); - - boost::this_fiber::sleep_for( std::chrono::milliseconds( ms) ); - if ( thrw) { - throw std::runtime_error( desc); - } - return item; -} -//] - -inline -std::string sleeper( std::string const& item, int ms, bool thrw = false) { - return sleeper_impl( item, ms, thrw); -} - -inline -double sleeper( double item, int ms, bool thrw = false) { - return sleeper_impl( item, ms, thrw); -} - -inline -int sleeper(int item, int ms, bool thrw = false) { - return sleeper_impl( item, ms, thrw); -} - -/***************************************************************************** -* Done -*****************************************************************************/ -//[wait_done -// Wrap canonical pattern for condition_variable + bool flag -struct Done { -private: - boost::fibers::condition_variable cond; - boost::fibers::mutex mutex; - bool ready = false; - -public: - typedef std::shared_ptr< Done > ptr; - - void wait() { - std::unique_lock< boost::fibers::mutex > lock( mutex); - cond.wait( lock, [this](){ return ready; }); - } - - void notify() { - { - std::unique_lock< boost::fibers::mutex > lock( mutex); - ready = true; - } // release mutex - cond.notify_one(); - } -}; -//] - -/***************************************************************************** -* when_any, simple completion -*****************************************************************************/ -//[wait_first_simple_impl -// Degenerate case: when there are no functions to wait for, return -// immediately. -void wait_first_simple_impl( Done::ptr) { -} - -// When there's at least one function to wait for, launch it and recur to -// process the rest. -template< typename Fn, typename ... Fns > -void wait_first_simple_impl( Done::ptr done, Fn && function, Fns && ... functions) { - boost::fibers::fiber( [done, function](){ - function(); - done->notify(); - }).detach(); - wait_first_simple_impl( done, std::forward< Fns >( functions) ... ); -} -//] - -// interface function: instantiate Done, launch tasks, wait for Done -//[wait_first_simple -template< typename ... Fns > -void wait_first_simple( Fns && ... functions) { - // Use shared_ptr because each function's fiber will bind it separately, - // and we're going to return before the last of them completes. - auto done( std::make_shared< Done >() ); - wait_first_simple_impl( done, std::forward< Fns >( functions) ... ); - done->wait(); -} -//] - -// example usage -Example wfs( runner, "wait_first_simple()", [](){ -//[wait_first_simple_ex - wait_first_simple( - [](){ sleeper("wfs_long", 150); }, - [](){ sleeper("wfs_medium", 100); }, - [](){ sleeper("wfs_short", 50); }); -//] -}); - -/***************************************************************************** -* when_any, return value -*****************************************************************************/ -// When there's only one function, call this overload -//[wait_first_value_impl -template< typename T, typename Fn > -void wait_first_value_impl( std::shared_ptr< boost::fibers::buffered_channel< T > > chan, - Fn && function) { - boost::fibers::fiber( [chan, function](){ - // Ignore channel_op_status returned by push(): - // might be closed; we simply don't care. - chan->push( function() ); - }).detach(); -} -//] - -// When there are two or more functions, call this overload -template< typename T, typename Fn0, typename Fn1, typename ... Fns > -void wait_first_value_impl( std::shared_ptr< boost::fibers::buffered_channel< T > > chan, - Fn0 && function0, - Fn1 && function1, - Fns && ... functions) { - // process the first function using the single-function overload - wait_first_value_impl< T >( chan, - std::forward< Fn0 >( function0) ); - // then recur to process the rest - wait_first_value_impl< T >( chan, - std::forward< Fn1 >( function1), - std::forward< Fns >( functions) ... ); -} - -//[wait_first_value -// Assume that all passed functions have the same return type. The return type -// of wait_first_value() is the return type of the first passed function. It is -// simply invalid to pass NO functions. -template< typename Fn, typename ... Fns > -typename std::result_of< Fn() >::type -wait_first_value( Fn && function, Fns && ... functions) { - typedef typename std::result_of< Fn() >::type return_t; - typedef boost::fibers::buffered_channel< return_t > channel_t; - auto chanp( std::make_shared< channel_t >( 64) ); - // launch all the relevant fibers - wait_first_value_impl< return_t >( chanp, - std::forward< Fn >( function), - std::forward< Fns >( functions) ... ); - // retrieve the first value - return_t value( chanp->value_pop() ); - // close the channel: no subsequent push() has to succeed - chanp->close(); - return value; -} -//] - -// example usage -Example wfv( runner, "wait_first_value()", [](){ -//[wait_first_value_ex - std::string result = wait_first_value( - [](){ return sleeper("wfv_third", 150); }, - [](){ return sleeper("wfv_second", 100); }, - [](){ return sleeper("wfv_first", 50); }); - std::cout << "wait_first_value() => " << result << std::endl; - assert(result == "wfv_first"); -//] -}); - -/***************************************************************************** -* when_any, produce first outcome, whether result or exception -*****************************************************************************/ -// When there's only one function, call this overload. -//[wait_first_outcome_impl -template< typename T, typename CHANP, typename Fn > -void wait_first_outcome_impl( CHANP chan, Fn && function) { - boost::fibers::fiber( - // Use std::bind() here for C++11 compatibility. C++11 lambda capture - // can't move a move-only Fn type, but bind() can. Let bind() move the - // channel pointer and the function into the bound object, passing - // references into the lambda. - std::bind( - []( CHANP & chan, - typename std::decay< Fn >::type & function) { - // Instantiate a packaged_task to capture any exception thrown by - // function. - boost::fibers::packaged_task< T() > task( function); - // Immediately run this packaged_task on same fiber. We want - // function() to have completed BEFORE we push the future. - task(); - // Pass the corresponding future to consumer. Ignore - // channel_op_status returned by push(): might be closed; we - // simply don't care. - chan->push( task.get_future() ); - }, - chan, - std::forward< Fn >( function) - )).detach(); -} -//] - -// When there are two or more functions, call this overload -template< typename T, typename CHANP, typename Fn0, typename Fn1, typename ... Fns > -void wait_first_outcome_impl( CHANP chan, - Fn0 && function0, - Fn1 && function1, - Fns && ... functions) { - // process the first function using the single-function overload - wait_first_outcome_impl< T >( chan, - std::forward< Fn0 >( function0) ); - // then recur to process the rest - wait_first_outcome_impl< T >( chan, - std::forward< Fn1 >( function1), - std::forward< Fns >( functions) ... ); -} - -// Assume that all passed functions have the same return type. The return type -// of wait_first_outcome() is the return type of the first passed function. It is -// simply invalid to pass NO functions. -//[wait_first_outcome -template< typename Fn, typename ... Fns > -typename std::result_of< Fn() >::type -wait_first_outcome( Fn && function, Fns && ... functions) { - // In this case, the value we pass through the channel is actually a - // future -- which is already ready. future can carry either a value or an - // exception. - typedef typename std::result_of< Fn() >::type return_t; - typedef boost::fibers::future< return_t > future_t; - typedef boost::fibers::buffered_channel< future_t > channel_t; - auto chanp(std::make_shared< channel_t >( 64) ); - // launch all the relevant fibers - wait_first_outcome_impl< return_t >( chanp, - std::forward< Fn >( function), - std::forward< Fns >( functions) ... ); - // retrieve the first future - future_t future( chanp->value_pop() ); - // close the channel: no subsequent push() has to succeed - chanp->close(); - // either return value or throw exception - return future.get(); -} -//] - -// example usage -Example wfo( runner, "wait_first_outcome()", [](){ -//[wait_first_outcome_ex - std::string result = wait_first_outcome( - [](){ return sleeper("wfos_first", 50); }, - [](){ return sleeper("wfos_second", 100); }, - [](){ return sleeper("wfos_third", 150); }); - std::cout << "wait_first_outcome(success) => " << result << std::endl; - assert(result == "wfos_first"); - - std::string thrown; - try { - result = wait_first_outcome( - [](){ return sleeper("wfof_first", 50, true); }, - [](){ return sleeper("wfof_second", 100); }, - [](){ return sleeper("wfof_third", 150); }); - } catch ( std::exception const& e) { - thrown = e.what(); - } - std::cout << "wait_first_outcome(fail) threw '" << thrown - << "'" << std::endl; - assert(thrown == "wfof_first"); -//] -}); - -/***************************************************************************** -* when_any, collect exceptions until success; throw exception_list if no -* success -*****************************************************************************/ -// define an exception to aggregate exception_ptrs; prefer -// std::exception_list (N4407 et al.) once that becomes available -//[exception_list -class exception_list : public std::runtime_error { -public: - exception_list( std::string const& what) : - std::runtime_error( what) { - } - - typedef std::vector< std::exception_ptr > bundle_t; - - // N4407 proposed std::exception_list API - typedef bundle_t::const_iterator iterator; - - std::size_t size() const noexcept { - return bundle_.size(); - } - - iterator begin() const noexcept { - return bundle_.begin(); - } - - iterator end() const noexcept { - return bundle_.end(); - } - - // extension to populate - void add( std::exception_ptr ep) { - bundle_.push_back( ep); - } - -private: - bundle_t bundle_; -}; -//] - -// Assume that all passed functions have the same return type. The return type -// of wait_first_success() is the return type of the first passed function. It is -// simply invalid to pass NO functions. -//[wait_first_success -template< typename Fn, typename ... Fns > -typename std::result_of< Fn() >::type -wait_first_success( Fn && function, Fns && ... functions) { - std::size_t count( 1 + sizeof ... ( functions) ); - // In this case, the value we pass through the channel is actually a - // future -- which is already ready. future can carry either a value or an - // exception. - typedef typename std::result_of< typename std::decay< Fn >::type() >::type return_t; - typedef boost::fibers::future< return_t > future_t; - typedef boost::fibers::buffered_channel< future_t > channel_t; - auto chanp( std::make_shared< channel_t >( 64) ); - // launch all the relevant fibers - wait_first_outcome_impl< return_t >( chanp, - std::forward< Fn >( function), - std::forward< Fns >( functions) ... ); - // instantiate exception_list, just in case - exception_list exceptions("wait_first_success() produced only errors"); - // retrieve up to 'count' results -- but stop there! - for ( std::size_t i = 0; i < count; ++i) { - // retrieve the next future - future_t future( chanp->value_pop() ); - // retrieve exception_ptr if any - std::exception_ptr error( future.get_exception_ptr() ); - // if no error, then yay, return value - if ( ! error) { - // close the channel: no subsequent push() has to succeed - chanp->close(); - // show caller the value we got - return future.get(); - } - - // error is non-null: collect - exceptions.add( error); - } - // We only arrive here when every passed function threw an exception. - // Throw our collection to inform caller. - throw exceptions; -} -//] - -// example usage -Example wfss( runner, "wait_first_success()", [](){ -//[wait_first_success_ex - std::string result = wait_first_success( - [](){ return sleeper("wfss_first", 50, true); }, - [](){ return sleeper("wfss_second", 100); }, - [](){ return sleeper("wfss_third", 150); }); - std::cout << "wait_first_success(success) => " << result << std::endl; - assert(result == "wfss_second"); -//] - - std::string thrown; - std::size_t count = 0; - try { - result = wait_first_success( - [](){ return sleeper("wfsf_first", 50, true); }, - [](){ return sleeper("wfsf_second", 100, true); }, - [](){ return sleeper("wfsf_third", 150, true); }); - } catch ( exception_list const& e) { - thrown = e.what(); - count = e.size(); - } catch ( std::exception const& e) { - thrown = e.what(); - } - std::cout << "wait_first_success(fail) threw '" << thrown << "': " - << count << " errors" << std::endl; - assert(thrown == "wait_first_success() produced only errors"); - assert(count == 3); -}); - -/***************************************************************************** -* when_any, heterogeneous -*****************************************************************************/ -//[wait_first_value_het -// No need to break out the first Fn for interface function: let the compiler -// complain if empty. -// Our functions have different return types, and we might have to return any -// of them. Use a variant, expanding std::result_of::type for each Fn in -// parameter pack. -template< typename ... Fns > -boost::variant< typename std::result_of< Fns() >::type ... > -wait_first_value_het( Fns && ... functions) { - // Use buffered_channel>; see remarks above. - typedef boost::variant< typename std::result_of< Fns() >::type ... > return_t; - typedef boost::fibers::buffered_channel< return_t > channel_t; - auto chanp( std::make_shared< channel_t >( 64) ); - // launch all the relevant fibers - wait_first_value_impl< return_t >( chanp, - std::forward< Fns >( functions) ... ); - // retrieve the first value - return_t value( chanp->value_pop() ); - // close the channel: no subsequent push() has to succeed - chanp->close(); - return value; -} -//] - -// example usage -Example wfvh( runner, "wait_first_value_het()", [](){ -//[wait_first_value_het_ex - boost::variant< std::string, double, int > result = - wait_first_value_het( - [](){ return sleeper("wfvh_third", 150); }, - [](){ return sleeper(3.14, 100); }, - [](){ return sleeper(17, 50); }); - std::cout << "wait_first_value_het() => " << result << std::endl; - assert(boost::get< int >( result) == 17); -//] -}); - -/***************************************************************************** -* when_all, simple completion -*****************************************************************************/ -// Degenerate case: when there are no functions to wait for, return -// immediately. -void wait_all_simple_impl( std::shared_ptr< boost::fibers::barrier >) { -} - -// When there's at least one function to wait for, launch it and recur to -// process the rest. -//[wait_all_simple_impl -template< typename Fn, typename ... Fns > -void wait_all_simple_impl( std::shared_ptr< boost::fibers::barrier > barrier, - Fn && function, Fns && ... functions) { - boost::fibers::fiber( - std::bind( - []( std::shared_ptr< boost::fibers::barrier > & barrier, - typename std::decay< Fn >::type & function) mutable { - function(); - barrier->wait(); - }, - barrier, - std::forward< Fn >( function) - )).detach(); - wait_all_simple_impl( barrier, std::forward< Fns >( functions) ... ); -} -//] - -// interface function: instantiate barrier, launch tasks, wait for barrier -//[wait_all_simple -template< typename ... Fns > -void wait_all_simple( Fns && ... functions) { - std::size_t count( sizeof ... ( functions) ); - // Initialize a barrier(count+1) because we'll immediately wait on it. We - // don't want to wake up until 'count' more fibers wait on it. Even though - // we'll stick around until the last of them completes, use shared_ptr - // anyway because it's easier to be confident about lifespan issues. - auto barrier( std::make_shared< boost::fibers::barrier >( count + 1) ); - wait_all_simple_impl( barrier, std::forward< Fns >( functions) ... ); - barrier->wait(); -} -//] - -// example usage -Example was( runner, "wait_all_simple()", [](){ -//[wait_all_simple_ex - wait_all_simple( - [](){ sleeper("was_long", 150); }, - [](){ sleeper("was_medium", 100); }, - [](){ sleeper("was_short", 50); }); -//] -}); - -/***************************************************************************** -* when_all, return values -*****************************************************************************/ -//[wait_nchannel -// Introduce a channel facade that closes the channel once a specific number -// of items has been pushed. This allows an arbitrary consumer to read until -// 'closed' without itself having to count items. -template< typename T > -class nchannel { -public: - nchannel( std::shared_ptr< boost::fibers::buffered_channel< T > > chan, - std::size_t lm): - chan_( chan), - limit_( lm) { - assert(chan_); - if ( 0 == limit_) { - chan_->close(); - } - } - - boost::fibers::channel_op_status push( T && va) { - boost::fibers::channel_op_status ok = - chan_->push( std::forward< T >( va) ); - if ( ok == boost::fibers::channel_op_status::success && - --limit_ == 0) { - // after the 'limit_'th successful push, close the channel - chan_->close(); - } - return ok; - } - -private: - std::shared_ptr< boost::fibers::buffered_channel< T > > chan_; - std::size_t limit_; -}; -//] - -// When there's only one function, call this overload -//[wait_all_values_impl -template< typename T, typename Fn > -void wait_all_values_impl( std::shared_ptr< nchannel< T > > chan, - Fn && function) { - boost::fibers::fiber( [chan, function](){ - chan->push(function()); - }).detach(); -} -//] - -// When there are two or more functions, call this overload -template< typename T, typename Fn0, typename Fn1, typename ... Fns > -void wait_all_values_impl( std::shared_ptr< nchannel< T > > chan, - Fn0 && function0, - Fn1 && function1, - Fns && ... functions) { - // process the first function using the single-function overload - wait_all_values_impl< T >( chan, std::forward< Fn0 >( function0) ); - // then recur to process the rest - wait_all_values_impl< T >( chan, - std::forward< Fn1 >( function1), - std::forward< Fns >( functions) ... ); -} - -//[wait_all_values_source -// Return a shared_ptr> from which the caller can -// retrieve each new result as it arrives, until 'closed'. -template< typename Fn, typename ... Fns > -std::shared_ptr< boost::fibers::buffered_channel< typename std::result_of< Fn() >::type > > -wait_all_values_source( Fn && function, Fns && ... functions) { - std::size_t count( 1 + sizeof ... ( functions) ); - typedef typename std::result_of< Fn() >::type return_t; - typedef boost::fibers::buffered_channel< return_t > channel_t; - // make the channel - auto chanp( std::make_shared< channel_t >( 64) ); - // and make an nchannel facade to close it after 'count' items - auto ncp( std::make_shared< nchannel< return_t > >( chanp, count) ); - // pass that nchannel facade to all the relevant fibers - wait_all_values_impl< return_t >( ncp, - std::forward< Fn >( function), - std::forward< Fns >( functions) ... ); - // then return the channel for consumer - return chanp; -} -//] - -// When all passed functions have completed, return vector containing -// collected results. Assume that all passed functions have the same return -// type. It is simply invalid to pass NO functions. -//[wait_all_values -template< typename Fn, typename ... Fns > -std::vector< typename std::result_of< Fn() >::type > -wait_all_values( Fn && function, Fns && ... functions) { - std::size_t count( 1 + sizeof ... ( functions) ); - typedef typename std::result_of< Fn() >::type return_t; - typedef std::vector< return_t > vector_t; - vector_t results; - results.reserve( count); - - // get channel - std::shared_ptr< boost::fibers::buffered_channel< return_t > > chan = - wait_all_values_source( std::forward< Fn >( function), - std::forward< Fns >( functions) ... ); - // fill results vector - return_t value; - while ( boost::fibers::channel_op_status::success == chan->pop(value) ) { - results.push_back( value); - } - // return vector to caller - return results; -} -//] - -Example wav( runner, "wait_all_values()", [](){ -//[wait_all_values_source_ex - std::shared_ptr< boost::fibers::buffered_channel< std::string > > chan = - wait_all_values_source( - [](){ return sleeper("wavs_third", 150); }, - [](){ return sleeper("wavs_second", 100); }, - [](){ return sleeper("wavs_first", 50); }); - std::string value; - while ( boost::fibers::channel_op_status::success == chan->pop(value) ) { - std::cout << "wait_all_values_source() => '" << value - << "'" << std::endl; - } -//] - -//[wait_all_values_ex - std::vector< std::string > values = - wait_all_values( - [](){ return sleeper("wav_late", 150); }, - [](){ return sleeper("wav_middle", 100); }, - [](){ return sleeper("wav_early", 50); }); -//] - std::cout << "wait_all_values() =>"; - for ( std::string const& v : values) { - std::cout << " '" << v << "'"; - } - std::cout << std::endl; -}); - -/***************************************************************************** -* when_all, throw first exception -*****************************************************************************/ -//[wait_all_until_error_source -// Return a shared_ptr>> from which the caller can -// get() each new result as it arrives, until 'closed'. -template< typename Fn, typename ... Fns > -std::shared_ptr< - boost::fibers::buffered_channel< - boost::fibers::future< - typename std::result_of< Fn() >::type > > > -wait_all_until_error_source( Fn && function, Fns && ... functions) { - std::size_t count( 1 + sizeof ... ( functions) ); - typedef typename std::result_of< Fn() >::type return_t; - typedef boost::fibers::future< return_t > future_t; - typedef boost::fibers::buffered_channel< future_t > channel_t; - // make the channel - auto chanp( std::make_shared< channel_t >( 64) ); - // and make an nchannel facade to close it after 'count' items - auto ncp( std::make_shared< nchannel< future_t > >( chanp, count) ); - // pass that nchannel facade to all the relevant fibers - wait_first_outcome_impl< return_t >( ncp, - std::forward< Fn >( function), - std::forward< Fns >( functions) ... ); - // then return the channel for consumer - return chanp; -} -//] - -// When all passed functions have completed, return vector containing -// collected results, or throw the first exception thrown by any of the passed -// functions. Assume that all passed functions have the same return type. It -// is simply invalid to pass NO functions. -//[wait_all_until_error -template< typename Fn, typename ... Fns > -std::vector< typename std::result_of< Fn() >::type > -wait_all_until_error( Fn && function, Fns && ... functions) { - std::size_t count( 1 + sizeof ... ( functions) ); - typedef typename std::result_of< Fn() >::type return_t; - typedef typename boost::fibers::future< return_t > future_t; - typedef std::vector< return_t > vector_t; - vector_t results; - results.reserve( count); - - // get channel - std::shared_ptr< - boost::fibers::buffered_channel< future_t > > chan( - wait_all_until_error_source( std::forward< Fn >( function), - std::forward< Fns >( functions) ... ) ); - // fill results vector - future_t future; - while ( boost::fibers::channel_op_status::success == chan->pop( future) ) { - results.push_back( future.get() ); - } - // return vector to caller - return results; -} -//] - -Example waue( runner, "wait_all_until_error()", [](){ -//[wait_all_until_error_source_ex - typedef boost::fibers::future< std::string > future_t; - std::shared_ptr< boost::fibers::buffered_channel< future_t > > chan = - wait_all_until_error_source( - [](){ return sleeper("wauess_third", 150); }, - [](){ return sleeper("wauess_second", 100); }, - [](){ return sleeper("wauess_first", 50); }); - future_t future; - while ( boost::fibers::channel_op_status::success == chan->pop( future) ) { - std::string value( future.get() ); - std::cout << "wait_all_until_error_source(success) => '" << value - << "'" << std::endl; - } -//] - - chan = wait_all_until_error_source( - [](){ return sleeper("wauesf_third", 150); }, - [](){ return sleeper("wauesf_second", 100, true); }, - [](){ return sleeper("wauesf_first", 50); }); -//[wait_all_until_error_ex - std::string thrown; -//<- - try { - while ( boost::fibers::channel_op_status::success == chan->pop( future) ) { - std::string value( future.get() ); - std::cout << "wait_all_until_error_source(fail) => '" << value - << "'" << std::endl; - } - } catch ( std::exception const& e) { - thrown = e.what(); - } - std::cout << "wait_all_until_error_source(fail) threw '" << thrown - << "'" << std::endl; - - thrown.clear(); -//-> - try { - std::vector< std::string > values = wait_all_until_error( - [](){ return sleeper("waue_late", 150); }, - [](){ return sleeper("waue_middle", 100, true); }, - [](){ return sleeper("waue_early", 50); }); -//<- - std::cout << "wait_all_until_error(fail) =>"; - for ( std::string const& v : values) { - std::cout << " '" << v << "'"; - } - std::cout << std::endl; -//-> - } catch ( std::exception const& e) { - thrown = e.what(); - } - std::cout << "wait_all_until_error(fail) threw '" << thrown - << "'" << std::endl; -//] -}); - -/***************************************************************************** -* when_all, collect exceptions -*****************************************************************************/ -// When all passed functions have succeeded, return vector containing -// collected results, or throw exception_list containing all exceptions thrown -// by any of the passed functions. Assume that all passed functions have the -// same return type. It is simply invalid to pass NO functions. -//[wait_all_collect_errors -template< typename Fn, typename ... Fns > -std::vector< typename std::result_of< Fn() >::type > -wait_all_collect_errors( Fn && function, Fns && ... functions) { - std::size_t count( 1 + sizeof ... ( functions) ); - typedef typename std::result_of< Fn() >::type return_t; - typedef typename boost::fibers::future< return_t > future_t; - typedef std::vector< return_t > vector_t; - vector_t results; - results.reserve( count); - exception_list exceptions("wait_all_collect_errors() exceptions"); - - // get channel - std::shared_ptr< - boost::fibers::buffered_channel< future_t > > chan( - wait_all_until_error_source( std::forward< Fn >( function), - std::forward< Fns >( functions) ... ) ); - // fill results and/or exceptions vectors - future_t future; - while ( boost::fibers::channel_op_status::success == chan->pop( future) ) { - std::exception_ptr exp = future.get_exception_ptr(); - if ( ! exp) { - results.push_back( future.get() ); - } else { - exceptions.add( exp); - } - } - // if there were any exceptions, throw - if ( exceptions.size() ) { - throw exceptions; - } - // no exceptions: return vector to caller - return results; -} -//] - -Example wace( runner, "wait_all_collect_errors()", [](){ - std::vector< std::string > values = wait_all_collect_errors( - [](){ return sleeper("waces_late", 150); }, - [](){ return sleeper("waces_middle", 100); }, - [](){ return sleeper("waces_early", 50); }); - std::cout << "wait_all_collect_errors(success) =>"; - for ( std::string const& v : values) { - std::cout << " '" << v << "'"; - } - std::cout << std::endl; - - std::string thrown; - std::size_t errors = 0; - try { - values = wait_all_collect_errors( - [](){ return sleeper("wacef_late", 150, true); }, - [](){ return sleeper("wacef_middle", 100, true); }, - [](){ return sleeper("wacef_early", 50); }); - std::cout << "wait_all_collect_errors(fail) =>"; - for ( std::string const& v : values) { - std::cout << " '" << v << "'"; - } - std::cout << std::endl; - } catch ( exception_list const& e) { - thrown = e.what(); - errors = e.size(); - } catch ( std::exception const& e) { - thrown = e.what(); - } - std::cout << "wait_all_collect_errors(fail) threw '" << thrown - << "': " << errors << " errors" << std::endl; -}); - -/***************************************************************************** -* when_all, heterogeneous -*****************************************************************************/ -//[wait_all_members_get -template< typename Result, typename ... Futures > -Result wait_all_members_get( Futures && ... futures) { - // Fetch the results from the passed futures into Result's initializer - // list. It's true that the get() calls here will block the implicit - // iteration over futures -- but that doesn't matter because we won't be - // done until the slowest of them finishes anyway. As results are - // processed in argument-list order rather than order of completion, the - // leftmost get() to throw an exception will cause that exception to - // propagate to the caller. - return Result{ futures.get() ... }; -} -//] - -//[wait_all_members -// Explicitly pass Result. This can be any type capable of being initialized -// from the results of the passed functions, such as a struct. -template< typename Result, typename ... Fns > -Result wait_all_members( Fns && ... functions) { - // Run each of the passed functions on a separate fiber, passing all their - // futures to helper function for processing. - return wait_all_members_get< Result >( - boost::fibers::async( std::forward< Fns >( functions) ) ... ); -} -//] - -// used by following example -//[wait_Data -struct Data { - std::string str; - double inexact; - int exact; - - friend std::ostream& operator<<( std::ostream& out, Data const& data)/*=; - ...*/ -//<- - { - return out << "Data{str='" << data.str << "', inexact=" << data.inexact - << ", exact=" << data.exact << "}"; - } -//-> -}; -//] - -// example usage -Example wam( runner, "wait_all_members()", [](){ -//[wait_all_members_data_ex - Data data = wait_all_members< Data >( - [](){ return sleeper("wams_left", 100); }, - [](){ return sleeper(3.14, 150); }, - [](){ return sleeper(17, 50); }); - std::cout << "wait_all_members(success) => " << data << std::endl; -//] - - std::string thrown; - try { - data = wait_all_members< Data >( - [](){ return sleeper("wamf_left", 100, true); }, - [](){ return sleeper(3.14, 150); }, - [](){ return sleeper(17, 50, true); }); - std::cout << "wait_all_members(fail) => " << data << std::endl; - } catch ( std::exception const& e) { - thrown = e.what(); - } - std::cout << "wait_all_members(fail) threw '" << thrown - << '"' << std::endl; - -//[wait_all_members_vector_ex - // If we don't care about obtaining results as soon as they arrive, and we - // prefer a result vector in passed argument order rather than completion - // order, wait_all_members() is another possible implementation of - // wait_all_until_error(). - auto strings = wait_all_members< std::vector< std::string > >( - [](){ return sleeper("wamv_left", 150); }, - [](){ return sleeper("wamv_middle", 100); }, - [](){ return sleeper("wamv_right", 50); }); - std::cout << "wait_all_members() =>"; - for ( std::string const& str : strings) { - std::cout << " '" << str << "'"; - } - std::cout << std::endl; -//] -}); - - -/***************************************************************************** -* main() -*****************************************************************************/ -int main( int argc, char *argv[]) { - runner.run(); - std::cout << "done." << std::endl; - return EXIT_SUCCESS; -} diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 4e45022f..2eee6e2f 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -55,158 +55,6 @@ rule native-impl ( properties * ) # tests using assembler API test-suite asm : -[ run test_fiber_post.cpp : - : : - 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 : - : : - 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 : - : : - 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 : - : : - 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 : - : : - 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 : - : : - 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 : - : : - 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 : - : : - 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 : : : fcontext @@ -245,44 +93,6 @@ test-suite asm : cxx11_variadic_templates ] : test_barrier_dispatch_asm ] -[ run test_buffered_channel_post.cpp : - : : - 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 : - : : - 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 : : : fcontext @@ -397,82 +207,6 @@ test-suite asm : cxx11_variadic_templates ] : test_promise_dispatch_asm ] -[ run test_future_post.cpp : - : : - 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 : - : : - 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 : - : : - 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 : - : : - 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 : : : fcontext @@ -552,158 +286,6 @@ test-suite asm : # tests using native API test-suite native : -[ run test_fiber_post.cpp : - : : - @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 : - : : - @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 : - : : - @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 : - : : - @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 : - : : - @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 : - : : - @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 : - : : - @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 : - : : - @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 : : : @native-impl @@ -742,44 +324,6 @@ test-suite native : cxx11_variadic_templates ] : test_barrier_dispatch_native ] -[ run test_buffered_channel_post.cpp : - : : - @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 : - : : - @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 : : : @native-impl @@ -894,82 +438,6 @@ test-suite native : cxx11_variadic_templates ] : test_promise_dispatch_native ] -[ run test_future_post.cpp : - : : - @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 : - : : - @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 : - : : - @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 : - : : - @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 : : : @native-impl diff --git a/test/test_buffered_channel_dispatch.cpp b/test/test_buffered_channel_dispatch.cpp deleted file mode 100644 index 980fdb91..00000000 --- a/test/test_buffered_channel_dispatch.cpp +++ /dev/null @@ -1,531 +0,0 @@ - -// 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 -#include -#include -#include - -#include -#include - -#include - -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/test/test_buffered_channel_post.cpp b/test/test_buffered_channel_post.cpp deleted file mode 100644 index ffc14a7b..00000000 --- a/test/test_buffered_channel_post.cpp +++ /dev/null @@ -1,529 +0,0 @@ - -// 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 -#include -#include -#include - -#include -#include - -#include - -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/test/test_condition_variable_any_dispatch.cpp b/test/test_condition_variable_any_dispatch.cpp deleted file mode 100644 index e227fd45..00000000 --- a/test/test_condition_variable_any_dispatch.cpp +++ /dev/null @@ -1,501 +0,0 @@ - -// 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 -#include -#include -#include -#include -#include -#include - -#include - -#include - -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/test/test_condition_variable_any_post.cpp b/test/test_condition_variable_any_post.cpp deleted file mode 100644 index da6d882a..00000000 --- a/test/test_condition_variable_any_post.cpp +++ /dev/null @@ -1,501 +0,0 @@ - -// 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 -#include -#include -#include -#include -#include -#include - -#include - -#include - -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/test/test_condition_variable_dispatch.cpp b/test/test_condition_variable_dispatch.cpp deleted file mode 100644 index dc5e00fe..00000000 --- a/test/test_condition_variable_dispatch.cpp +++ /dev/null @@ -1,495 +0,0 @@ - -// 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 -#include -#include -#include -#include -#include -#include -#include - -#include - -#include - -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 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/test/test_condition_variable_post.cpp b/test/test_condition_variable_post.cpp deleted file mode 100644 index 3f043a7b..00000000 --- a/test/test_condition_variable_post.cpp +++ /dev/null @@ -1,495 +0,0 @@ - -// 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 -#include -#include -#include -#include -#include -#include -#include - -#include - -#include - -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 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/test/test_fiber_dispatch.cpp b/test/test_fiber_dispatch.cpp deleted file mode 100644 index 0a05378a..00000000 --- a/test/test_fiber_dispatch.cpp +++ /dev/null @@ -1,436 +0,0 @@ - -// 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 -#include -#include -#include - -#include -#include - -#include - -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 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/test/test_fiber_post.cpp b/test/test_fiber_post.cpp deleted file mode 100644 index 67d9a6b2..00000000 --- a/test/test_fiber_post.cpp +++ /dev/null @@ -1,436 +0,0 @@ - -// 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 -#include -#include -#include - -#include -#include - -#include - -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 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/test/test_future_dispatch.cpp b/test/test_future_dispatch.cpp deleted file mode 100644 index 2990ec41..00000000 --- a/test/test_future_dispatch.cpp +++ /dev/null @@ -1,569 +0,0 @@ -// (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 -#include -#include -#include -#include - -#include - -#include - -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/test/test_future_post.cpp b/test/test_future_post.cpp deleted file mode 100644 index 01deb26f..00000000 --- a/test/test_future_post.cpp +++ /dev/null @@ -1,569 +0,0 @@ -// (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 -#include -#include -#include -#include - -#include - -#include - -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/test/test_mutex_dispatch.cpp b/test/test_mutex_dispatch.cpp deleted file mode 100644 index d0bb9112..00000000 --- a/test/test_mutex_dispatch.cpp +++ /dev/null @@ -1,144 +0,0 @@ - -// 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 -#include -#include -#include -#include -#include -#include - -#include - -#include - -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 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); - } -}; - -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(); -} - -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) ); - - return test; -} diff --git a/test/test_mutex_post.cpp b/test/test_mutex_post.cpp deleted file mode 100644 index c33ee4e8..00000000 --- a/test/test_mutex_post.cpp +++ /dev/null @@ -1,144 +0,0 @@ - -// 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 -#include -#include -#include -#include -#include -#include - -#include - -#include - -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 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); - } -}; - -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(); -} - -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) ); - - return test; -} diff --git a/test/test_shared_future_dispatch.cpp b/test/test_shared_future_dispatch.cpp deleted file mode 100644 index 2dd327ff..00000000 --- a/test/test_shared_future_dispatch.cpp +++ /dev/null @@ -1,608 +0,0 @@ -// (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 -#include -#include -#include -#include - -#include - -#include - -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/test/test_shared_future_post.cpp b/test/test_shared_future_post.cpp deleted file mode 100644 index 2e429f31..00000000 --- a/test/test_shared_future_post.cpp +++ /dev/null @@ -1,608 +0,0 @@ -// (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 -#include -#include -#include -#include - -#include - -#include - -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; -}