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