make it possible to provide custom stack allocator types to schedulers

This commit is contained in:
q66 2017-03-25 15:01:14 +01:00
parent f93b08a924
commit b1d95faa41

View file

@ -111,7 +111,10 @@ namespace detail {
}; };
} }
struct thread_scheduler: scheduler { template<typename SA>
struct basic_thread_scheduler: scheduler {
basic_thread_scheduler(SA &&sa = SA{}): p_stacks(std::move(sa)) {}
template<typename F, typename ...A> template<typename F, typename ...A>
auto start(F &&func, A &&...args) -> std::result_of_t<F(A...)> { auto start(F &&func, A &&...args) -> std::result_of_t<F(A...)> {
detail::current_scheduler_owner iface{*this}; detail::current_scheduler_owner iface{*this};
@ -144,12 +147,15 @@ struct thread_scheduler: scheduler {
} }
stack_context allocate_stack() { stack_context allocate_stack() {
/* TODO: store the allocator properly, for now it's fine */ return p_stacks.allocate();
return fixedsize_stack{}.allocate();
} }
void deallocate_stack(stack_context &st) noexcept { void deallocate_stack(stack_context &st) noexcept {
fixedsize_stack{}.deallocate(st); p_stacks.deallocate(st);
}
void reserve_stacks(size_t n) {
p_stacks.reserve(n);
} }
private: private:
@ -174,11 +180,14 @@ private:
} }
} }
SA p_stacks;
std::list<std::thread> p_threads; std::list<std::thread> p_threads;
std::thread p_dead; std::thread p_dead;
std::mutex p_lock; std::mutex p_lock;
}; };
using thread_scheduler = basic_thread_scheduler<stack_pool>;
namespace detail { namespace detail {
struct csched_task; struct csched_task;
@ -235,7 +244,7 @@ namespace detail {
}; };
} }
template<typename TR, bool Protected> template<typename SA>
struct basic_simple_coroutine_scheduler: scheduler { struct basic_simple_coroutine_scheduler: scheduler {
private: private:
/* simple one just for channels */ /* simple one just for channels */
@ -273,11 +282,8 @@ private:
}; };
public: public:
basic_simple_coroutine_scheduler( basic_simple_coroutine_scheduler(SA &&sa = SA{}):
size_t ss = TR::default_size(), p_stacks(std::move(sa))
size_t cs = basic_stack_pool<TR, Protected>::DEFAULT_CHUNK_SIZE
):
p_stacks(ss, cs), p_coros()
{} {}
template<typename F, typename ...A> template<typename F, typename ...A>
@ -286,7 +292,9 @@ public:
using R = std::result_of_t<F(A...)>; using R = std::result_of_t<F(A...)>;
basic_fixedsize_stack<TR, Protected> sa{detail::stack_main_size()}; basic_fixedsize_stack<typename SA::traits_type, false> sa{
detail::stack_main_size()
};
if constexpr(std::is_same_v<R, void>) { if constexpr(std::is_same_v<R, void>) {
if constexpr(sizeof...(A) == 0) { if constexpr(sizeof...(A) == 0) {
@ -352,18 +360,14 @@ private:
} }
} }
basic_stack_pool<TR, Protected> p_stacks; SA p_stacks;
std::list<detail::csched_task> p_coros; std::list<detail::csched_task> p_coros;
typename std::list<detail::csched_task>::iterator p_idx = p_coros.end(); typename std::list<detail::csched_task>::iterator p_idx = p_coros.end();
}; };
using simple_coroutine_scheduler = using simple_coroutine_scheduler = basic_simple_coroutine_scheduler<stack_pool>;
basic_simple_coroutine_scheduler<stack_traits, false>;
using protected_simple_coroutine_scheduler = template<typename SA>
basic_simple_coroutine_scheduler<stack_traits, true>;
template<typename TR, bool Protected>
struct basic_coroutine_scheduler: scheduler { struct basic_coroutine_scheduler: scheduler {
private: private:
struct task_cond; struct task_cond;
@ -381,9 +385,9 @@ private:
task *next_waiting = nullptr; task *next_waiting = nullptr;
titer pos; titer pos;
template<typename F, typename SA> template<typename F, typename TSA>
task(F &&f, SA &&sa): task(F &&f, TSA &&sa):
p_func(std::forward<F>(f), std::forward<SA>(sa)) p_func(std::forward<F>(f), std::forward<TSA>(sa))
{} {}
void operator()() { void operator()() {
@ -442,11 +446,8 @@ private:
}; };
public: public:
basic_coroutine_scheduler( basic_coroutine_scheduler(SA &&sa = SA{}):
size_t ss = TR::default_size(), p_stacks(std::move(sa))
size_t cs = basic_stack_pool<TR, Protected>::DEFAULT_CHUNK_SIZE
):
p_stacks(ss, cs)
{} {}
~basic_coroutine_scheduler() {} ~basic_coroutine_scheduler() {}
@ -463,7 +464,9 @@ public:
/* the default 64 KiB stack won't cut it for main, allocate a stack /* the default 64 KiB stack won't cut it for main, allocate a stack
* which matches the size of the process stack outside of the pool * which matches the size of the process stack outside of the pool
*/ */
basic_fixedsize_stack<TR, Protected> sa{detail::stack_main_size()}; basic_fixedsize_stack<typename SA::traits_type, false> sa{
detail::stack_main_size()
};
if constexpr(std::is_same_v<R, void>) { if constexpr(std::is_same_v<R, void>) {
spawn_add(sa, std::move(func), std::forward<A>(args)...); spawn_add(sa, std::move(func), std::forward<A>(args)...);
@ -506,13 +509,13 @@ public:
} }
private: private:
template<typename SA, typename F, typename ...A> template<typename TSA, typename F, typename ...A>
void spawn_add(SA &&sa, F &&func, A &&...args) { void spawn_add(TSA &&sa, F &&func, A &&...args) {
task *t = nullptr; task *t = nullptr;
if constexpr(sizeof...(A) == 0) { if constexpr(sizeof...(A) == 0) {
t = &p_available.emplace_back( t = &p_available.emplace_back(
std::forward<F>(func), std::forward<F>(func),
std::forward<SA>(sa) std::forward<TSA>(sa)
); );
} else { } else {
t = &p_available.emplace_back( t = &p_available.emplace_back(
@ -521,7 +524,7 @@ private:
)]() mutable { )]() mutable {
lfunc(); lfunc();
}, },
std::forward<SA>(sa) std::forward<TSA>(sa)
); );
} }
t->pos = --p_available.end(); t->pos = --p_available.end();
@ -619,17 +622,13 @@ private:
std::condition_variable p_cond; std::condition_variable p_cond;
std::mutex p_lock; std::mutex p_lock;
basic_stack_pool<TR, Protected> p_stacks; SA p_stacks;
tlist p_available; tlist p_available;
tlist p_waiting; tlist p_waiting;
tlist p_running; tlist p_running;
}; };
using coroutine_scheduler = using coroutine_scheduler = basic_coroutine_scheduler<stack_pool>;
basic_coroutine_scheduler<stack_traits, false>;
using protected_coroutine_scheduler =
basic_coroutine_scheduler<stack_traits, true>;
template<typename F, typename ...A> template<typename F, typename ...A>
inline void spawn(F &&func, A &&...args) { inline void spawn(F &&func, A &&...args) {