2018-02-04 03:22:01 +01:00
|
|
|
// Matrix Construct
|
|
|
|
//
|
|
|
|
// Copyright (C) Matrix Construct Developers, Authors & Contributors
|
|
|
|
// Copyright (C) 2016-2018 Jason Volk <jason@zemos.net>
|
|
|
|
//
|
|
|
|
// Permission to use, copy, modify, and/or distribute this software for any
|
|
|
|
// purpose with or without fee is hereby granted, provided that the above
|
|
|
|
// copyright notice and this permission notice is present in all copies. The
|
|
|
|
// full license for this software is available in the LICENSE file.
|
2016-09-21 23:15:49 +02:00
|
|
|
|
|
|
|
#pragma once
|
|
|
|
#define HAVE_IRCD_CTX_POOL_H
|
|
|
|
|
2017-08-28 23:51:22 +02:00
|
|
|
namespace ircd::ctx
|
|
|
|
{
|
|
|
|
struct pool;
|
2018-12-17 00:41:32 +01:00
|
|
|
|
|
|
|
const string_view &name(const pool &);
|
2018-12-28 21:57:32 +01:00
|
|
|
void debug_stats(const pool &);
|
2017-08-28 23:51:22 +02:00
|
|
|
}
|
2016-09-21 23:15:49 +02:00
|
|
|
|
2018-12-28 21:57:32 +01:00
|
|
|
struct ircd::ctx::pool
|
2016-09-21 23:15:49 +02:00
|
|
|
{
|
2018-12-28 21:57:32 +01:00
|
|
|
struct opts;
|
2016-09-21 23:15:49 +02:00
|
|
|
using closure = std::function<void ()>;
|
|
|
|
|
2018-12-28 21:57:32 +01:00
|
|
|
static const string_view default_name;
|
|
|
|
static const opts default_opts;
|
|
|
|
|
|
|
|
string_view name {default_name};
|
|
|
|
const opts *opt {&default_opts};
|
|
|
|
size_t running {0};
|
|
|
|
size_t working {0};
|
2018-12-28 00:45:02 +01:00
|
|
|
dock q_max;
|
2018-09-19 01:45:04 +02:00
|
|
|
queue<closure> q;
|
2016-09-21 23:15:49 +02:00
|
|
|
std::vector<context> ctxs;
|
|
|
|
|
2018-12-24 21:06:05 +01:00
|
|
|
void work();
|
2018-03-15 21:44:29 +01:00
|
|
|
void main() noexcept;
|
2016-09-21 23:15:49 +02:00
|
|
|
|
|
|
|
public:
|
2018-12-28 21:57:32 +01:00
|
|
|
explicit operator const opts &() const;
|
2018-12-17 00:41:32 +01:00
|
|
|
|
2016-11-29 16:23:38 +01:00
|
|
|
// indicators
|
2018-12-17 00:41:32 +01:00
|
|
|
auto size() const { return ctxs.size(); }
|
|
|
|
auto queued() const { return q.size(); }
|
|
|
|
auto active() const { return working; }
|
2018-12-28 21:57:32 +01:00
|
|
|
auto avail() const { return running - active(); }
|
2018-12-17 00:41:32 +01:00
|
|
|
auto pending() const { return active() + queued(); }
|
2019-09-19 05:03:24 +02:00
|
|
|
bool wouldblock() const;
|
2018-12-17 00:41:32 +01:00
|
|
|
|
|
|
|
// dispatch to pool
|
|
|
|
template<class F, class... A> future_void<F, A...> async(F&&, A&&...);
|
|
|
|
template<class F, class... A> future_value<F, A...> async(F&&, A&&...);
|
|
|
|
void operator()(closure);
|
2016-09-21 23:15:49 +02:00
|
|
|
|
2016-11-29 16:23:38 +01:00
|
|
|
// control panel
|
2016-09-21 23:15:49 +02:00
|
|
|
void add(const size_t & = 1);
|
|
|
|
void del(const size_t & = 1);
|
2018-08-22 23:08:03 +02:00
|
|
|
void set(const size_t &);
|
2018-12-25 01:20:03 +01:00
|
|
|
void min(const size_t &);
|
2018-08-20 00:55:35 +02:00
|
|
|
void terminate();
|
2016-11-29 16:23:38 +01:00
|
|
|
void interrupt();
|
2017-09-20 04:01:37 +02:00
|
|
|
void join();
|
2016-09-21 23:15:49 +02:00
|
|
|
|
2018-12-28 21:57:32 +01:00
|
|
|
pool(const string_view &name = default_name,
|
|
|
|
const opts & = default_opts);
|
2016-11-29 16:23:38 +01:00
|
|
|
|
|
|
|
pool(pool &&) = delete;
|
|
|
|
pool(const pool &) = delete;
|
|
|
|
pool &operator=(pool &&) = delete;
|
|
|
|
pool &operator=(const pool &) = delete;
|
2016-09-21 23:15:49 +02:00
|
|
|
~pool() noexcept;
|
2017-10-19 09:58:43 +02:00
|
|
|
|
2018-12-17 00:41:32 +01:00
|
|
|
friend const string_view &name(const pool &);
|
2017-10-19 09:58:43 +02:00
|
|
|
friend void debug_stats(const pool &);
|
2016-09-21 23:15:49 +02:00
|
|
|
};
|
|
|
|
|
2018-12-28 21:57:32 +01:00
|
|
|
struct ircd::ctx::pool::opts
|
|
|
|
{
|
|
|
|
/// When the pool spawns a new context this will be the stack size it has.
|
|
|
|
size_t stack_size { DEFAULT_STACK_SIZE };
|
|
|
|
|
|
|
|
/// When the pool is constructed this will be how many contexts it spawns
|
|
|
|
/// This value may be ignored for static duration instances.
|
|
|
|
size_t initial_ctxs {0};
|
|
|
|
|
|
|
|
/// Hard-limit for jobs queued. A submit to the pool over this limit throws
|
|
|
|
/// an exception. Default is -1, effectively unlimited.
|
|
|
|
ssize_t queue_max_hard {-1};
|
|
|
|
|
|
|
|
/// Soft-limit for jobs queued. The behavior of the limit is configurable.
|
|
|
|
/// The default is 0, meaning if there is no context available to service
|
|
|
|
/// the request being submitted then the soft limit is immediately reached.
|
|
|
|
/// See the specific behavior options following this.
|
|
|
|
ssize_t queue_max_soft {0};
|
|
|
|
|
|
|
|
/// Yield a context submitting to the pool if it will violate the soft
|
|
|
|
/// limit. This is true by default. Note the default of 0 for the
|
|
|
|
/// soft-limit itself combined with this: by default there is no queueing
|
|
|
|
/// of jobs at all! This behavior purposely propagates flow control by
|
|
|
|
/// slowing down the submitting context and prevents flooding the queue.
|
|
|
|
/// This option has no effect if the submitter is not on any ircd::ctx.
|
|
|
|
bool queue_max_blocking {true};
|
|
|
|
|
|
|
|
/// Log a DWARNING (developer-warning level) when the soft limit is
|
|
|
|
/// exceeded. The soft-limit is never actually exceeded when contexts
|
|
|
|
/// are blocked from submitting (see: queue_max_blocking). This warning
|
|
|
|
/// will still be seen for submissions outside any ircd::ctx.
|
|
|
|
bool queue_max_dwarning {true};
|
2020-01-06 21:01:04 +01:00
|
|
|
|
|
|
|
/// IO priority nice value for contexts in this pool.
|
|
|
|
int8_t ionice {0};
|
|
|
|
|
|
|
|
/// Scheduler priority nice value for contexts in this pool.
|
|
|
|
int8_t nice {0};
|
2018-12-28 21:57:32 +01:00
|
|
|
};
|
|
|
|
|
2016-09-23 08:55:36 +02:00
|
|
|
template<class F,
|
|
|
|
class... A>
|
2017-08-28 23:51:22 +02:00
|
|
|
ircd::ctx::future_value<F, A...>
|
|
|
|
ircd::ctx::pool::async(F&& f,
|
|
|
|
A&&... a)
|
2016-09-23 08:55:36 +02:00
|
|
|
{
|
|
|
|
using R = typename std::result_of<F (A...)>::type;
|
|
|
|
|
2017-09-20 04:01:37 +02:00
|
|
|
auto func
|
|
|
|
{
|
|
|
|
std::bind(std::forward<F>(f), std::forward<A>(a)...)
|
|
|
|
};
|
|
|
|
|
2018-01-18 15:01:49 +01:00
|
|
|
promise<R> p;
|
|
|
|
future<R> ret{p};
|
2018-12-28 21:57:32 +01:00
|
|
|
operator()([p(std::move(p)), func(std::move(func))]
|
2016-09-23 08:55:36 +02:00
|
|
|
{
|
2018-01-18 15:01:49 +01:00
|
|
|
p.set_value(func());
|
2016-09-23 08:55:36 +02:00
|
|
|
});
|
|
|
|
|
2018-01-18 15:01:49 +01:00
|
|
|
return ret;
|
2016-09-23 08:55:36 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
template<class F,
|
|
|
|
class... A>
|
2017-08-28 23:51:22 +02:00
|
|
|
ircd::ctx::future_void<F, A...>
|
|
|
|
ircd::ctx::pool::async(F&& f,
|
|
|
|
A&&... a)
|
2016-09-23 08:55:36 +02:00
|
|
|
{
|
|
|
|
using R = typename std::result_of<F (A...)>::type;
|
|
|
|
|
2017-09-20 04:01:37 +02:00
|
|
|
auto func
|
|
|
|
{
|
|
|
|
std::bind(std::forward<F>(f), std::forward<A>(a)...)
|
|
|
|
};
|
|
|
|
|
2018-01-18 15:01:49 +01:00
|
|
|
promise<R> p;
|
|
|
|
future<R> ret{p};
|
2018-12-28 21:57:32 +01:00
|
|
|
operator()([p(std::move(p)), func(std::move(func))]
|
2016-09-23 08:55:36 +02:00
|
|
|
{
|
|
|
|
func();
|
2018-01-18 15:01:49 +01:00
|
|
|
p.set_value();
|
2016-09-23 08:55:36 +02:00
|
|
|
});
|
|
|
|
|
2018-01-18 15:01:49 +01:00
|
|
|
return ret;
|
2016-09-23 08:55:36 +02:00
|
|
|
}
|
2018-12-17 00:41:32 +01:00
|
|
|
|
|
|
|
inline ircd::ctx::pool::operator
|
2018-12-28 21:57:32 +01:00
|
|
|
const opts &()
|
2018-12-17 00:41:32 +01:00
|
|
|
const
|
|
|
|
{
|
2018-12-28 21:57:32 +01:00
|
|
|
assert(opt);
|
|
|
|
return *opt;
|
2018-12-17 00:41:32 +01:00
|
|
|
}
|