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:
parent
9972d58b29
commit
e4372253a8
1 changed files with 26 additions and 26 deletions
|
@ -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)
|
||||||
|
|
Loading…
Reference in a new issue