Commit bb70495b authored by Lee Howes's avatar Lee Howes Committed by Facebook GitHub Bot

Add weakDetachOnGlobalCPUExecutorAfter

Summary: Adds a form of detach that is safe to use in recursive code. Detaches a task after a delay, and checks for availability of the global executor at that point to decouple shutdown from the delayed detach.

Reviewed By: andriigrynenko

Differential Revision: D24174495

fbshipit-source-id: e6b22485a817c18319c897fd51c3f8ba81d13041
parent b0e23aef
......@@ -131,11 +131,16 @@ LeakySingleton<GlobalExecutor<IOExecutor>> gGlobalIOExecutor([] {
// Default global IO executor is an IOThreadPoolExecutor.
[] { return getImmutable<IOExecutor>(); });
});
} // namespace
namespace folly {
namespace detail {
std::shared_ptr<Executor> tryGetImmutableCPUPtr() {
return getImmutable<Executor>();
}
} // namespace detail
Executor::KeepAlive<> getGlobalCPUExecutor() {
auto executorPtrPtr = getImmutablePtrPtr<Executor>();
if (!executorPtrPtr) {
......
......@@ -23,6 +23,10 @@
namespace folly {
namespace detail {
std::shared_ptr<Executor> tryGetImmutableCPUPtr();
}
/**
* Return the global executor.
* The global executor is a CPU thread pool and is immutable.
......
......@@ -2533,6 +2533,17 @@ void detachOnGlobalCPUExecutor(folly::SemiFuture<T>&& fut) {
detachOn(folly::getGlobalCPUExecutor(), std::move(fut));
}
template <class T>
void maybeDetachOnGlobalExecutorAfter(
HighResDuration dur,
folly::SemiFuture<T>&& fut) {
sleep(dur).toUnsafeFuture().thenValue([fut = std::move(fut)](auto&&) mutable {
if (auto ptr = folly::detail::tryGetImmutableCPUPtr()) {
detachOn(folly::getKeepAliveToken(ptr.get()), std::move(fut));
}
});
}
template <class T>
void detachWithoutExecutor(folly::SemiFuture<T>&& fut) {
auto executor = futures::detail::stealDeferredExecutor(fut);
......
......@@ -452,6 +452,14 @@ void detachOn(folly::Executor::KeepAlive<> exec, folly::SemiFuture<T>&& fut);
template <class T>
void detachOnGlobalCPUExecutor(folly::SemiFuture<T>&& fut);
// Detach the SemiFuture onto the global CPU executor after dur.
// This will only hold a weak ref to the global executor and during
// shutdown will cleanly drop the work.
template <class T>
void maybeDetachOnGlobalExecutorAfter(
HighResDuration dur,
folly::SemiFuture<T>&& fut);
// Detach the SemiFuture with no executor.
// NOTE: If there is deferred work of any sort on this SemiFuture
// will leak and not be run.
......
......@@ -1442,7 +1442,7 @@ TEST(Future, NoThrow) {
}
TEST(Future, DetachTest) {
folly::Baton<> b1, b2, b3;
folly::Baton<> b1, b2, b3, b4;
folly::ManualExecutor exec;
std::atomic<int> result(0);
......@@ -1468,11 +1468,18 @@ TEST(Future, DetachTest) {
})
.semi());
folly::futures::maybeDetachOnGlobalExecutorAfter(
std::chrono::milliseconds{100}, makeSemiFuture().deferValue([&](auto&&) {
result++;
b4.post();
}));
exec.drain();
b1.wait();
b2.wait();
b3.wait();
EXPECT_TRUE(result == 3);
b4.wait();
EXPECT_TRUE(result == 4);
}
TEST(Future, SimpleGet) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment