1 2 // Copyright Oliver Kowalke 2013. 3 // Distributed under the Boost Software License, Version 1.0. 4 // (See accompanying file LICENSE_1_0.txt or copy at 5 // http://www.boost.org/LICENSE_1_0.txt) 6 7 #ifndef BOOST_FIBERS_DETAIL_TASK_OBJECT_H 8 #define BOOST_FIBERS_DETAIL_TASK_OBJECT_H 9 10 #include <exception> 11 #include <memory> 12 #include <tuple> 13 #include <utility> 14 15 #include <boost/config.hpp> 16 #include <boost/context/detail/config.hpp> 17 #if defined(BOOST_NO_CXX17_STD_APPLY) 18 #include <boost/context/detail/apply.hpp> 19 #endif 20 #include <boost/core/pointer_traits.hpp> 21 22 #include <boost/fiber/detail/config.hpp> 23 #include <boost/fiber/future/detail/task_base.hpp> 24 25 #ifdef BOOST_HAS_ABI_HEADERS 26 # include BOOST_ABI_PREFIX 27 #endif 28 29 namespace boost { 30 namespace fibers { 31 namespace detail { 32 33 template< typename Fn, typename Allocator, typename R, typename ... Args > 34 class task_object : public task_base< R, Args ... > { 35 private: 36 typedef task_base< R, Args ... > base_type; 37 typedef std::allocator_traits< Allocator > allocator_traits; 38 39 public: 40 typedef typename allocator_traits::template rebind_alloc< 41 task_object 42 > allocator_type; 43 task_object(allocator_type const & alloc,Fn const & fn)44 task_object( allocator_type const& alloc, Fn const& fn) : 45 base_type{}, 46 fn_{ fn }, 47 alloc_{ alloc } { 48 } 49 task_object(allocator_type const & alloc,Fn && fn)50 task_object( allocator_type const& alloc, Fn && fn) : 51 base_type{}, 52 fn_{ std::move( fn) }, 53 alloc_{ alloc } { 54 } 55 run(Args &&...args)56 void run( Args && ... args) override final { 57 try { 58 this->set_value( 59 #if defined(BOOST_NO_CXX17_STD_APPLY) 60 boost::context::detail::apply( 61 fn_, std::make_tuple( std::forward< Args >( args) ... ) ) 62 #else 63 std::apply( 64 fn_, std::make_tuple( std::forward< Args >( args) ... ) ) 65 #endif 66 ); 67 #if defined(BOOST_CONTEXT_HAS_CXXABI_H) 68 } catch ( abi::__forced_unwind const&) { 69 throw; 70 #endif 71 } catch (...) { 72 this->set_exception( std::current_exception() ); 73 } 74 } 75 reset()76 typename base_type::ptr_type reset() override final { 77 typedef std::allocator_traits< allocator_type > traity_type; 78 typedef pointer_traits< typename traity_type::pointer> ptrait_type; 79 80 typename traity_type::pointer ptr{ traity_type::allocate( alloc_, 1) }; 81 typename ptrait_type::element_type* p = boost::to_address(ptr); 82 try { 83 traity_type::construct( alloc_, p, alloc_, std::move( fn_) ); 84 } catch (...) { 85 traity_type::deallocate( alloc_, ptr, 1); 86 throw; 87 } 88 return { p }; 89 } 90 91 protected: deallocate_future()92 void deallocate_future() noexcept override final { 93 destroy_( alloc_, this); 94 } 95 96 private: 97 Fn fn_; 98 allocator_type alloc_; 99 destroy_(allocator_type const & alloc,task_object * p)100 static void destroy_( allocator_type const& alloc, task_object * p) noexcept { 101 allocator_type a{ alloc }; 102 typedef std::allocator_traits< allocator_type > traity_type; 103 traity_type::destroy( a, p); 104 traity_type::deallocate( a, p, 1); 105 } 106 }; 107 108 template< typename Fn, typename Allocator, typename ... Args > 109 class task_object< Fn, Allocator, void, Args ... > : public task_base< void, Args ... > { 110 private: 111 typedef task_base< void, Args ... > base_type; 112 typedef std::allocator_traits< Allocator > allocator_traits; 113 114 public: 115 typedef typename allocator_traits::template rebind_alloc< 116 task_object< Fn, Allocator, void, Args ... > 117 > allocator_type; 118 task_object(allocator_type const & alloc,Fn const & fn)119 task_object( allocator_type const& alloc, Fn const& fn) : 120 base_type{}, 121 fn_{ fn }, 122 alloc_{ alloc } { 123 } 124 task_object(allocator_type const & alloc,Fn && fn)125 task_object( allocator_type const& alloc, Fn && fn) : 126 base_type{}, 127 fn_{ std::move( fn) }, 128 alloc_{ alloc } { 129 } 130 run(Args &&...args)131 void run( Args && ... args) override final { 132 try { 133 #if defined(BOOST_NO_CXX17_STD_APPLY) 134 boost::context::detail::apply( 135 fn_, std::make_tuple( std::forward< Args >( args) ... ) ); 136 #else 137 std::apply( 138 fn_, std::make_tuple( std::forward< Args >( args) ... ) ); 139 #endif 140 this->set_value(); 141 #if defined(BOOST_CONTEXT_HAS_CXXABI_H) 142 } catch ( abi::__forced_unwind const&) { 143 throw; 144 #endif 145 } catch (...) { 146 this->set_exception( std::current_exception() ); 147 } 148 } 149 reset()150 typename base_type::ptr_type reset() override final { 151 typedef std::allocator_traits< allocator_type > traity_type; 152 typedef pointer_traits< typename traity_type::pointer> ptrait_type; 153 154 typename traity_type::pointer ptr{ traity_type::allocate( alloc_, 1) }; 155 typename ptrait_type::element_type* p = boost::to_address(ptr); 156 try { 157 traity_type::construct( alloc_, p, alloc_, std::move( fn_) ); 158 } catch (...) { 159 traity_type::deallocate( alloc_, ptr, 1); 160 throw; 161 } 162 return { p }; 163 } 164 165 protected: deallocate_future()166 void deallocate_future() noexcept override final { 167 destroy_( alloc_, this); 168 } 169 170 private: 171 Fn fn_; 172 allocator_type alloc_; 173 destroy_(allocator_type const & alloc,task_object * p)174 static void destroy_( allocator_type const& alloc, task_object * p) noexcept { 175 allocator_type a{ alloc }; 176 typedef std::allocator_traits< allocator_type > traity_type; 177 traity_type::destroy( a, p); 178 traity_type::deallocate( a, p, 1); 179 } 180 }; 181 182 }}} 183 184 #ifdef BOOST_HAS_ABI_HEADERS 185 # include BOOST_ABI_SUFFIX 186 #endif 187 188 #endif // BOOST_FIBERS_DETAIL_TASK_OBJECT_H 189