From 310f3ce2f245a3e87696b1bb8f89c012d268aa88 Mon Sep 17 00:00:00 2001 From: Oliver Kowalke Date: Fri, 13 May 2016 20:14:48 +0200 Subject: [PATCH] move sched_algorithm to algo::algorithm - new namesapce algo - shared_round_robin with shared ready queue --- build/Jamfile.v2 | 5 +- doc/barrier.qbk | 21 ++- doc/channel.qbk | 140 ++++++++-------- doc/condition_variables.qbk | 59 +++---- doc/customization.qbk | 6 +- doc/fiber.qbk | 59 +++++-- doc/fibers.qbk | 6 +- doc/fls.qbk | 5 + doc/future.qbk | 19 +++ doc/integration.qbk | 6 +- doc/migration.qbk | 4 +- doc/mutexes.qbk | 20 +++ doc/packaged_task.qbk | 7 + doc/promise.qbk | 7 + doc/scheduling.qbk | 152 +++++++++++------- doc/stack.qbk | 22 +++ examples/asio/autoecho.cpp | 1 + examples/asio/round_robin.hpp | 2 +- examples/priority.cpp | 12 +- examples/work_sharing.cpp | 86 +--------- examples/work_stealing.cpp | 4 +- include/boost/fiber/{ => algo}/algorithm.hpp | 32 ++-- .../boost/fiber/{ => algo}/round_robin.hpp | 19 +-- .../boost/fiber/algo/shared_round_robin.hpp | 77 +++++++++ include/boost/fiber/all.hpp | 4 +- include/boost/fiber/operations.hpp | 6 +- include/boost/fiber/properties.hpp | 17 +- include/boost/fiber/scheduler.hpp | 6 +- performance/fiber/skynet_shared.cpp | 82 ++-------- src/{ => algo}/algorithm.cpp | 9 +- src/{ => algo}/round_robin.cpp | 15 +- src/algo/shared_round_robin.cpp | 101 ++++++++++++ src/properties.cpp | 6 +- src/scheduler.cpp | 28 ++-- 34 files changed, 637 insertions(+), 408 deletions(-) rename include/boost/fiber/{ => algo}/algorithm.hpp (79%) rename include/boost/fiber/{ => algo}/round_robin.hpp (77%) create mode 100644 include/boost/fiber/algo/shared_round_robin.hpp rename src/{ => algo}/algorithm.cpp (69%) rename src/{ => algo}/round_robin.cpp (86%) create mode 100644 src/algo/shared_round_robin.cpp diff --git a/build/Jamfile.v2 b/build/Jamfile.v2 index 54a1ee59..fdb2fbb9 100644 --- a/build/Jamfile.v2 +++ b/build/Jamfile.v2 @@ -27,7 +27,9 @@ project boost/fiber ; lib boost_fiber - : algorithm.cpp + : algo/algorithm.cpp + algo/round_robin.cpp + algo/shared_round_robin.cpp barrier.cpp condition_variable.cpp context.cpp @@ -38,7 +40,6 @@ lib boost_fiber properties.cpp recursive_mutex.cpp recursive_timed_mutex.cpp - round_robin.cpp timed_mutex.cpp scheduler.cpp : shared:../../context/build//boost_context diff --git a/doc/barrier.qbk b/doc/barrier.qbk index 510808d9..1ccbe61d 100644 --- a/doc/barrier.qbk +++ b/doc/barrier.qbk @@ -48,17 +48,22 @@ members in the barrier object.] [class_heading barrier] - #include + #include - class barrier { - public: - explicit barrier( std::size_t); + namespace boost { + namespace fibers { - barrier( barrier const&) = delete; - barrier & operator=( barrier const&) = delete; + class barrier { + public: + explicit barrier( std::size_t); - bool wait(); - }; + barrier( barrier const&) = delete; + barrier & operator=( barrier const&) = delete; + + bool wait(); + }; + + }} Instances of __barrier__ are not copyable or movable. diff --git a/doc/channel.qbk b/doc/channel.qbk index 70f32169..1f3437d9 100644 --- a/doc/channel.qbk +++ b/doc/channel.qbk @@ -73,35 +73,40 @@ channel operations return the state of the channel. [template_heading unbounded_channel] - #include + #include - template< typename T, typename __Allocator__ = __allocator__ > - class unbounded_channel { - public: - typedef T value_type; + namespace boost { + namespace fibers { - explicit unbounded_channel( __Allocator__ const& alloc = Allocator() ) noexcept; + template< typename T, typename __Allocator__ = __allocator__ > + class unbounded_channel { + public: + typedef T value_type; - unbounded_channel( unbounded_channel const& other) = delete; - unbounded_channel & operator=( unbounded_channel const& other) = delete; + explicit unbounded_channel( __Allocator__ const& alloc = Allocator() ) noexcept; - void close() noexcept; + unbounded_channel( unbounded_channel const& other) = delete; + unbounded_channel & operator=( unbounded_channel const& other) = delete; - channel_op_status push( value_type const& va); - channel_op_status push( value_type && va); + void close() noexcept; - channel_op_status pop( value_type & va); - value_type value_pop(); - channel_op_status try_pop( value_type & va); - template< typename Rep, typename Period > - channel_op_status pop_wait_for( - value_type & va, - std::chrono::duration< Rep, Period > const& timeout_duration); - template< typename Clock, typename Duration > - channel_op_status pop_wait_until( - value_type & va, - std::chrono::time_point< Clock, Duration > const& timeout_time); - }; + channel_op_status push( value_type const& va); + channel_op_status push( value_type && va); + + channel_op_status pop( value_type & va); + value_type value_pop(); + channel_op_status try_pop( value_type & va); + template< typename Rep, typename Period > + channel_op_status pop_wait_for( + value_type & va, + std::chrono::duration< Rep, Period > const& timeout_duration); + template< typename Clock, typename Duration > + channel_op_status pop_wait_until( + value_type & va, + std::chrono::time_point< Clock, Duration > const& timeout_time); + }; + + }} [heading Constructor] @@ -234,55 +239,60 @@ time as (system time + `timeout_duration`). [template_heading bounded_channel] - #include + #include - template< typename T, typename __Allocator__ = __allocator__ > - class bounded_channel { - public: - typedef T value_type; + namespace boost { + namespace fibers { - bounded_channel( std::size_t wm, __Allocator__ const& alloc = Allocator() ); - bounded_channel( std::size_t hwm, std::size_t lwm, __Allocator__ const& alloc = Allocator() ); + template< typename T, typename __Allocator__ = __allocator__ > + class bounded_channel { + public: + typedef T value_type; - bounded_channel( bounded_channel const& other) = delete; - bounded_channel & operator=( bounded_channel const& other) = delete; + bounded_channel( std::size_t wm, __Allocator__ const& alloc = Allocator() ); + bounded_channel( std::size_t hwm, std::size_t lwm, __Allocator__ const& alloc = Allocator() ); - std::size_t upper_bound() const noexcept; - std::size_t lower_bound() const noexcept; + bounded_channel( bounded_channel const& other) = delete; + bounded_channel & operator=( bounded_channel const& other) = delete; - void close() noexcept; + std::size_t upper_bound() const noexcept; + std::size_t lower_bound() const noexcept; - channel_op_status push( value_type const& va); - channel_op_status push( value_type && va); - template< typename Rep, typename Period > - channel_op_status push_wait_for( - value_type const& va, - std::chrono::duration< Rep, Period > const& timeout_duration); - channel_op_status push_wait_for( value_type && va, - std::chrono::duration< Rep, Period > const& timeout_duration); - template< typename Clock, typename Duration > - channel_op_status push_wait_until( - value_type const& va, - std::chrono::time_point< Clock, Duration > const& timeout_time); - template< typename Clock, typename Duration > - channel_op_status push_wait_until( - value_type && va, - std::chrono::time_point< Clock, Duration > const& timeout_time); - channel_op_status try_push( value_type const& va); - channel_op_status try_push( value_type && va); + void close() noexcept; - channel_op_status pop( value_type & va); - value_type value_pop(); - template< typename Rep, typename Period > - channel_op_status pop_wait_for( - value_type & va, - std::chrono::duration< Rep, Period > const& timeout_duration); - template< typename Clock, typename Duration > - channel_op_status pop_wait_until( - value_type & va, - std::chrono::time_point< Clock, Duration > const& timeout_time); - channel_op_status try_pop( value_type & va); - }; + channel_op_status push( value_type const& va); + channel_op_status push( value_type && va); + template< typename Rep, typename Period > + channel_op_status push_wait_for( + value_type const& va, + std::chrono::duration< Rep, Period > const& timeout_duration); + channel_op_status push_wait_for( value_type && va, + std::chrono::duration< Rep, Period > const& timeout_duration); + template< typename Clock, typename Duration > + channel_op_status push_wait_until( + value_type const& va, + std::chrono::time_point< Clock, Duration > const& timeout_time); + template< typename Clock, typename Duration > + channel_op_status push_wait_until( + value_type && va, + std::chrono::time_point< Clock, Duration > const& timeout_time); + channel_op_status try_push( value_type const& va); + channel_op_status try_push( value_type && va); + + channel_op_status pop( value_type & va); + value_type value_pop(); + template< typename Rep, typename Period > + channel_op_status pop_wait_for( + value_type & va, + std::chrono::duration< Rep, Period > const& timeout_duration); + template< typename Clock, typename Duration > + channel_op_status pop_wait_until( + value_type & va, + std::chrono::time_point< Clock, Duration > const& timeout_time); + channel_op_status try_pop( value_type & va); + }; + + }} [heading Constructor] diff --git a/doc/condition_variables.qbk b/doc/condition_variables.qbk index a321bb23..b7f2dd0d 100644 --- a/doc/condition_variables.qbk +++ b/doc/condition_variables.qbk @@ -156,42 +156,47 @@ A timed wait operation might return because of timeout or not. [template condition_variable_x[classname locktype template_rtype template_arg] [class_heading [classname]] - #include + #include - class ``[classname]`` { - public: - ``[classname]``(); - ~``[classname]``(); + namespace boost { + namespace fibers { - ``[classname]``( ``[classname]`` const&) = delete; - ``[classname]`` & operator=( ``[classname]`` const&) = delete; + class ``[classname]`` { + public: + ``[classname]``(); + ~``[classname]``(); - void notify_one() noexcept; - void notify_all() noexcept; + ``[classname]``( ``[classname]`` const&) = delete; + ``[classname]`` & operator=( ``[classname]`` const&) = delete; - ``[template_rtype]`` wait( ``[locktype]`` &); + void notify_one() noexcept; + void notify_all() noexcept; - template< ``[template_arg]`` Pred > - void wait( ``[locktype]`` &, Pred); + ``[template_rtype]`` wait( ``[locktype]`` &); - template< ``[template_arg]`` Clock, typename Duration > - cv_status wait_until( ``[locktype]`` &, - std::chrono::time_point< Clock, Duration > const&); + template< ``[template_arg]`` Pred > + void wait( ``[locktype]`` &, Pred); - template< ``[template_arg]`` Clock, typename Duration, typename Pred > - bool wait_until( ``[locktype]`` &, - std::chrono::time_point< Clock, Duration > const&, - Pred); + template< ``[template_arg]`` Clock, typename Duration > + cv_status wait_until( ``[locktype]`` &, + std::chrono::time_point< Clock, Duration > const&); - template< ``[template_arg]`` Rep, typename Period > - cv_status wait_for( ``[locktype]`` &, - std::chrono::duration< Rep, Period > const&); + template< ``[template_arg]`` Clock, typename Duration, typename Pred > + bool wait_until( ``[locktype]`` &, + std::chrono::time_point< Clock, Duration > const&, + Pred); - template< ``[template_arg]`` Rep, typename Period, typename Pred > - bool wait_for( ``[locktype]`` &, - std::chrono::duration< Rep, Period > const&, - Pred); - }; + template< ``[template_arg]`` Rep, typename Period > + cv_status wait_for( ``[locktype]`` &, + std::chrono::duration< Rep, Period > const&); + + template< ``[template_arg]`` Rep, typename Period, typename Pred > + bool wait_for( ``[locktype]`` &, + std::chrono::duration< Rep, Period > const&, + Pred); + }; + + }} [heading Constructor] diff --git a/doc/customization.qbk b/doc/customization.qbk index 8be85568..e9b97d48 100644 --- a/doc/customization.qbk +++ b/doc/customization.qbk @@ -72,13 +72,13 @@ fiber_properties]. [heading Custom Scheduler Class] Now we can derive a custom scheduler from [template_link -sched_algorithm_with_properties], specifying our custom property class +algorithm_with_properties], specifying our custom property class `priority_props` as the template parameter. [priority_scheduler] Our example `priority_scheduler` doesn't override [member_link -sched_algorithm_with_properties..new_properties]: we're content with +algorithm_with_properties..new_properties]: we're content with allocating `priority_props` instances on the heap. [heading Replace Default Scheduler] @@ -114,6 +114,6 @@ until it blocks (or yields, or terminates) for some other reason. As shown in the `launch()` function above, it is reasonable to launch a fiber and immediately set relevant properties -- such as, for instance, its priority. Your custom scheduler can then make use of this information next time the -fiber manager calls [member_link sched_algorithm_with_properties..pick_next]. +fiber manager calls [member_link algorithm_with_properties..pick_next]. [endsect] diff --git a/doc/fiber.qbk b/doc/fiber.qbk index d83a9d39..4e315885 100644 --- a/doc/fiber.qbk +++ b/doc/fiber.qbk @@ -20,14 +20,18 @@ bool operator<( fiber const& l, fiber const& r) noexcept; void swap( fiber & l, fiber & r) noexcept; - struct sched_algorithm; - template< typename PROPS > - struct sched_algorithm_with_properties; - class round_robin; template< typename SchedAlgo, typename ... Args > void use_scheduling_algorithm( Args && ... args); bool has_ready_fibers(); + namespace algo { + + struct algorithm; + template< typename PROPS > + struct algorithm_with_properties; + class round_robin; + class shared_round_robin; + } namespace this_fiber { @@ -195,6 +199,9 @@ be entered when the fiber scheduler has a chance to resume it later.]] #include + namespace boost { + namespace fibers { + class fiber { public: class id; @@ -246,6 +253,8 @@ be entered when the fiber scheduler has a chance to resume it later.]] bool has_ready_fibers() noexcept; + }} + [heading Default constructor] @@ -385,13 +394,13 @@ default-constructed __fiber_id__.]] [variablelist [[Preconditions:] [`*this` refers to a fiber of execution. [function_link use_scheduling_algorithm] has been called from this thread with a subclass of -[template_link sched_algorithm_with_properties] with the same template +[template_link algorithm_with_properties] with the same template argument `PROPS`.]] [[Returns:] [a reference to the scheduler properties instance for `*this`.]] [[Throws:] [`std::bad_cast` if `use_scheduling_algorithm()` was called with a -`sched_algorithm_with_properties` subclass with some other template parameter +`algorithm_with_properties` subclass with some other template parameter than `PROPS`.]] -[[Note:] [[template_link sched_algorithm_with_properties] provides a way for a +[[Note:] [[template_link algorithm_with_properties] provides a way for a user-coded scheduler to associate extended properties, such as priority, with a fiber instance. This method allows access to those user-provided properties.]] [[See also:] [[link custom Customization]]] @@ -466,6 +475,9 @@ create a default [class_link round_robin] instance for this thread.]] #include + namespace boost { + namespace fibers { + class id { public: constexpr id() noexcept; @@ -487,6 +499,8 @@ create a default [class_link round_robin] instance for this thread.]] operator<<( std::basic_ostream< charT, traitsT > &, id const&); }; + }} + [heading Constructor] constexpr id() noexcept; @@ -596,8 +610,13 @@ explicitly-launched fiber. #include + namespace boost { + namespace fibers { + fiber::id get_id() noexcept; + }} + [variablelist [[Returns:] [An instance of __fiber_id__ that represents the currently executing fiber.]] @@ -608,9 +627,14 @@ executing fiber.]] #include + namespace boost { + namespace fibers { + template< typename Clock, typename Duration > void sleep_until( std::chrono::time_point< Clock, Duration > const& abs_time); + }} + [variablelist [[Effects:] [Suspends the current fiber until the time point specified by `abs_time` has been reached.]] @@ -628,9 +652,14 @@ exceptions are referred to as ['timeout-related exceptions.]]]] #include + namespace boost { + namespace fibers { + template< class Rep, class Period > void sleep_for( std::chrono::duration< Rep, Period > const& rel_time); + }} + [variablelist [[Effects:] [Suspends the current fiber until the time duration specified by `rel_time` has elapsed.]] @@ -643,8 +672,13 @@ there are no guarantees about how soon after that it might resume.]] #include + namespace boost { + namespace fibers { + void yield() noexcept; + }} + [variablelist [[Effects:] [Reliquishes execution control, allowing other fibers to run.]] [[Throws:] [Nothing.]] @@ -657,19 +691,24 @@ to run.]] #include + namespace boost { + namespace fibers { + template< typename PROPS > PROPS & properties(); + }} + [variablelist [[Preconditions:] [[function_link use_scheduling_algorithm] has been called from this thread with a subclass of [template_link -sched_algorithm_with_properties] with the same template argument `PROPS`.]] +algorithm_with_properties] with the same template argument `PROPS`.]] [[Returns:] [a reference to the scheduler properties instance for the currently running fiber.]] [[Throws:] [`std::bad_cast` if `use_scheduling_algorithm()` was called with a -`sched_algorithm_with_properties` subclass with some other template parameter +`algorithm_with_properties` subclass with some other template parameter than `PROPS`.]] -[[Note:] [[template_link sched_algorithm_with_properties] provides a way for a +[[Note:] [[template_link algorithm_with_properties] provides a way for a user-coded scheduler to associate extended properties, such as priority, with a fiber instance. This function allows access to those user-provided properties.]] diff --git a/doc/fibers.qbk b/doc/fibers.qbk index 8ceb4cb3..19954368 100644 --- a/doc/fibers.qbk +++ b/doc/fibers.qbk @@ -144,9 +144,9 @@ [def __already_retrieved__ `future_errc::future_already_retrieved`] [def __already_satisfied__ `future_errc::future_already_satisfied`] -[def __algo__ [class_link sched_algorithm]] -[def __algo_awakened__ [member_link sched_algorithm..awakened]] -[def __algo_pick_next__ [member_link sched_algorithm..pick_next]] +[def __algo__ [class_link algorithm]] +[def __algo_awakened__ [member_link algorithm..awakened]] +[def __algo_pick_next__ [member_link algorithm..pick_next]] [def __async__ `async()`] [def __barrier_wait__ [member_link barrier..wait]] [def __cond_wait_for__ [member_link condition_variable..wait_for]] diff --git a/doc/fls.qbk b/doc/fls.qbk index aec069a1..d4c610e0 100644 --- a/doc/fls.qbk +++ b/doc/fls.qbk @@ -26,6 +26,9 @@ order. #include + namespace boost { + namespace fibers { + template< typename T > class fiber_specific_ptr { public: @@ -51,6 +54,8 @@ order. void reset( T *); }; + }} + [heading Constructor] fiber_specific_ptr(); diff --git a/doc/future.qbk b/doc/future.qbk index 8606426d..014a55ca 100644 --- a/doc/future.qbk +++ b/doc/future.qbk @@ -55,6 +55,11 @@ Timed wait-operations (__wait_for__ and __wait_until__) return the state of the A __future__ contains a [link shared_state shared state] which is not shared with any other future. + #include + + namespace boost { + namespace fibers { + template< typename R > class future { public: @@ -91,6 +96,8 @@ A __future__ contains a [link shared_state shared state] which is not shared wit std::chrono::time_point< Clock, Duration > const& timeout_time) const; }; + }} + [heading Default constructor] future() noexcept; @@ -257,6 +264,11 @@ timeout-related exceptions.]] A __shared_future__ contains a [link shared_state shared state] which might be shared with other __shared_future__ instances. + #include + + namespace boost { + namespace fibers { + template< typename R > class shared_future { public: @@ -295,6 +307,8 @@ shared with other __shared_future__ instances. std::chrono::time_point< Clock, Duration > const& timeout_time) const; }; + }} + [heading Default constructor] shared_future(); @@ -352,6 +366,9 @@ const&`, otherwise `false`.]] #include + namespace boost { + namespace fibers { + template< class Function, class ... Args > future< std::result_of_t< @@ -377,6 +394,8 @@ const&`, otherwise `false`.]] async( ``[link class_launch `launch`]`` policy, __allocator_arg_t__, __StackAllocator__ salloc, Function && fn, Args && ... args); + }} + [variablelist [[Effects:] [Executes `fn` in a [class_link fiber] and returns an associated [template_link future].]] diff --git a/doc/integration.qbk b/doc/integration.qbk index 6d2080b0..01553d43 100644 --- a/doc/integration.qbk +++ b/doc/integration.qbk @@ -69,7 +69,7 @@ wake up again on its next expiration. Since, in this thought experiment, we always pass control to the fiber manager via `yield()`, the calling fiber is never blocked. Therefore there is always at least one ready fiber. Therefore the fiber manager never calls [member_link -sched_algorithm..suspend_until]. +algorithm..suspend_until]. Using [@http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/io_service/post.html @@ -247,7 +247,7 @@ Doubtless you have been asking yourself: why are we calling `suspend_until()`, whose very API was designed for just such a purpose? Under normal circumstances, when the fiber manager finds no ready fibers, it -calls [member_link sched_algorithm..suspend_until]. Why test +calls [member_link algorithm..suspend_until]. Why test `has_ready_fibers()` in the lambda loop? Why not leverage the normal mechanism? @@ -257,7 +257,7 @@ Consider the lambda loop shown above. The only __boost_fiber__ APIs it engages are `has_ready_fibers()` and [ns_function_link this_fiber..yield]. `yield()` does not ['block] the calling fiber: the calling fiber does not become unready. It is immediately passed back to [member_link -sched_algorithm..awakened], to be resumed in its turn when all other ready +algorithm..awakened], to be resumed in its turn when all other ready fibers have had a chance to run. In other words: during a `yield()` call, ['there is always at least one ready fiber.] diff --git a/doc/migration.qbk b/doc/migration.qbk index 8b7e9385..4093518d 100644 --- a/doc/migration.qbk +++ b/doc/migration.qbk @@ -43,12 +43,12 @@ which the fiber migrates. Thus, fiber migration is accomplished by sharing state between instances of a user-coded __algo__ implementation running on different threads. The fiber[s] -original thread calls [member_link sched_algorithm..awakened], passing the +original thread calls [member_link algorithm..awakened], passing the fiber[s] [class_link context][^*]. The `awakened()` implementation calls __context_detach__. At some later point, when the same or a different thread calls [member_link -sched_algorithm..pick_next], the `pick_next()` implementation selects a ready +algorithm..pick_next], the `pick_next()` implementation selects a ready fiber and calls __context_attach__ on it before returning it. As stated above, a `context` for which `is_context(pinned_context) == true` diff --git a/doc/mutexes.qbk b/doc/mutexes.qbk index 9e4bcb66..82fae783 100644 --- a/doc/mutexes.qbk +++ b/doc/mutexes.qbk @@ -11,6 +11,9 @@ [class_heading mutex] #include + + namespace boost { + namespace fibers { class mutex { public: @@ -25,6 +28,8 @@ void unlock(); }; + }} + __mutex__ provides an exclusive-ownership mutex. At most one fiber can own the lock on a given instance of __mutex__ at any time. Multiple concurrent calls to __lock__, __try_lock__ and __unlock__ shall be permitted. @@ -76,6 +81,9 @@ otherwise.]] #include + namespace boost { + namespace fibers { + class timed_mutex { public: timed_mutex(); @@ -94,6 +102,8 @@ otherwise.]] bool try_lock_for( std::chrono::duration< Rep, Period > const& timeout_duration); }; + }} + __timed_mutex__ provides an exclusive-ownership mutex. At most one fiber can own the lock on a given instance of __timed_mutex__ at any time. Multiple concurrent calls to __lock__, __try_lock__, __try_lock_until__, __try_lock_for__ and @@ -177,6 +187,9 @@ otherwise.]] #include + namespace boost { + namespace fibers { + class recursive_mutex { public: recursive_mutex(); @@ -190,6 +203,8 @@ otherwise.]] void unlock(); }; + }} + __recursive_mutex__ provides an exclusive-ownership recursive mutex. At most one fiber can own the lock on a given instance of __recursive_mutex__ at any time. Multiple concurrent calls to __lock__, __try_lock__ and __unlock__ shall be @@ -236,6 +251,9 @@ otherwise.]] #include + namespace boost { + namespace fibers { + class recursive_timed_mutex { public: recursive_timed_mutex(); @@ -254,6 +272,8 @@ otherwise.]] bool try_lock_for( std::chrono::duration< Rep, Period > const& timeout_duration); }; + }} + __recursive_timed_mutex__ provides an exclusive-ownership recursive mutex. At most one fiber can own the lock on a given instance of __recursive_timed_mutex__ at any time. Multiple concurrent calls to __lock__, diff --git a/doc/packaged_task.qbk b/doc/packaged_task.qbk index 2dc5c2cd..1b140683 100644 --- a/doc/packaged_task.qbk +++ b/doc/packaged_task.qbk @@ -26,6 +26,11 @@ Conventional usage of `packaged_task<>` is like this: This is, in fact, pretty much what [ns_function_link fibers..async] encapsulates. + #include + + namespace boost { + namespace fibers { + template< class R, typename ... Args > class packaged_task< R( Args ... ) > { public: @@ -61,6 +66,8 @@ encapsulates. template< typename Signature > void swap( packaged_task< Signature > &, packaged_task< Signature > &) noexcept; + }} + [heading Default constructor `packaged_task()`] packaged_task() noexcept; diff --git a/doc/promise.qbk b/doc/promise.qbk index da875c24..4104a5a4 100644 --- a/doc/promise.qbk +++ b/doc/promise.qbk @@ -12,6 +12,11 @@ A __promise__ provides a mechanism to store a value (or exception) that can later be retrieved from the corresponding __future__ object. `promise<>` and `future<>` communicate via their underlying [link shared_state shared state]. + #include + + namespace boost { + namespace fibers { + template< typename R > class promise { public: @@ -45,6 +50,8 @@ later be retrieved from the corresponding __future__ object. `promise<>` and template< typename R > void swap( promise< R > &, promise< R > &) noexcept; + } + [heading Default constructor] promise(); diff --git a/doc/scheduling.qbk b/doc/scheduling.qbk index 200453d3..a0b7b92c 100644 --- a/doc/scheduling.qbk +++ b/doc/scheduling.qbk @@ -22,12 +22,12 @@ different schedulers. By default, __boost_fiber__ implicitly instantiates [class_link round_robin] as the scheduler for each thread. You are explicitly permitted to code your own __algo__ subclass. For the most -part, your `sched_algorithm` subclass need not defend against cross-thread +part, your `algorithm` subclass need not defend against cross-thread calls: the fiber manager intercepts and defers such calls. Most -`sched_algorithm` methods are only ever directly called from the thread whose +`algorithm` methods are only ever directly called from the thread whose fibers it is managing [mdash] with exceptions as documented below. -Your `sched_algorithm` subclass is engaged on a particular thread by calling +Your `algorithm` subclass is engaged on a particular thread by calling [function_link use_scheduling_algorithm]: void thread_fn() { @@ -39,15 +39,19 @@ A scheduler class must implement interface __algo__. __boost_fiber__ provides one scheduler: [class_link round_robin]. -[class_heading sched_algorithm] +[class_heading algorithm] -`sched_algorithm` is the abstract base class defining the interface that a +`algorithm` is the abstract base class defining the interface that a fiber scheduler must implement. - #include + #include - struct sched_algorithm { - virtual ~sched_algorithm(); + namespace boost { + namespace fibers { + namespace algo { + + struct algorithm { + virtual ~algorithm(); virtual void awakened( context *) noexcept = 0; @@ -60,7 +64,9 @@ fiber scheduler must implement. virtual void notify() noexcept = 0; }; -[member_heading sched_algorithm..awakened] + }}} + +[member_heading algorithm..awakened] virtual void awakened( context * f) noexcept = 0; @@ -74,7 +80,7 @@ queue.]] [[See also:] [[class_link round_robin]]] ] -[member_heading sched_algorithm..pick_next] +[member_heading algorithm..pick_next] virtual context * pick_next() noexcept = 0; @@ -87,7 +93,7 @@ queue.]] [[See also:] [[class_link round_robin]]] ] -[member_heading sched_algorithm..has_ready_fibers] +[member_heading algorithm..has_ready_fibers] virtual bool has_ready_fibers() const noexcept = 0; @@ -95,7 +101,7 @@ queue.]] [[Returns:] [`true` if scheduler has fibers ready to run.]] ] -[member_heading sched_algorithm..suspend_until] +[member_heading algorithm..suspend_until] virtual void suspend_until( std::chrono::steady_clock::time_point const& abs_time) noexcept = 0; @@ -105,7 +111,7 @@ time-point `abs_time`.]] [[Note:] [This method allows a custom scheduler to yield control to the containing environment in whatever way makes sense. The fiber manager is stating that `suspend_until()` need not return until `abs_time` [mdash] or -[member_link sched_algorithm..notify] is called [mdash] whichever comes first. +[member_link algorithm..notify] is called [mdash] whichever comes first. The interaction with `notify()` means that, for instance, calling [@http://en.cppreference.com/w/cpp/thread/sleep_until `std::this_thread::sleep_until(abs_time)`] would be too simplistic. @@ -115,29 +121,33 @@ The interaction with `notify()` means that, for instance, calling round_robin..notify].]] [[Note:] [Given that `notify()` might be called from another thread, your `suspend_until()` implementation [mdash] like the rest of your -`sched_algorithm` implementation [mdash] must guard any data it shares with +`algorithm` implementation [mdash] must guard any data it shares with your `notify()` implementation.]] ] -[member_heading sched_algorithm..notify] +[member_heading algorithm..notify] virtual void notify() noexcept = 0; [variablelist [[Effects:] [Requests the scheduler to return from a pending call to -[member_link sched_algorithm..suspend_until].]] -[[Note:] [Alone among the `sched_algorithm` methods, `notify()` may be called +[member_link algorithm..suspend_until].]] +[[Note:] [Alone among the `algorithm` methods, `notify()` may be called from another thread. Your `notify()` implementation must guard any data it -shares with the rest of your `sched_algorithm` implementation.]] +shares with the rest of your `algorithm` implementation.]] ] [class_heading round_robin] This class implements __algo__, scheduling fibers in round-robin fashion. - #include + #include - class round_robin : public sched_algorithm { + namespace boost { + namespace fibers { + namespace algo { + + class round_robin : public algorithm { virtual void awakened( context *) noexcept; virtual context * pick_next() noexcept; @@ -149,6 +159,8 @@ This class implements __algo__, scheduling fibers in round-robin fashion. virtual void notify() noexcept; }; + }}} + [member_heading round_robin..awakened] virtual void awakened( context * f) noexcept; @@ -209,7 +221,7 @@ wakes `suspend_until()` via [heading Custom Scheduler Fiber Properties] A scheduler class directly derived from __algo__ can use any information -available from [class_link context] to implement the `sched_algorithm` +available from [class_link context] to implement the `algorithm` interface. But a custom scheduler might need to track additional properties for a fiber. For instance, a priority-based scheduler would need to track a fiber's priority. @@ -223,6 +235,9 @@ A custom fiber properties class must be derived from `fiber_properties`. #include + namespace boost { + namespace fibers { + class fiber_properties { public: fiber_properties( context *) noexcept; @@ -233,6 +248,8 @@ A custom fiber properties class must be derived from `fiber_properties`. void notify() noexcept; }; + }} + [heading Constructor] fiber_properties( context * f) noexcept; @@ -250,13 +267,13 @@ to the base-class `fiber_properties` constructor.]] [variablelist [[Effects:] [Pass control to the custom [template_link -sched_algorithm_with_properties] subclass's [member_link -sched_algorithm_with_properties..property_change] method.]] +algorithm_with_properties] subclass's [member_link +algorithm_with_properties..property_change] method.]] [[Throws:] [Nothing.]] [[Note:] [A custom scheduler's [member_link -sched_algorithm_with_properties..pick_next] method might dynamically select +algorithm_with_properties..pick_next] method might dynamically select from the ready fibers, or [member_link -sched_algorithm_with_properties..awakened] might instead insert each ready +algorithm_with_properties..awakened] might instead insert each ready fiber into some form of ready queue for `pick_next()`. In the latter case, if application code modifies a fiber property (e.g. priority) that should affect that fiber's relationship to other ready fibers, the custom scheduler must be @@ -270,16 +287,20 @@ behavior of the `pick_next()` method, you need not call `notify()` when that property is modified.]] ] -[template_heading sched_algorithm_with_properties] +[template_heading algorithm_with_properties] A custom scheduler that depends on a custom properties class `PROPS` should be -derived from `sched_algorithm_with_properties`. `PROPS` should be +derived from `algorithm_with_properties`. `PROPS` should be derived from [class_link fiber_properties]. #include + namespace boost { + namespace fibers { + namespace algo { + template< typename PROPS > - struct sched_algorithm_with_properties { + struct algorithm_with_properties { virtual void awakened( context *, PROPS &) noexcept = 0; virtual context * pick_next() noexcept; @@ -297,20 +318,22 @@ derived from [class_link fiber_properties]. virtual fiber_properties * new_properties( context *); }; -[member_heading sched_algorithm_with_properties..awakened] + }}} + +[member_heading algorithm_with_properties..awakened] virtual void awakened( context * f, PROPS & properties) noexcept; [variablelist [[Effects:] [Informs the scheduler that fiber `f` is ready to run, like -[member_link sched_algorithm..awakened]. Passes the fiber's associated `PROPS` +[member_link algorithm..awakened]. Passes the fiber's associated `PROPS` instance.]] [[Throws:] [Nothing.]] -[[Note:] [A `sched_algorithm_with_properties<>` subclass must override this -method instead of `sched_algorithm::awakened()`.]] +[[Note:] [A `algorithm_with_properties<>` subclass must override this +method instead of `algorithm::awakened()`.]] ] -[member_heading sched_algorithm_with_properties..pick_next] +[member_heading algorithm_with_properties..pick_next] virtual context * pick_next() noexcept; @@ -318,40 +341,40 @@ method instead of `sched_algorithm::awakened()`.]] [[Returns:] [the fiber which is to be resumed next, or `nullptr` if there is no ready fiber.]] [[Throws:] [Nothing.]] -[[Note:] [same as [member_link sched_algorithm..pick_next]]] +[[Note:] [same as [member_link algorithm..pick_next]]] ] -[member_heading sched_algorithm_with_properties..has_ready_fibers] +[member_heading algorithm_with_properties..has_ready_fibers] virtual bool has_ready_fibers() const noexcept; [variablelist [[Returns:] [`true` if scheduler has fibers ready to run.]] [[Throws:] [Nothing.]] -[[Note:] [same as [member_link sched_algorithm..has_ready_fibers]]] +[[Note:] [same as [member_link algorithm..has_ready_fibers]]] ] -[member_heading sched_algorithm_with_properties..suspend_until] +[member_heading algorithm_with_properties..suspend_until] virtual void suspend_until( std::chrono::steady_clock::time_point const& abs_time) noexcept = 0; [variablelist [[Effects:] [Informs the scheduler that no fiber will be ready until time-point `abs_time`.]] -[[Note:] [same as [member_link sched_algorithm..suspend_until]]] +[[Note:] [same as [member_link algorithm..suspend_until]]] ] -[member_heading sched_algorithm_with_properties..notify] +[member_heading algorithm_with_properties..notify] virtual void notify() noexcept = 0; [variablelist [[Effects:] [Requests the scheduler to return from a pending call to -[member_link sched_algorithm_with_properties..suspend_until].]] -[[Note:] [same as [member_link sched_algorithm..notify]]] +[member_link algorithm_with_properties..suspend_until].]] +[[Note:] [same as [member_link algorithm..notify]]] ] -[member_heading sched_algorithm_with_properties..properties] +[member_heading algorithm_with_properties..properties] PROPS& properties( context * f) noexcept; @@ -359,15 +382,15 @@ time-point `abs_time`.]] [[Returns:] [the `PROPS` instance associated with fiber `f`.]] [[Throws:] [Nothing.]] [[Note:] [The fiber's associated `PROPS` instance is already passed to -[member_link sched_algorithm_with_properties..awakened] and [member_link -sched_algorithm_with_properties..property_change]. However, every [class_link -sched_algorithm] subclass is expected to track a collection of ready +[member_link algorithm_with_properties..awakened] and [member_link +algorithm_with_properties..property_change]. However, every [class_link +algorithm] subclass is expected to track a collection of ready [class_link context] instances. This method allows your custom scheduler to retrieve the [class_link fiber_properties] subclass instance for any `context` in its collection.]] ] -[member_heading sched_algorithm_with_properties..property_change] +[member_heading algorithm_with_properties..property_change] virtual void property_change( context * f, PROPS & properties) noexcept; @@ -381,14 +404,14 @@ fiber_properties] subclass explicitly calls [member_link fiber_properties..notify].]] ] -[member_heading sched_algorithm_with_properties..new_properties] +[member_heading algorithm_with_properties..new_properties] virtual fiber_properties * new_properties( context * f); [variablelist [[Returns:] [A new instance of [class_link fiber_properties] subclass `PROPS`.]] -[[Note:] [By default, `sched_algorithm_with_properties<>::new_properties()` +[[Note:] [By default, `algorithm_with_properties<>::new_properties()` simply returns `new PROPS(f)`, placing the `PROPS` instance on the heap. Override this method to allocate `PROPS` some other way. The returned `fiber_properties` pointer must point to the `PROPS` instance to be associated @@ -406,16 +429,19 @@ Of particular note is the fact that `context` contains a hook to participate in a [@http://www.boost.org/doc/libs/release/doc/html/intrusive/list.html `boost::intrusive::list`] typedef'ed as `boost::fibers::scheduler::ready_queue_t`. This hook is reserved for use by -[class_link sched_algorithm] implementations. (For instance, [class_link +[class_link algorithm] implementations. (For instance, [class_link round_robin] contains a `ready_queue_t` instance to manage its ready fibers.) See [member_link context..ready_is_linked], [member_link context..ready_link], [member_link context..ready_unlink]. -Your `sched_algorithm` implementation may use any container you desire to +Your `algorithm` implementation may use any container you desire to manage passed `context` instances. `ready_queue_t` avoids some of the overhead of typical STL containers. #include + + namespace boost { + namespace fibers { enum class type { none = ``['unspecified]``, @@ -464,6 +490,8 @@ of typical STL containers. bool operator<( context const& l, context const& r) noexcept; + }} + [static_member_heading context..active] static context * active() noexcept; @@ -498,10 +526,10 @@ default-constructed __fiber_id__.]] [[Note:] [`f` must not be the running fiber[s] context. It must not be __blocked__ or terminated. It must not be a `pinned_context`. It must be currently detached. It must not currently be linked into a [class_link -sched_algorithm] implementation[s] ready queue. Most of these conditions are -implied by `f` being owned by a `sched_algorithm` implementation: that is, it -has been passed to [member_link sched_algorithm..awakened] but has not yet -been returned by [member_link sched_algorithm..pick_next]. Typically a +algorithm] implementation[s] ready queue. Most of these conditions are +implied by `f` being owned by a `algorithm` implementation: that is, it +has been passed to [member_link algorithm..awakened] but has not yet +been returned by [member_link algorithm..pick_next]. Typically a `pick_next()` implementation would call `attach()` with the `context*` it is about to return. It must first remove `f` from its ready queue. You should never pass a `pinned_context` to `attach()` because you should never have @@ -521,13 +549,13 @@ called its `detach()` method in the first place.]] currently associated. `*this` must not be the running fiber[s] context. It must not be __blocked__ or terminated. It must not be a `pinned_context`. It must not be detached already. It must not already be linked into a [class_link -sched_algorithm] implementation[s] ready queue. Most of these conditions are -implied by `*this` being passed to [member_link sched_algorithm..awakened]; an +algorithm] implementation[s] ready queue. Most of these conditions are +implied by `*this` being passed to [member_link algorithm..awakened]; an `awakened()` implementation must, however, test for `pinned_context`. It must call `detach()` ['before] linking `*this` into its ready queue.]] [[Note:] [In particular, it is erroneous to attempt to migrate a fiber from one thread to another by calling both `detach()` and `attach()` in the -[member_link sched_algorithm..pick_next] method. `pick_next()` is called on +[member_link algorithm..pick_next] method. `pick_next()` is called on the intended destination thread. `detach()` must be called on the fiber[s] original thread. You must call `detach()` in the corresponding `awakened()` method.]] @@ -571,7 +599,7 @@ no longer considered a valid context.]] bool ready_is_linked() const noexcept; [variablelist -[[Returns:] [`true` if `*this` is stored in a [class_link sched_algorithm] +[[Returns:] [`true` if `*this` is stored in a [class_link algorithm] implementation's ready-queue.]] [[Throws:] [Nothing]] [[Note:] [Specifically, this method indicates whether [member_link @@ -589,8 +617,8 @@ remote-ready-queue.]] [[Throws:] [Nothing]] [[Note:] [A `context` signaled as ready by another thread is first stored in the fiber manager's remote-ready-queue. This is the mechanism by which the -fiber manager protects a [class_link sched_algorithm] implementation from -cross-thread [member_link sched_algorithm..awakened] calls.]] +fiber manager protects a [class_link algorithm] implementation from +cross-thread [member_link algorithm..awakened] calls.]] ] [member_heading context..wait_is_linked] @@ -699,8 +727,8 @@ with a pointer to `this` at some future time.]] [[Effects:] [Mark the fiber associated with context `*ctx` as being ready to run. This does not immediately resume that fiber; rather it passes the fiber to the scheduler for subsequent resumption. If the scheduler is idle (has not -returned from a call to [member_link sched_algorithm..suspend_until]), -[member_link sched_algorithm..notify] is called to wake it up.]] +returned from a call to [member_link algorithm..suspend_until]), +[member_link algorithm..notify] is called to wake it up.]] [[Throws:] [Nothing]] [[Note:] [This is a low-level API potentially useful for integration with other frameworks. It is not intended to be directly invoked by a typical diff --git a/doc/stack.qbk b/doc/stack.qbk index 6c933b32..9c6eb5e7 100644 --- a/doc/stack.qbk +++ b/doc/stack.qbk @@ -72,6 +72,9 @@ virtual addresses are used.] #include + namespace boost { + namespace fibers { + struct protected_fixedsize { protected_fixesize(std::size_t size = traits_type::default_size()); @@ -80,6 +83,8 @@ virtual addresses are used.] void deallocate( stack_context &); } + }} + [member_heading protected_fixedsize..allocate] stack_context allocate(); @@ -114,6 +119,9 @@ end of each stack. The memory is managed internally by #include + namespace boost { + namespace fibers { + struct pooled_fixedsize_stack { pooled_fixedsize_stack(std::size_t stack_size = traits_type::default_size(), std::size_t next_size = 32, std::size_t max_size = 0); @@ -122,6 +130,8 @@ end of each stack. The memory is managed internally by void deallocate( stack_context &); } + }} + [hding pooled_fixedsize..Constructor] pooled_fixedsize_stack(std::size_t stack_size, std::size_t next_size, std::size_t max_size); @@ -160,6 +170,8 @@ address of the stack.]] [[Effects:] [Deallocates the stack space.]] ] +[note This stack allocator is not thread safe.] + [class_heading fixedsize_stack] @@ -171,6 +183,9 @@ end of each stack. The memory is simply managed by `std::malloc()` and #include + namespace boost { + namespace fibers { + struct fixedsize_stack { fixedsize_stack(std::size_t size = traits_type::default_size()); @@ -179,6 +194,8 @@ end of each stack. The memory is simply managed by `std::malloc()` and void deallocate( stack_context &); } + }} + [member_heading fixedsize..allocate] stack_context allocate(); @@ -220,6 +237,9 @@ command line.] #include + namespace boost { + namespace fibers { + struct segmented_stack { segmented_stack(std::size_t stack_size = traits_type::default_size()); @@ -228,6 +248,8 @@ command line.] void deallocate( stack_context &); } + }} + [member_heading segmented..allocate] stack_context allocate(); diff --git a/examples/asio/autoecho.cpp b/examples/asio/autoecho.cpp index ef85d142..bc9f5700 100644 --- a/examples/asio/autoecho.cpp +++ b/examples/asio/autoecho.cpp @@ -251,6 +251,7 @@ int main( int argc, char* argv[]) { //] print( tag(), ": io_service 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"); diff --git a/examples/asio/round_robin.hpp b/examples/asio/round_robin.hpp index 30fea352..0b208ab0 100644 --- a/examples/asio/round_robin.hpp +++ b/examples/asio/round_robin.hpp @@ -32,7 +32,7 @@ namespace boost { namespace fibers { namespace asio { -class round_robin : public sched_algorithm { +class round_robin : public algo::algorithm { private: typedef scheduler::ready_queue_t rqueue_t; diff --git a/examples/priority.cpp b/examples/priority.cpp index 9f95714a..c6ec66e4 100644 --- a/examples/priority.cpp +++ b/examples/priority.cpp @@ -73,7 +73,7 @@ private: //[priority_scheduler class priority_scheduler : - public boost::fibers::sched_algorithm_with_properties< priority_props > { + public boost::fibers::algo::algorithm_with_properties< priority_props > { private: typedef boost::fibers::scheduler::ready_queue_t/*< See [link ready_queue_t]. >*/ rqueue_t; @@ -87,9 +87,9 @@ public: rqueue_() { } - // For a subclass of sched_algorithm_with_properties<>, it's important to + // For a subclass of algorithm_with_properties<>, it's important to // override the correct awakened() overload. - /*<< You must override the [member_link sched_algorithm_with_properties..awakened] + /*<< 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 { @@ -115,7 +115,7 @@ public: //-> } - /*<< You must override the [member_link sched_algorithm_with_properties..pick_next] + /*<< 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 { @@ -132,13 +132,13 @@ public: return ctx; } - /*<< You must override [member_link sched_algorithm_with_properties..has_ready_fibers] + /*<< 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 sched_algorithm_with_properties..property_change] + /*<< 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. >>*/ diff --git a/examples/work_sharing.cpp b/examples/work_sharing.cpp index 078fb9aa..0931fa73 100644 --- a/examples/work_sharing.cpp +++ b/examples/work_sharing.cpp @@ -6,10 +6,10 @@ #include #include #include +#include #include #include #include -#include #include #include #include @@ -25,82 +25,6 @@ static std::mutex mtx_count{}; static boost::fibers::condition_variable_any cnd_count{}; typedef std::unique_lock< std::mutex > lock_t; -/***************************************************************************** -* shared_ready_queue scheduler -*****************************************************************************/ -class shared_ready_queue : public boost::fibers::sched_algorithm { -private: - typedef std::queue< boost::fibers::context * > rqueue_t; - - static rqueue_t rqueue_; - static std::mutex rqueue_mtx_; - - rqueue_t local_queue_{}; - -public: -//[awakened_ws - virtual void awakened( boost::fibers::context * ctx) noexcept { - BOOST_ASSERT( nullptr != ctx); - - if ( ctx->is_context( boost::fibers::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 - >*/ - local_queue_.push( ctx); - } else { - ctx->detach(); - lock_t lk(rqueue_mtx_); /*< - worker fiber, enqueue on shared queue - >*/ - rqueue_.push( ctx); - } - } -//] -//[pick_next_ws - virtual boost::fibers::context * pick_next() noexcept { - boost::fibers::context * ctx( nullptr); - lock_t lk(rqueue_mtx_); - if ( ! rqueue_.empty() ) { /*< - pop an item from the ready queue - >*/ - ctx = rqueue_.front(); - rqueue_.pop(); - lk.unlock(); - BOOST_ASSERT( nullptr != ctx); - boost::fibers::context::active()->attach( ctx); /*< - attach context to current scheduler via the active fiber - of this thread - >*/ - } else { - lk.unlock(); - if ( ! local_queue_.empty() ) { /*< - nothing in the ready queue, return main or dispatcher fiber - >*/ - ctx = local_queue_.front(); - local_queue_.pop(); - } - } - return ctx; - } -//] - - virtual bool has_ready_fibers() const noexcept { - lock_t lock(rqueue_mtx_); - return ! rqueue_.empty() || ! local_queue_.empty(); - } - - void suspend_until( std::chrono::steady_clock::time_point const& time_point) noexcept { - // let scheduler (dispatcher-fiber) spin - } - - void notify() noexcept { - } -}; - -shared_ready_queue::rqueue_t shared_ready_queue::rqueue_{}; -std::mutex shared_ready_queue::rqueue_mtx_{}; - /***************************************************************************** * example fiber function *****************************************************************************/ @@ -141,8 +65,8 @@ void 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< shared_ready_queue >(); /*< - Install the scheduling algorithm `shared_ready_queue` in order to + boost::fibers::use_scheduling_algorithm< boost::fibers::algo::shared_round_robin >(); /*< + Install the scheduling algorithm `boost::fibers::algo::shared_round_robin` in order to join the work sharing. >*/ b->wait(); /*< sync with other threads: allow them to start processing >*/ @@ -162,8 +86,8 @@ void thread( barrier * b) { 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< shared_ready_queue >(); /*< - Install the scheduling algorithm `shared_ready_queue` in the main thread + boost::fibers::use_scheduling_algorithm< boost::fibers::algo::shared_round_robin >(); /*< + Install the scheduling algorithm `boost::fibers::algo::shared_round_robin` in the main thread too, so each new fiber gets launched into the shared pool. >*/ diff --git a/examples/work_stealing.cpp b/examples/work_stealing.cpp index e41d7742..95080477 100644 --- a/examples/work_stealing.cpp +++ b/examples/work_stealing.cpp @@ -85,7 +85,7 @@ public: } }; -class victim_algo : public boost::fibers::sched_algorithm { +class victim_algo : public boost::fibers::algo::algorithm { private: typedef work_stealing_queue rqueue_t; @@ -139,7 +139,7 @@ public: } }; -class thief_algo : public boost::fibers::sched_algorithm { +class thief_algo : public boost::fibers::algo::algorithm { private: typedef boost::fibers::scheduler::ready_queue_t rqueue_t; typedef work_stealing_queue ws_rqueue_t; diff --git a/include/boost/fiber/algorithm.hpp b/include/boost/fiber/algo/algorithm.hpp similarity index 79% rename from include/boost/fiber/algorithm.hpp rename to include/boost/fiber/algo/algorithm.hpp index 1116a65e..515fc5ed 100644 --- a/include/boost/fiber/algorithm.hpp +++ b/include/boost/fiber/algo/algorithm.hpp @@ -3,8 +3,8 @@ // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) -#ifndef BOOST_FIBERS_ALGORITHM_H -#define BOOST_FIBERS_ALGORITHM_H +#ifndef BOOST_FIBERS_ALGO_ALGORITHM_H +#define BOOST_FIBERS_ALGO_ALGORITHM_H #include #include @@ -24,8 +24,10 @@ namespace fibers { class context; -struct BOOST_FIBERS_DECL sched_algorithm { - virtual ~sched_algorithm() {} +namespace algo { + +struct BOOST_FIBERS_DECL algorithm { + virtual ~algorithm() {} virtual void awakened( context *) noexcept = 0; @@ -38,7 +40,7 @@ struct BOOST_FIBERS_DECL sched_algorithm { virtual void notify() noexcept = 0; }; -class BOOST_FIBERS_DECL sched_algorithm_with_properties_base : public sched_algorithm { +class BOOST_FIBERS_DECL algorithm_with_properties_base : public algorithm { public: // called by fiber_properties::notify() -- don't directly call virtual void property_change_( context * f, fiber_properties * props) noexcept = 0; @@ -49,13 +51,13 @@ protected: }; template< typename PROPS > -struct sched_algorithm_with_properties : public sched_algorithm_with_properties_base { - typedef sched_algorithm_with_properties_base super; +struct algorithm_with_properties : public algorithm_with_properties_base { + typedef algorithm_with_properties_base super; - // Mark this override 'final': sched_algorithm_with_properties subclasses + // Mark this override 'final': algorithm_with_properties subclasses // must override awakened() with properties parameter instead. Otherwise // you'd have to remember to start every subclass awakened() override - // with: sched_algorithm_with_properties::awakened(fb); + // with: algorithm_with_properties::awakened(fb); virtual void awakened( context * f) noexcept override final { fiber_properties * props = super::get_properties( f); if ( nullptr == props) { @@ -69,10 +71,10 @@ struct sched_algorithm_with_properties : public sched_algorithm_with_properties_ "new_properties() must return properties class"); super::set_properties( f, props); } - // Set sched_algo_ again every time this fiber becomes READY. That + // Set algo_ again every time this fiber becomes READY. That // handles the case of a fiber migrating to a new thread with a new - // sched_algorithm subclass instance. - props->set_sched_algorithm( this); + // algorithm subclass instance. + props->set_algorithm( this); // Okay, now forward the call to subclass override. awakened( f, properties(f) ); @@ -90,7 +92,7 @@ struct sched_algorithm_with_properties : public sched_algorithm_with_properties_ virtual void property_change( context * f, PROPS & props) noexcept { } - // implementation for sched_algorithm_with_properties_base method + // implementation for algorithm_with_properties_base method void property_change_( context * f, fiber_properties * props ) noexcept override final { property_change( f, * static_cast< PROPS * >( props) ); } @@ -103,10 +105,10 @@ struct sched_algorithm_with_properties : public sched_algorithm_with_properties_ } }; -}} +}}} #ifdef BOOST_HAS_ABI_HEADERS # include BOOST_ABI_SUFFIX #endif -#endif // BOOST_FIBERS_ALGORITHM_H +#endif // BOOST_FIBERS_ALGO_ALGORITHM_H diff --git a/include/boost/fiber/round_robin.hpp b/include/boost/fiber/algo/round_robin.hpp similarity index 77% rename from include/boost/fiber/round_robin.hpp rename to include/boost/fiber/algo/round_robin.hpp index 7d888a3c..9f188267 100644 --- a/include/boost/fiber/round_robin.hpp +++ b/include/boost/fiber/algo/round_robin.hpp @@ -3,8 +3,8 @@ // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) -#ifndef BOOST_FIBERS_DEFAULT_ROUND_ROBIN_H -#define BOOST_FIBERS_DEFAULT_ROUND_ROBIN_H +#ifndef BOOST_FIBERS_ALGO_ROUND_ROBIN_H +#define BOOST_FIBERS_ALGO_ROUND_ROBIN_H #include #include @@ -12,7 +12,7 @@ #include -#include +#include #include #include #include @@ -23,12 +23,13 @@ namespace boost { namespace fibers { +namespace algo { -class context; - -class BOOST_FIBERS_DECL round_robin : public sched_algorithm { +class BOOST_FIBERS_DECL round_robin : public algorithm { private: - scheduler::ready_queue_t ready_queue_{}; + typedef scheduler::ready_queue_t rqueue_t; + + rqueue_t rqueue_{}; std::mutex mtx_{}; std::condition_variable cnd_{}; bool flag_{ false }; @@ -50,10 +51,10 @@ public: virtual void notify() noexcept; }; -}} +}}} #ifdef BOOST_HAS_ABI_HEADERS # include BOOST_ABI_SUFFIX #endif -#endif // BOOST_FIBERS_DEFAULT_ROUND_ROBIN_H +#endif // BOOST_FIBERS_ALGO_ROUND_ROBIN_H diff --git a/include/boost/fiber/algo/shared_round_robin.hpp b/include/boost/fiber/algo/shared_round_robin.hpp new file mode 100644 index 00000000..e02d7079 --- /dev/null +++ b/include/boost/fiber/algo/shared_round_robin.hpp @@ -0,0 +1,77 @@ + +// 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_SHARED_ROUND_ROBIN_H +#define BOOST_FIBERS_ALGO_SHARED_ROUND_ROBIN_H + +#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 shared_round_robin : public algorithm { +private: + typedef std::deque< context * > rqueue_t; + typedef scheduler::ready_queue_t lqueue_t; + + static rqueue_t rqueue_; + static std::mutex rqueue_mtx_; + + lqueue_t lqueue_{}; + std::mutex mtx_{}; + std::condition_variable cnd_{}; + bool flag_{ false }; + bool suspend_; + +public: + shared_round_robin() = default; + + shared_round_robin( bool suspend) : + suspend_{ suspend } { + } + + shared_round_robin( shared_round_robin const&) = delete; + shared_round_robin( shared_round_robin &&) = delete; + + shared_round_robin & operator=( shared_round_robin const&) = delete; + shared_round_robin & operator=( shared_round_robin &&) = delete; + + void awakened( context * ctx) noexcept; + + context * pick_next() noexcept; + + bool has_ready_fibers() const noexcept { + 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; + + void notify() noexcept; +}; + +}}} + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif + +#endif // BOOST_FIBERS_ALGO_SHARED_ROUND_ROBIN_H diff --git a/include/boost/fiber/all.hpp b/include/boost/fiber/all.hpp index 19efe0fa..fc32f534 100644 --- a/include/boost/fiber/all.hpp +++ b/include/boost/fiber/all.hpp @@ -7,7 +7,9 @@ #ifndef BOOST_FIBERS_H #define BOOST_FIBERS_H -#include +#include +#include +#include #include #include #include diff --git a/include/boost/fiber/operations.hpp b/include/boost/fiber/operations.hpp index 2821caaa..490ba462 100644 --- a/include/boost/fiber/operations.hpp +++ b/include/boost/fiber/operations.hpp @@ -52,7 +52,7 @@ PROPS & properties() { fibers::context::active()->get_properties(); if ( ! props) { // props could be nullptr if the thread's main fiber has not yet - // yielded (not yet passed through sched_algorithm_with_properties:: + // yielded (not yet passed through algorithm_with_properties:: // awakened()). Address that by yielding right now. yield(); // Try again to obtain the fiber_properties subclass instance ptr. @@ -60,7 +60,7 @@ PROPS & properties() { // have happened while we were yielding! props = fibers::context::active()->get_properties(); // Could still be hosed if the running manager isn't a subclass of - // sched_algorithm_with_properties. + // algorithm_with_properties. BOOST_ASSERT_MSG(props, "this_fiber::properties not set"); } return dynamic_cast< PROPS & >( * props ); @@ -78,7 +78,7 @@ bool has_ready_fibers() noexcept { template< typename SchedAlgo, typename ... Args > void use_scheduling_algorithm( Args && ... args) noexcept { boost::fibers::context::active()->get_scheduler() - ->set_sched_algo( + ->set_algo( std::unique_ptr< SchedAlgo >( new SchedAlgo( std::forward< Args >( args) ... ) ) ); } diff --git a/include/boost/fiber/properties.hpp b/include/boost/fiber/properties.hpp index dd450bc8..09ac7405 100644 --- a/include/boost/fiber/properties.hpp +++ b/include/boost/fiber/properties.hpp @@ -24,17 +24,22 @@ namespace boost { namespace fibers { -struct sched_algorithm; class context; +namespace algo { + +struct algorithm; + +} + class BOOST_FIBERS_DECL fiber_properties { protected: // initialized by constructor context * ctx_; // set every time this fiber becomes READY - sched_algorithm * sched_algo_{ nullptr }; + algo::algorithm * algo_{ nullptr }; - // Inform the relevant sched_algorithm instance that something important + // Inform the relevant algorithm instance that something important // has changed, so it can (presumably) adjust its data structures // accordingly. void notify() noexcept; @@ -54,10 +59,10 @@ public: // destroyed via that pointer. virtual ~fiber_properties() = default; - // not really intended for public use, but sched_algorithm_with_properties + // not really intended for public use, but algorithm_with_properties // must be able to call this - void set_sched_algorithm( sched_algorithm * algo) noexcept { - sched_algo_ = algo; + void set_algorithm( algo::algorithm * algo) noexcept { + algo_ = algo; } }; diff --git a/include/boost/fiber/scheduler.hpp b/include/boost/fiber/scheduler.hpp index a04657db..92867a94 100644 --- a/include/boost/fiber/scheduler.hpp +++ b/include/boost/fiber/scheduler.hpp @@ -18,7 +18,7 @@ #include #include -#include +#include #include #include #include @@ -63,7 +63,7 @@ private: context, detail::worker_hook, & context::worker_hook_ >, intrusive::constant_time_size< false > > worker_queue_t; - std::unique_ptr< sched_algorithm > sched_algo_; + std::unique_ptr< algo::algorithm > algo_; context * main_ctx_{ nullptr }; intrusive_ptr< context > dispatcher_ctx_{}; // worker-queue contains all context' mananged by this scheduler @@ -124,7 +124,7 @@ public: bool has_ready_fibers() const noexcept; - void set_sched_algo( std::unique_ptr< sched_algorithm >) noexcept; + void set_algo( std::unique_ptr< algo::algorithm >) noexcept; void attach_main_context( context *) noexcept; diff --git a/performance/fiber/skynet_shared.cpp b/performance/fiber/skynet_shared.cpp index 9c4e3f80..ff5d90a5 100644 --- a/performance/fiber/skynet_shared.cpp +++ b/performance/fiber/skynet_shared.cpp @@ -1,3 +1,4 @@ + // Copyright Oliver Kowalke 2015. // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at @@ -6,14 +7,15 @@ #include #include #include +#include #include #include #include -#include +#include #include #include +#include #include -#include #include #include @@ -21,71 +23,16 @@ #include "barrier.hpp" #include "bind/bind_processor.hpp" +using allocator_type = boost::fibers::fixedsize_stack; +using channel_type = boost::fibers::unbounded_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; -using channel_type = boost::fibers::unbounded_channel< std::uint64_t >; -using allocator_type = boost::fibers::fixedsize_stack; static bool done = false; static std::mutex mtx{}; static boost::fibers::condition_variable_any cnd{}; -using lock_t = std::unique_lock< std::mutex >; - -class shared_queue_scheduler : public boost::fibers::sched_algorithm { -private: - typedef boost::fibers::scheduler::ready_queue_t queue_t; - - static queue_t rqueue_; - static std::mutex rqueue_mtx_; - - queue_t lqueue_{}; - -public: - virtual void awakened( boost::fibers::context * ctx) noexcept { - if ( ! ctx->is_context( boost::fibers::type::pinned_context) ) { - ctx->detach(); - lock_t lk( rqueue_mtx_); - ctx->ready_link( rqueue_); - } else { - ctx->ready_link( lqueue_); - } - } - - virtual boost::fibers::context * pick_next() noexcept { - boost::fibers::context * ctx( nullptr); - lock_t lk( rqueue_mtx_); - if ( ! rqueue_.empty() ) { - ctx = & rqueue_.front(); - rqueue_.pop_front(); - lk.unlock(); - BOOST_ASSERT( nullptr != ctx); - boost::fibers::context::active()->attach( ctx); - } else { - lk.unlock(); - if ( ! lqueue_.empty() ) { - ctx = & lqueue_.front(); - lqueue_.pop_front(); - } - } - return ctx; - } - - virtual bool has_ready_fibers() const noexcept { - lock_t lock( rqueue_mtx_); - return ! rqueue_.empty() || ! lqueue_.empty(); - } - - void suspend_until( std::chrono::steady_clock::time_point const& time_point) noexcept { - // do not block thread; spin in dispatcher-fiber till ready fibers are available - } - - void notify() noexcept { - } -}; - -shared_queue_scheduler::queue_t shared_queue_scheduler::rqueue_{}; -std::mutex shared_queue_scheduler::rqueue_mtx_{}; // microbenchmark void skynet( allocator_type & salloc, channel_type & c, std::size_t num, std::size_t size, std::size_t div) { @@ -110,26 +57,25 @@ void skynet( allocator_type & salloc, channel_type & c, std::size_t num, std::si void thread( unsigned int i, barrier * b) { bind_to_processor( i); - boost::fibers::use_scheduling_algorithm< shared_queue_scheduler >(); + boost::fibers::use_scheduling_algorithm< boost::fibers::algo::shared_round_robin >(); b->wait(); - lock_t lk( mtx); + lock_type lk( mtx); cnd.wait( lk, [](){ return done; }); BOOST_ASSERT( done); } int main() { try { - boost::fibers::use_scheduling_algorithm< shared_queue_scheduler >(); + boost::fibers::use_scheduling_algorithm< boost::fibers::algo::shared_round_robin >(); unsigned int n = std::thread::hardware_concurrency(); barrier b( n); - n -= 1; // this thread - bind_to_processor( n); + bind_to_processor( n - 1); std::size_t stack_size{ 4048 }; std::size_t size{ 100000 }; std::size_t div{ 10 }; std::vector< std::thread > threads; - for ( unsigned int i = 0; i < n; i++) { - threads.push_back( std::thread( thread, i, & b) ); + for ( unsigned int i = 1; i < n; ++i) { + threads.push_back( std::thread( thread, i - 1, & b) ); }; allocator_type salloc{ stack_size }; std::uint64_t result{ 0 }; @@ -141,7 +87,7 @@ int main() { result = rc.value_pop(); duration = clock_type::now() - start; std::cout << "Result: " << result << " in " << duration.count() / 1000000 << " ms" << std::endl; - lock_t lk( mtx); + lock_type lk( mtx); done = true; lk.unlock(); cnd.notify_all(); diff --git a/src/algorithm.cpp b/src/algo/algorithm.cpp similarity index 69% rename from src/algorithm.cpp rename to src/algo/algorithm.cpp index 7fd8430c..e567cf59 100644 --- a/src/algorithm.cpp +++ b/src/algo/algorithm.cpp @@ -4,7 +4,7 @@ // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) -#include "boost/fiber/algorithm.hpp" +#include "boost/fiber/algo/algorithm.hpp" #include "boost/fiber/context.hpp" @@ -14,20 +14,21 @@ namespace boost { namespace fibers { +namespace algo { //static fiber_properties * -sched_algorithm_with_properties_base::get_properties( context * ctx) noexcept { +algorithm_with_properties_base::get_properties( context * ctx) noexcept { return ctx->get_properties(); } //static void -sched_algorithm_with_properties_base::set_properties( context * ctx, fiber_properties * props) noexcept { +algorithm_with_properties_base::set_properties( context * ctx, fiber_properties * props) noexcept { ctx->set_properties( props); } -}} +}}} #ifdef BOOST_HAS_ABI_HEADERS # include BOOST_ABI_SUFFIX diff --git a/src/round_robin.cpp b/src/algo/round_robin.cpp similarity index 86% rename from src/round_robin.cpp rename to src/algo/round_robin.cpp index 1f560697..ea69a8f2 100644 --- a/src/round_robin.cpp +++ b/src/algo/round_robin.cpp @@ -4,7 +4,7 @@ // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) -#include "boost/fiber/round_robin.hpp" +#include "boost/fiber/algo/round_robin.hpp" #include @@ -14,21 +14,22 @@ namespace boost { namespace fibers { +namespace algo { void round_robin::awakened( context * ctx) noexcept { BOOST_ASSERT( nullptr != ctx); BOOST_ASSERT( ! ctx->ready_is_linked() ); - ctx->ready_link( ready_queue_); + ctx->ready_link( rqueue_); } context * round_robin::pick_next() noexcept { context * victim{ nullptr }; - if ( ! ready_queue_.empty() ) { - victim = & ready_queue_.front(); - ready_queue_.pop_front(); + if ( ! rqueue_.empty() ) { + victim = & rqueue_.front(); + rqueue_.pop_front(); BOOST_ASSERT( nullptr != victim); BOOST_ASSERT( ! victim->ready_is_linked() ); } @@ -37,7 +38,7 @@ round_robin::pick_next() noexcept { bool round_robin::has_ready_fibers() const noexcept { - return ! ready_queue_.empty(); + return ! rqueue_.empty(); } void @@ -61,7 +62,7 @@ round_robin::notify() noexcept { cnd_.notify_all(); } -}} +}}} #ifdef BOOST_HAS_ABI_HEADERS # include BOOST_ABI_SUFFIX diff --git a/src/algo/shared_round_robin.cpp b/src/algo/shared_round_robin.cpp new file mode 100644 index 00000000..3a039fc9 --- /dev/null +++ b/src/algo/shared_round_robin.cpp @@ -0,0 +1,101 @@ + +// 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_round_robin.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_round_robin::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_round_robin::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_round_robin::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_round_robin::notify() noexcept { + if ( suspend_) { + std::unique_lock< std::mutex > lk( mtx_); + flag_ = true; + lk.unlock(); + cnd_.notify_all(); + } +} + +shared_round_robin::rqueue_t shared_round_robin::rqueue_{}; +std::mutex shared_round_robin::rqueue_mtx_{}; + +}}} + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif diff --git a/src/properties.cpp b/src/properties.cpp index 4d0b4684..c8d14501 100644 --- a/src/properties.cpp +++ b/src/properties.cpp @@ -7,7 +7,7 @@ #include -#include "boost/fiber/algorithm.hpp" +#include "boost/fiber/algo/algorithm.hpp" #include "boost/fiber/scheduler.hpp" #include "boost/fiber/context.hpp" @@ -20,7 +20,7 @@ namespace fibers { void fiber_properties::notify() noexcept { - BOOST_ASSERT( nullptr != sched_algo_); + BOOST_ASSERT( nullptr != algo_); // Application code might change an important property for any fiber at // any time. The fiber in question might be ready, running or waiting. // Significantly, only a fiber which is ready but not actually running is @@ -28,7 +28,7 @@ fiber_properties::notify() noexcept { // with a change to a fiber it's not currently tracking: it will do the // right thing next time the fiber is passed to its awakened() method. if ( ctx_->ready_is_linked() ) { - static_cast< sched_algorithm_with_properties_base * >( sched_algo_)-> + static_cast< algo::algorithm_with_properties_base * >( algo_)-> property_change_( ctx_, this); } } diff --git a/src/scheduler.cpp b/src/scheduler.cpp index 75e51268..2f746228 100644 --- a/src/scheduler.cpp +++ b/src/scheduler.cpp @@ -11,9 +11,9 @@ #include +#include "boost/fiber/algo/round_robin.hpp" #include "boost/fiber/context.hpp" #include "boost/fiber/exceptions.hpp" -#include "boost/fiber/round_robin.hpp" #ifdef BOOST_HAS_ABI_HEADERS # include BOOST_ABI_PREFIX @@ -24,7 +24,7 @@ namespace fibers { context * scheduler::get_next_() noexcept { - context * ctx = sched_algo_->pick_next(); + context * ctx = algo_->pick_next(); //BOOST_ASSERT( nullptr == ctx); //BOOST_ASSERT( this == ctx->get_scheduler() ); return ctx; @@ -89,7 +89,7 @@ scheduler::sleep2ready_() noexcept { // reset sleep-tp ctx->tp_ = (std::chrono::steady_clock::time_point::max)(); // push new context to ready-queue - sched_algo_->awakened( ctx); + algo_->awakened( ctx); } else { break; // first context with now < deadline } @@ -97,7 +97,7 @@ scheduler::sleep2ready_() noexcept { } scheduler::scheduler() noexcept : - sched_algo_{ new round_robin() } { + algo_{ new algo::round_robin() } { } scheduler::~scheduler() { @@ -135,7 +135,7 @@ scheduler::dispatch() noexcept { bool no_worker = worker_queue_.empty(); if ( shutdown_) { // notify sched-algorithm about termination - sched_algo_->notify(); + algo_->notify(); if ( no_worker) { break; } @@ -164,7 +164,7 @@ scheduler::dispatch() noexcept { suspend_time = i->tp_; } // no ready context, wait till signaled - sched_algo_->suspend_until( suspend_time); + algo_->suspend_until( suspend_time); } } // release termianted context' @@ -194,7 +194,7 @@ scheduler::set_ready( context * ctx) noexcept { // for safety unlink it from ready-queue ctx->ready_unlink(); // push new context to ready-queue - sched_algo_->awakened( ctx); + algo_->awakened( ctx); } void @@ -214,7 +214,7 @@ scheduler::set_remote_ready( context * ctx) noexcept { remote_ready_queue_.push_back( ctx); lk.unlock(); // notify scheduler - sched_algo_->notify(); + algo_->notify(); } #if (BOOST_EXECUTION_CONTEXT==1) @@ -337,16 +337,16 @@ scheduler::suspend( detail::spinlock_lock & lk) noexcept { bool scheduler::has_ready_fibers() const noexcept { - return sched_algo_->has_ready_fibers(); + return algo_->has_ready_fibers(); } void -scheduler::set_sched_algo( std::unique_ptr< sched_algorithm > algo) noexcept { +scheduler::set_algo( std::unique_ptr< algo::algorithm > algo) noexcept { // move remaining cotnext in current scheduler to new one - while ( sched_algo_->has_ready_fibers() ) { - algo->awakened( sched_algo_->pick_next() ); + while ( algo_->has_ready_fibers() ) { + algo->awakened( algo_->pick_next() ); } - sched_algo_ = std::move( algo); + algo_ = std::move( algo); } void @@ -375,7 +375,7 @@ scheduler::attach_dispatcher_context( intrusive_ptr< context > dispatcher_ctx) n // the dispatcher-context is resumed and // scheduler::dispatch() is executed dispatcher_ctx_->scheduler_ = this; - sched_algo_->awakened( dispatcher_ctx_.get() ); + algo_->awakened( dispatcher_ctx_.get() ); } void