Commit a7d768ee authored by Pranav Thulasiram Bhat's avatar Pranav Thulasiram Bhat Committed by Facebook GitHub Bot

Awaiting futures

Summary:
This diff adds `future_wait`, an annotated helper to run blocking `get` operations on futures.

`future_wait` will help annotate functions (and their caller stack) that block on futures.

For semifutures, deferred work is performed on fiber-main context, so there is no concern of bleeding fibers.

Reviewed By: yfeldblum

Differential Revision: D21965552

fbshipit-source-id: 79941c3b73c67d63d83dcdc778c62a0fc9051de3
parent 3b5ce36b
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include <folly/fibers/async/Async.h>
#include <folly/futures/Future.h>
namespace folly {
namespace fibers {
namespace async {
/**
* Async tagged helpers to perform blocking future operations. Ensures that
* functions that block on futures are annotated as well.
*/
template <typename T>
Async<T> futureWait(SemiFuture<T>&& semi) {
// Any deferred work will be executed inline on main-context
return std::move(semi).get();
}
template <typename T>
Async<T> futureWait(Future<T>&& fut) {
return std::move(fut).get();
}
} // namespace async
} // namespace fibers
} // namespace folly
......@@ -39,6 +39,7 @@
#include <folly/fibers/WhenN.h>
#include <folly/fibers/async/Async.h>
#include <folly/fibers/async/Baton.h>
#include <folly/fibers/async/Future.h>
#include <folly/io/async/ScopedEventBaseThread.h>
#include <folly/portability/GTest.h>
......@@ -2713,3 +2714,52 @@ TEST(FiberManager, asyncBaton) {
})
.getVia(&evb));
}
TEST(FiberManager, asyncFuture) {
folly::EventBase evb;
auto& fm = getFiberManager(evb);
// Return format: Info about where continuation runs (thread_id,
// in_fiber_loop, on_active_fiber)
auto getSemiFuture = []() {
return folly::futures::sleep(std::chrono::milliseconds(1))
.defer([](auto&&) {
return std::make_tuple(
std::this_thread::get_id(),
FiberManager::getFiberManagerUnsafe() != nullptr,
onFiber());
});
};
fm.addTaskFuture([&]() {
auto this_thread_id = std::this_thread::get_id();
{
// Unspecified executor: Deferred work will be executed inline on
// producer thread
auto res = async::init_await(
async::futureWait(getSemiFuture().toUnsafeFuture()));
EXPECT_NE(this_thread_id, std::get<0>(res));
EXPECT_FALSE(std::get<1>(res));
EXPECT_FALSE(std::get<2>(res));
}
{
// Specified executor: Deferred work will be executed on evb
auto res =
async::init_await(async::futureWait(getSemiFuture().via(&evb)));
EXPECT_EQ(this_thread_id, std::get<0>(res));
EXPECT_FALSE(std::get<1>(res));
EXPECT_FALSE(std::get<2>(res));
}
{
// Unspecified executor: Deferred work will be executed inline on
// consumer thread main-context
auto res = async::init_await(async::futureWait(getSemiFuture()));
EXPECT_EQ(this_thread_id, std::get<0>(res));
EXPECT_TRUE(std::get<1>(res));
EXPECT_FALSE(std::get<2>(res));
}
})
.getVia(&evb);
}
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