0
0
Fork 0
mirror of https://github.com/matrix-construct/construct synced 2024-12-26 23:44:01 +01:00

ircd::ctx::ole: Use a ctx::latch for the kick.

This commit is contained in:
Jason Volk 2019-07-20 14:46:59 -07:00
parent 9972d58b29
commit e4372253a8

View file

@ -54,18 +54,15 @@ noexcept
ircd::ctx::ole::offload::offload(const opts &opts, ircd::ctx::ole::offload::offload(const opts &opts,
const closure &func) const closure &func)
{ {
assert(current);
assert(opts.concurrency == 1); // not yet implemented assert(opts.concurrency == 1); // not yet implemented
bool done(false); // Prepare the offload package on our stack here. These objects will
auto *const context(current); // remain here for the duration of the offload.
const auto kick([&context, &done] latch latch{1};
{
done = true;
notify(*context);
});
std::exception_ptr eptr; std::exception_ptr eptr;
auto closure([&func, &eptr, &context, &kick] auto *const context(current);
auto closure([&func, &latch, &eptr, &context]
() noexcept () noexcept
{ {
try try
@ -74,35 +71,38 @@ ircd::ctx::ole::offload::offload(const opts &opts,
} }
catch(...) catch(...)
{ {
// Note that the write to eptr is taking place on a different
// thread from where we created the eptr.
eptr = std::current_exception(); eptr = std::current_exception();
} }
// To wake the context on the IRCd thread we give it the kick // The ctx::signal() is a special device which executes the closure
signal(*context, kick); // as soon as the target context is not currently running on any
// thread. This has the ability to provide the cross-thread
// synchronization we need to hit the latch from this thread.
assert(context);
signal(*context, [&latch]
{
assert(!latch.is_ready());
latch.count_down();
});
}); });
// interrupt(ctx) is suppressed while this context has offloaded some work // interrupt(ctx) is suppressed while this context has offloaded some work
// to another thread. This context must stay right here and not disappear // to another thread. This context must stay right here and not disappear
// until the other thread signals back. Note that the destructor is // until the other thread signals back. Note that the destructor is
// capable of throwing an interrupt that was received during this scope. // capable of throwing an interrupt that was received during this scope.
// const uninterruptible uninterruptible;
ole::push(std::move(closure)); // scope address required for clang-7
latch.wait();
// Don't throw any exception if there is a pending interrupt for this ctx. // Don't throw any exception if there is a pending interrupt for this ctx.
// Two exceptions will be thrown in that case and if there's an interrupt // Two exceptions will be thrown in that case and if there's an interrupt
// we don't care about eptr anyway. // we don't care about eptr anyway.
const uninterruptible uninterruptible; if(likely(!interruption_requested()))
if(unlikely(eptr))
// scope address required for clang-7 std::rethrow_exception(eptr);
ole::push(std::move(closure)); do
{
wait();
}
while(!done);
if(unlikely(interruption_requested()))
return;
if(eptr)
std::rethrow_exception(eptr);
} }
void void
ircd::ctx::ole::push(offload::closure &&func) ircd::ctx::ole::push(offload::closure &&func)