File indexing completed on 2025-09-18 08:37:39
0001
0002
0003
0004
0005
0006
0007 #ifndef BOOST_FIBERS_CONTEXT_H
0008 #define BOOST_FIBERS_CONTEXT_H
0009
0010 #include <atomic>
0011 #include <chrono>
0012 #include <cstdint>
0013 #include <exception>
0014 #include <functional>
0015 #include <iostream>
0016 #include <map>
0017 #include <memory>
0018 #include <tuple>
0019 #include <type_traits>
0020 #include <utility>
0021
0022 #include <boost/assert.hpp>
0023 #include <boost/config.hpp>
0024 #include <boost/core/ignore_unused.hpp>
0025 #if defined(BOOST_NO_CXX17_STD_APPLY)
0026 #include <boost/context/detail/apply.hpp>
0027 #endif
0028 #include <boost/context/fiber.hpp>
0029 #include <boost/context/stack_context.hpp>
0030 #include <boost/intrusive/list.hpp>
0031 #include <boost/intrusive/parent_from_member.hpp>
0032 #include <boost/intrusive_ptr.hpp>
0033 #include <boost/intrusive/set.hpp>
0034 #include <boost/intrusive/slist.hpp>
0035
0036 #include <boost/fiber/detail/config.hpp>
0037 #include <boost/fiber/detail/data.hpp>
0038 #include <boost/fiber/detail/decay_copy.hpp>
0039 #include <boost/fiber/detail/fss.hpp>
0040 #include <boost/fiber/detail/spinlock.hpp>
0041 #include <boost/fiber/exceptions.hpp>
0042 #include <boost/fiber/fixedsize_stack.hpp>
0043 #include <boost/fiber/policy.hpp>
0044 #include <boost/fiber/properties.hpp>
0045 #include <boost/fiber/segmented_stack.hpp>
0046 #include <boost/fiber/type.hpp>
0047 #include <boost/fiber/waker.hpp>
0048 #include <boost/fiber/stack_allocator_wrapper.hpp>
0049 #include <boost/fiber/algo/algorithm.hpp>
0050
0051 #ifdef BOOST_HAS_ABI_HEADERS
0052 # include BOOST_ABI_PREFIX
0053 #endif
0054
0055 #ifdef _MSC_VER
0056 # pragma warning(push)
0057 # pragma warning(disable:4251)
0058 #endif
0059
0060 namespace boost {
0061 namespace fibers {
0062
0063 class context;
0064 class fiber;
0065 class scheduler;
0066
0067 namespace detail {
0068
0069 struct ready_tag;
0070 typedef intrusive::list_member_hook<
0071 intrusive::tag< ready_tag >,
0072 intrusive::link_mode<
0073 intrusive::auto_unlink
0074 >
0075 > ready_hook;
0076
0077 struct sleep_tag;
0078 typedef intrusive::set_member_hook<
0079 intrusive::tag< sleep_tag >,
0080 intrusive::link_mode<
0081 intrusive::auto_unlink
0082 >
0083 > sleep_hook;
0084
0085 struct worker_tag;
0086 typedef intrusive::list_member_hook<
0087 intrusive::tag< worker_tag >,
0088 intrusive::link_mode<
0089 intrusive::auto_unlink
0090 >
0091 > worker_hook;
0092
0093 struct terminated_tag;
0094 typedef intrusive::slist_member_hook<
0095 intrusive::tag< terminated_tag >,
0096 intrusive::link_mode<
0097 intrusive::safe_link
0098 >
0099 > terminated_hook;
0100
0101 struct remote_ready_tag;
0102 typedef intrusive::slist_member_hook<
0103 intrusive::tag< remote_ready_tag >,
0104 intrusive::link_mode<
0105 intrusive::safe_link
0106 >
0107 > remote_ready_hook;
0108
0109 }
0110
0111 class BOOST_FIBERS_DECL context {
0112 private:
0113 friend class dispatcher_context;
0114 friend class main_context;
0115 template< typename Fn, typename ... Arg > friend class worker_context;
0116 friend class scheduler;
0117
0118 struct fss_data {
0119 void * vp{ nullptr };
0120 detail::fss_cleanup_function::ptr_t cleanup_function{};
0121
0122 fss_data() = default;
0123
0124 fss_data( void * vp_,
0125 detail::fss_cleanup_function::ptr_t fn) noexcept :
0126 vp( vp_),
0127 cleanup_function(std::move( fn)) {
0128 BOOST_ASSERT( cleanup_function);
0129 }
0130
0131 void do_cleanup() {
0132 ( * cleanup_function)( vp);
0133 }
0134 };
0135
0136 typedef std::map< uintptr_t, fss_data > fss_data_t;
0137
0138 #if ! defined(BOOST_FIBERS_NO_ATOMICS)
0139 std::atomic< std::size_t > use_count_;
0140 #else
0141 std::size_t use_count_;
0142 #endif
0143 #if ! defined(BOOST_FIBERS_NO_ATOMICS)
0144 detail::remote_ready_hook remote_ready_hook_{};
0145 #endif
0146 detail::spinlock splk_{};
0147 bool terminated_{ false };
0148 wait_queue wait_queue_{};
0149 public:
0150 #if ! defined(BOOST_FIBERS_NO_ATOMICS)
0151 std::atomic<size_t> waker_epoch_{ 0 };
0152 #endif
0153 private:
0154 scheduler * scheduler_{ nullptr };
0155 fss_data_t fss_data_{};
0156 detail::sleep_hook sleep_hook_{};
0157 waker sleep_waker_{};
0158 detail::ready_hook ready_hook_{};
0159 detail::terminated_hook terminated_hook_{};
0160 detail::worker_hook worker_hook_{};
0161 fiber_properties * properties_{ nullptr };
0162 boost::context::fiber c_{};
0163 std::chrono::steady_clock::time_point tp_;
0164 type type_;
0165 launch policy_;
0166
0167 context( std::size_t initial_count, type t, launch policy) noexcept :
0168 use_count_{ initial_count },
0169 tp_{ (std::chrono::steady_clock::time_point::max)() },
0170 type_{ t },
0171 policy_{ policy } {
0172 }
0173
0174 public:
0175 class id {
0176 private:
0177 friend std::hash<id>;
0178 context * impl_{ nullptr };
0179
0180 public:
0181 id() = default;
0182
0183 explicit id( context * impl) noexcept :
0184 impl_{ impl } {
0185 }
0186
0187 bool operator==( id const& other) const noexcept {
0188 return impl_ == other.impl_;
0189 }
0190
0191 bool operator!=( id const& other) const noexcept {
0192 return impl_ != other.impl_;
0193 }
0194
0195 bool operator<( id const& other) const noexcept {
0196 return impl_ < other.impl_;
0197 }
0198
0199 bool operator>( id const& other) const noexcept {
0200 return other.impl_ < impl_;
0201 }
0202
0203 bool operator<=( id const& other) const noexcept {
0204 return ! ( * this > other);
0205 }
0206
0207 bool operator>=( id const& other) const noexcept {
0208 return ! ( * this < other);
0209 }
0210
0211 template< typename charT, class traitsT >
0212 friend std::basic_ostream< charT, traitsT > &
0213 operator<<( std::basic_ostream< charT, traitsT > & os, id const& other) {
0214 if ( nullptr != other.impl_) {
0215 return os << other.impl_;
0216 }
0217 return os << "{not-valid}";
0218 }
0219
0220 explicit operator bool() const noexcept {
0221 return nullptr != impl_;
0222 }
0223
0224 bool operator!() const noexcept {
0225 return nullptr == impl_;
0226 }
0227 };
0228
0229
0230 static bool initialize_thread(algo::algorithm::ptr_t algo, stack_allocator_wrapper&& salloc) noexcept;
0231
0232 static context * active() noexcept;
0233
0234 static void reset_active() noexcept;
0235
0236 context( context const&) = delete;
0237 context( context &&) = delete;
0238 context & operator=( context const&) = delete;
0239 context & operator=( context &&) = delete;
0240
0241 #if !defined(BOOST_EMBTC)
0242
0243 friend bool
0244 operator==( context const& lhs, context const& rhs) noexcept {
0245 return & lhs == & rhs;
0246 }
0247
0248 #else
0249
0250 friend bool
0251 operator==( context const& lhs, context const& rhs) noexcept;
0252
0253 #endif
0254
0255 virtual ~context();
0256
0257 scheduler * get_scheduler() const noexcept {
0258 return scheduler_;
0259 }
0260
0261 id get_id() const noexcept;
0262
0263 bool is_resumable() const noexcept {
0264 return static_cast<bool>(c_);
0265 }
0266
0267 void resume() noexcept;
0268 void resume( detail::spinlock_lock &) noexcept;
0269 void resume( context *) noexcept;
0270
0271 void suspend() noexcept;
0272 void suspend( detail::spinlock_lock &) noexcept;
0273
0274 boost::context::fiber suspend_with_cc() noexcept;
0275 boost::context::fiber terminate() noexcept;
0276
0277 void join();
0278
0279 void yield() noexcept;
0280
0281 bool wait_until( std::chrono::steady_clock::time_point const&) noexcept;
0282 bool wait_until( std::chrono::steady_clock::time_point const&,
0283 detail::spinlock_lock &,
0284 waker &&) noexcept;
0285
0286 bool wake(const size_t) noexcept;
0287
0288 waker create_waker() noexcept {
0289
0290 return { this, ++waker_epoch_ };
0291 }
0292
0293 void schedule( context *) noexcept;
0294
0295 bool is_context( type t) const noexcept {
0296 return type::none != ( type_ & t);
0297 }
0298
0299 void * get_fss_data( void const * vp) const;
0300
0301 void set_fss_data(
0302 void const * vp,
0303 detail::fss_cleanup_function::ptr_t const& cleanup_fn,
0304 void * data,
0305 bool cleanup_existing);
0306
0307 void set_properties( fiber_properties * props) noexcept;
0308
0309 fiber_properties * get_properties() const noexcept {
0310 return properties_;
0311 }
0312
0313 launch get_policy() const noexcept {
0314 return policy_;
0315 }
0316
0317 bool worker_is_linked() const noexcept;
0318
0319 bool ready_is_linked() const noexcept;
0320
0321 bool remote_ready_is_linked() const noexcept;
0322
0323 bool sleep_is_linked() const noexcept;
0324
0325 bool terminated_is_linked() const noexcept;
0326
0327 template< typename List >
0328 void worker_link( List & lst) noexcept {
0329 static_assert( std::is_same< typename List::value_traits::hook_type, detail::worker_hook >::value, "not a worker-queue");
0330 BOOST_ASSERT( ! worker_is_linked() );
0331 lst.push_back( * this);
0332 }
0333
0334 template< typename List >
0335 void ready_link( List & lst) noexcept {
0336 static_assert( std::is_same< typename List::value_traits::hook_type, detail::ready_hook >::value, "not a ready-queue");
0337 BOOST_ASSERT( ! ready_is_linked() );
0338 lst.push_back( * this);
0339 }
0340
0341 template< typename List >
0342 void remote_ready_link( List & lst) noexcept {
0343 static_assert( std::is_same< typename List::value_traits::hook_type, detail::remote_ready_hook >::value, "not a remote-ready-queue");
0344 BOOST_ASSERT( ! remote_ready_is_linked() );
0345 lst.push_back( * this);
0346 }
0347
0348 template< typename Set >
0349 void sleep_link( Set & set) noexcept {
0350 static_assert( std::is_same< typename Set::value_traits::hook_type,detail::sleep_hook >::value, "not a sleep-queue");
0351 BOOST_ASSERT( ! sleep_is_linked() );
0352 set.insert( * this);
0353 }
0354
0355 template< typename List >
0356 void terminated_link( List & lst) noexcept {
0357 static_assert( std::is_same< typename List::value_traits::hook_type, detail::terminated_hook >::value, "not a terminated-queue");
0358 BOOST_ASSERT( ! terminated_is_linked() );
0359 lst.push_back( * this);
0360 }
0361
0362 void worker_unlink() noexcept;
0363
0364 void ready_unlink() noexcept;
0365
0366 void sleep_unlink() noexcept;
0367
0368 void detach() noexcept;
0369
0370 void attach( context *) noexcept;
0371
0372 #if !defined(BOOST_EMBTC)
0373
0374 friend void intrusive_ptr_add_ref( context * ctx) noexcept {
0375 BOOST_ASSERT( nullptr != ctx);
0376 ctx->use_count_.fetch_add( 1, std::memory_order_relaxed);
0377 }
0378
0379 friend void intrusive_ptr_release( context * ctx) noexcept {
0380 BOOST_ASSERT( nullptr != ctx);
0381 if ( 1 == ctx->use_count_.fetch_sub( 1, std::memory_order_release) ) {
0382 std::atomic_thread_fence( std::memory_order_acquire);
0383 boost::context::fiber c = std::move( ctx->c_);
0384
0385 ctx->~context();
0386
0387 std::move( c).resume();
0388 }
0389 }
0390
0391 #else
0392
0393 friend void intrusive_ptr_add_ref( context * ctx) noexcept;
0394 friend void intrusive_ptr_release( context * ctx) noexcept;
0395
0396 #endif
0397
0398 };
0399
0400 #if defined(BOOST_EMBTC)
0401
0402 inline bool
0403 operator==( context const& lhs, context const& rhs) noexcept {
0404 return & lhs == & rhs;
0405 }
0406
0407 inline void intrusive_ptr_add_ref( context * ctx) noexcept {
0408 BOOST_ASSERT( nullptr != ctx);
0409 ctx->use_count_.fetch_add( 1, std::memory_order_relaxed);
0410 }
0411
0412 inline void intrusive_ptr_release( context * ctx) noexcept {
0413 BOOST_ASSERT( nullptr != ctx);
0414 if ( 1 == ctx->use_count_.fetch_sub( 1, std::memory_order_release) ) {
0415 std::atomic_thread_fence( std::memory_order_acquire);
0416 boost::context::fiber c = std::move( ctx->c_);
0417
0418 ctx->~context();
0419
0420 std::move( c).resume();
0421 }
0422 }
0423
0424 #endif
0425
0426 inline
0427 bool operator<( context const& l, context const& r) noexcept {
0428 return l.get_id() < r.get_id();
0429 }
0430
0431 template< typename Fn, typename ... Arg >
0432 class worker_context final : public context {
0433 private:
0434 typename std::decay< Fn >::type fn_;
0435 std::tuple< Arg ... > arg_;
0436
0437 boost::context::fiber
0438 run_( boost::context::fiber && c) {
0439 {
0440
0441 auto fn = std::move( fn_);
0442 auto arg = std::move( arg_);
0443 #if (defined(BOOST_USE_UCONTEXT)||defined(BOOST_USE_WINFIB))
0444 std::move( c).resume();
0445 #else
0446 boost::ignore_unused(c);
0447 #endif
0448 #if defined(BOOST_NO_CXX17_STD_APPLY)
0449 boost::context::detail::apply( std::move( fn), std::move( arg) );
0450 #else
0451 std::apply( std::move( fn), std::move( arg) );
0452 #endif
0453 }
0454
0455 return terminate();
0456 }
0457
0458 public:
0459 template< typename StackAlloc >
0460 worker_context( launch policy,
0461 fiber_properties* properties,
0462 boost::context::preallocated const& palloc, StackAlloc && salloc,
0463 Fn && fn, Arg ... arg) :
0464 context{ 1, type::worker_context, policy },
0465 fn_( std::forward< Fn >( fn) ),
0466 arg_( std::forward< Arg >( arg) ... ) {
0467 if ( properties != nullptr ) {
0468 set_properties(properties);
0469 properties->set_context(this);
0470 }
0471 c_ = boost::context::fiber{ std::allocator_arg, palloc, std::forward< StackAlloc >( salloc),
0472 std::bind( & worker_context::run_, this, std::placeholders::_1) };
0473 #if (defined(BOOST_USE_UCONTEXT)||defined(BOOST_USE_WINFIB))
0474 c_ = std::move( c_).resume();
0475 #endif
0476 }
0477
0478 template< typename StackAlloc >
0479 worker_context( launch policy,
0480 boost::context::preallocated const& palloc, StackAlloc && salloc,
0481 Fn && fn, Arg ... arg) :
0482 worker_context( policy, palloc, salloc, nullptr, std::forward<Fn>( fn ), std::forward<Arg>( arg ) ... ){
0483 }
0484 };
0485
0486
0487 template< typename StackAlloc, typename Fn, typename ... Arg >
0488 static intrusive_ptr< context > make_worker_context_with_properties( launch policy,
0489 fiber_properties* properties,
0490 StackAlloc && salloc,
0491 Fn && fn, Arg ... arg) {
0492 typedef worker_context< Fn, Arg ... > context_t;
0493
0494 auto sctx = salloc.allocate();
0495
0496 void * storage = reinterpret_cast< void * >(
0497 ( reinterpret_cast< uintptr_t >( sctx.sp) - static_cast< uintptr_t >( sizeof( context_t) ) )
0498 & ~ static_cast< uintptr_t >( 0xff) );
0499 void * stack_bottom = reinterpret_cast< void * >(
0500 reinterpret_cast< uintptr_t >( sctx.sp) - static_cast< uintptr_t >( sctx.size) );
0501 const std::size_t size = reinterpret_cast< uintptr_t >( storage) - reinterpret_cast< uintptr_t >( stack_bottom);
0502
0503 return intrusive_ptr< context >{
0504 new ( storage) context_t{
0505 policy,
0506 properties,
0507 boost::context::preallocated{ storage, size, sctx },
0508 std::forward< StackAlloc >( salloc),
0509 std::forward< Fn >( fn),
0510 std::forward< Arg >( arg) ... } };
0511 }
0512
0513 template< typename StackAlloc, typename Fn, typename ... Arg >
0514 static intrusive_ptr< context > make_worker_context( launch policy,
0515 StackAlloc && salloc,
0516 Fn && fn, Arg ... arg){
0517 return make_worker_context_with_properties( policy, nullptr, std::forward<StackAlloc>(salloc),
0518 std::forward<Fn>( fn ), std::forward<Arg>( arg ) ... );
0519 }
0520
0521
0522 }}
0523
0524
0525 namespace std {
0526
0527 template <>
0528 struct hash< ::boost::fibers::context::id > {
0529 std::size_t
0530 operator() ( ::boost::fibers::context::id const& id ) const noexcept;
0531 };
0532
0533 }
0534
0535 #ifdef _MSC_VER
0536 # pragma warning(pop)
0537 #endif
0538
0539 #ifdef BOOST_HAS_ABI_HEADERS
0540 # include BOOST_ABI_SUFFIX
0541 #endif
0542
0543 #endif