0
0
Fork 0
mirror of https://github.com/matrix-construct/construct synced 2024-11-10 12:01:15 +01:00

ircd::ctx: Support user-supplied stacks.

This commit is contained in:
Jason Volk 2020-10-14 01:34:23 -07:00
parent 28eaf63543
commit ad41fb69a9
4 changed files with 129 additions and 98 deletions

View file

@ -64,6 +64,11 @@ struct ircd::ctx::context
ctx *detach(); // other calls undefined after this call ctx *detach(); // other calls undefined after this call
// Note: Constructing with DETACH flag makes any further use of this object undefined. // Note: Constructing with DETACH flag makes any further use of this object undefined.
context(const string_view &name,
const mutable_buffer &stack,
const flags &,
function);
context(const string_view &name, context(const string_view &name,
const size_t &stack_size, const size_t &stack_size,
const flags &, const flags &,

View file

@ -15,13 +15,15 @@ namespace ircd::ctx
struct ircd::ctx::stack struct ircd::ctx::stack
{ {
struct allocator;
mutable_buffer buf; // complete allocation mutable_buffer buf; // complete allocation
uintptr_t base {0}; // assigned when spawned uintptr_t base {0}; // base frame pointer
size_t max {0}; // User given stack size size_t max {0}; // User given stack size
size_t at {0}; // Updated for profiling at sleep size_t at {0}; // Updated for profiling at sleep
size_t peak {0}; // Updated for profiling; maximum size_t peak {0}; // Updated for profiling; maximum
stack(const size_t &max); stack(const mutable_buffer &) noexcept;
static const stack &get(const ctx &) noexcept; static const stack &get(const ctx &) noexcept;
static stack &get(ctx &) noexcept; static stack &get(ctx &) noexcept;

View file

@ -63,9 +63,14 @@ ircd::ctx::ctx::ios_handler
&ios_desc &ios_desc
}; };
/// Points to the next context to spawn (internal use)
[[gnu::visibility("internal")]]
decltype(ircd::ctx::ctx::spawning)
ircd::ctx::ctx::spawning;
/// Internal context struct ctor /// Internal context struct ctor
ircd::ctx::ctx::ctx(const string_view &name, ircd::ctx::ctx::ctx(const string_view &name,
const size_t &stack_max, const ircd::ctx::stack &stack,
const context::flags &flags) const context::flags &flags)
:name :name
{ {
@ -81,7 +86,7 @@ ircd::ctx::ctx::ctx(const string_view &name,
} }
,stack ,stack
{ {
stack_max stack
} }
{ {
} }
@ -106,9 +111,14 @@ ircd::ctx::ctx::spawn(context::function func)
boost::coroutines::no_stack_unwind, boost::coroutines::no_stack_unwind,
}; };
const scope_restore spawning
{
ircd::ctx::ctx::spawning, this
};
auto bound auto bound
{ {
std::bind(&ctx::operator(), this, ph::_1, ph::_2, std::move(func)) std::bind(&ctx::operator(), this, ph::_1, std::move(func))
}; };
auto *const parent_context auto *const parent_context
@ -142,7 +152,6 @@ ircd::ctx::ctx::spawn(context::function func)
void void
IRCD_CTX_STACK_PROTECT IRCD_CTX_STACK_PROTECT
ircd::ctx::ctx::operator()(boost::asio::yield_context yc, ircd::ctx::ctx::operator()(boost::asio::yield_context yc,
const mutable_buffer &stack_buf,
const std::function<void ()> func) const std::function<void ()> func)
noexcept try noexcept try
{ {
@ -150,7 +159,6 @@ noexcept try
ircd::ctx::current = this; ircd::ctx::current = this;
this->yc = &yc; this->yc = &yc;
notes = 1; notes = 1;
stack.buf = stack_buf;
stack.base = uintptr_t(__builtin_frame_address(0)); stack.base = uintptr_t(__builtin_frame_address(0));
const unwind atexit{[this] const unwind atexit{[this]
{ {
@ -956,36 +964,6 @@ noexcept
} }
#endif #endif
//////////////////////////////////////////////////////////////////////////////
//
// ctx/stack.h
//
[[gnu::hot]]
ircd::ctx::stack &
ircd::ctx::stack::get(ctx &ctx)
noexcept
{
return ctx.stack;
}
[[gnu::hot]]
const ircd::ctx::stack &
ircd::ctx::stack::get(const ctx &ctx)
noexcept
{
return ctx.stack;
}
//
// stack::stack
//
ircd::ctx::stack::stack(const size_t &max)
:max{max}
{
}
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// //
// ctx/continuation.h // ctx/continuation.h
@ -1174,12 +1152,23 @@ ircd::ctx::context::context(const string_view &name,
const size_t &stack_sz, const size_t &stack_sz,
const flags &flags, const flags &flags,
function func) function func)
:context
{
name, {nullptr, DEFAULT_STACK_SIZE}, flags, std::move(func)
}
{
}
ircd::ctx::context::context(const string_view &name,
const mutable_buffer &stack,
const flags &flags,
function func)
:c :c
{ {
std::make_unique<ctx> std::make_unique<ctx>
( (
name, name,
stack_sz, stack,
!current? flags | POST : flags !current? flags | POST : flags
) )
} }
@ -3087,42 +3076,77 @@ noexcept
return c.node; return c.node;
} }
/////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
// //
// (internal) stack_allocator // ctx/stack.h
// //
namespace ircd::ctx [[gnu::hot]]
ircd::ctx::stack &
ircd::ctx::stack::get(ctx &ctx)
noexcept
{ {
struct stack_allocator; return ctx.stack;
} }
[[gnu::hot]]
const ircd::ctx::stack &
ircd::ctx::stack::get(const ctx &ctx)
noexcept
{
return ctx.stack;
}
//
// stack::stack
//
ircd::ctx::stack::stack(const mutable_buffer &buf)
noexcept
:buf
{
buf
}
,max
{
ircd::size(buf)
}
{
}
//
// stack::allocator
//
struct [[gnu::visibility("hidden")]] struct [[gnu::visibility("hidden")]]
ircd::ctx::stack_allocator ircd::ctx::stack::allocator
{ {
using stack_context = boost::coroutines::stack_context; using stack_context = boost::coroutines::stack_context;
mutable_buffer &buf; mutable_buffer &buf;
bool owner {false};
void allocate(stack_context &, size_t size); void allocate(stack_context &, size_t size);
void deallocate(stack_context &); void deallocate(stack_context &);
}; };
void void
ircd::ctx::stack_allocator::allocate(stack_context &c, ircd::ctx::stack::allocator::allocate(stack_context &c,
size_t size) size_t size)
{ {
assert(size >= traits_type::minimum_size());
assert(traits_type::is_unbounded() || (traits_type::maximum_size() >= size));
static const auto &alignment static const auto &alignment
{ {
info::page_size info::page_size
}; };
unique_mutable_buffer buf unique_mutable_buffer umb
{ {
size, alignment null(this->buf)? size: 0, alignment
};
const mutable_buffer &buf
{
umb? umb: this->buf
}; };
c.size = ircd::size(buf); c.size = ircd::size(buf);
@ -3132,26 +3156,26 @@ ircd::ctx::stack_allocator::allocate(stack_context &c,
c.valgrind_stack_id = VALGRIND_STACK_REGISTER(c.sp, ircd::data(buf)); c.valgrind_stack_id = VALGRIND_STACK_REGISTER(c.sp, ircd::data(buf));
#endif #endif
this->buf = buf.release(); this->owner = bool(umb);
this->buf = umb? umb.release(): this->buf;
} }
void void
ircd::ctx::stack_allocator::deallocate(stack_context &c) ircd::ctx::stack::allocator::deallocate(stack_context &c)
{ {
assert(c.sp); assert(c.sp);
assert(traits_type::minimum_size() <= c.size);
assert(traits_type::is_unbounded() || (traits_type::maximum_size() >= c.size));
#if defined(BOOST_USE_VALGRIND) #if defined(BOOST_USE_VALGRIND)
VALGRIND_STACK_DEREGISTER(c.valgrind_stack_id) VALGRIND_STACK_DEREGISTER(c.valgrind_stack_id)
#endif #endif
void *const base const auto base
{ {
static_cast<uint8_t *>(c.sp) - c.size (reinterpret_cast<uintptr_t>(c.sp) - c.size)
& boolmask<uintptr_t>(owner)
}; };
std::free(base); std::free(reinterpret_cast<void *>(base));
} }
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
@ -3174,54 +3198,20 @@ boost::asio::detail::spawn_data
weak_ptr<callee_type> coro_; weak_ptr<callee_type> coro_;
Function function_; Function function_;
Handler handler_; Handler handler_;
ircd::mutable_buffer stack_; ircd::ctx::ctx *ctrl;
template<class H, template<class H,
class F> class F>
spawn_data(H&& handler, bool call_handler, F&& function) spawn_data(H&& handler, bool call_handler, F&& function)
:function_(std::move(function)) :function_(std::move(function))
,handler_(std::move(handler)) ,handler_(std::move(handler))
,ctrl{ircd::ctx::ctx::spawning}
{ {
assert(call_handler); assert(call_handler);
assert(ctrl);
} }
}; };
template<class Function>
struct [[gnu::visibility("hidden")]]
boost::asio::detail::spawn_helper
<
boost::asio::executor_binder<void (*)(), boost::asio::strand<boost::asio::executor>>,
Function
>
{
using Handler = boost::asio::executor_binder<void (*)(), boost::asio::strand<boost::asio::executor>>;
using callee_type = typename basic_yield_context<Handler>::callee_type;
void operator()() // push
{
ircd::ctx::stack_allocator allocator
{
data_->stack_
};
const auto coro
{
std::make_shared<callee_type>
(
coro_entry_point<Handler, Function>{data_},
attributes_,
allocator
)
};
data_->coro_ = coro;
(*coro)();
}
shared_ptr<spawn_data<Handler, Function>> data_;
boost::coroutines::attributes attributes_;
};
template<class Function> template<class Function>
struct [[gnu::visibility("hidden")]] struct [[gnu::visibility("hidden")]]
boost::asio::detail::coro_entry_point boost::asio::detail::coro_entry_point
@ -3237,7 +3227,7 @@ boost::asio::detail::coro_entry_point
{ {
const auto data const auto data
{ {
data_ this->data
}; };
basic_yield_context<Handler> yc basic_yield_context<Handler> yc
@ -3245,11 +3235,44 @@ boost::asio::detail::coro_entry_point
data->coro_, ca, data->handler_ data->coro_, ca, data->handler_
}; };
(data->function_)(yc, data->stack_); (data->function_)(yc);
(data->handler_)(); (data->handler_)();
} }
shared_ptr<spawn_data<Handler, Function>> data;
};
// Hooks the first push phase of coroutine spawn to supply our own stack
// allocator.
template<class Function>
struct [[gnu::visibility("hidden")]]
boost::asio::detail::spawn_helper
<
boost::asio::executor_binder<void (*)(), boost::asio::strand<boost::asio::executor>>,
Function
>
{
using Handler = boost::asio::executor_binder<void (*)(), boost::asio::strand<boost::asio::executor>>;
using callee_type = typename basic_yield_context<Handler>::callee_type;
void operator()() // push
{
const auto coro
{
std::make_shared<callee_type>
(
coro_entry_point<Handler, Function>{data_},
attributes_,
ircd::ctx::stack::allocator{data_->ctrl->stack.buf}
)
};
data_->coro_ = coro;
(*coro)();
}
shared_ptr<spawn_data<Handler, Function>> data_; shared_ptr<spawn_data<Handler, Function>> data_;
boost::coroutines::attributes attributes_;
}; };
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////

View file

@ -33,6 +33,7 @@ struct ircd::ctx::ctx
static uint64_t id_ctr; // monotonic static uint64_t id_ctr; // monotonic
static ios::descriptor ios_desc; static ios::descriptor ios_desc;
static ios::handler ios_handler; static ios::handler ios_handler;
static ctx *spawning;
uint64_t id {++id_ctr}; // Unique runtime ID uint64_t id {++id_ctr}; // Unique runtime ID
string_view name; // User given name (optional) string_view name; // User given name (optional)
@ -61,11 +62,11 @@ struct ircd::ctx::ctx
bool wait(); // yield context to ios queue (returns on this resume) bool wait(); // yield context to ios queue (returns on this resume)
void jump(); // jump to context directly (returns on your resume) void jump(); // jump to context directly (returns on your resume)
void operator()(boost::asio::yield_context, const mutable_buffer &, const std::function<void ()>) noexcept; void operator()(boost::asio::yield_context, const std::function<void ()>) noexcept;
void spawn(context::function func); void spawn(context::function func);
ctx(const string_view &name = "<noname>"_sv, ctx(const string_view &name = "<noname>"_sv,
const size_t &stack_max = DEFAULT_STACK_SIZE, const ircd::ctx::stack & = mutable_buffer{nullptr, DEFAULT_STACK_SIZE},
const context::flags & = (context::flags)0U); const context::flags & = (context::flags)0U);
ctx(ctx &&) = delete; ctx(ctx &&) = delete;