Commit 4762e080 authored by Tristan Rice's avatar Tristan Rice Committed by Facebook Github Bot

folly: propagate interrupts through thenError

Summary: The tagged/specific exception variant of thenError and deferError propagate interrupts where currently the untagged variant of thenError does not. As far as I can tell this was an oversight. This makes untagged thenError behave as expected.

Reviewed By: yfeldblum, mpark

Differential Revision: D18643814

fbshipit-source-id: 42688c4363de2f6b027766b19276b2e8ec6a48a8
parent d62f47c7
...@@ -1094,6 +1094,7 @@ typename std::enable_if< ...@@ -1094,6 +1094,7 @@ typename std::enable_if<
Future<T>>::type Future<T>>::type
Future<T>::thenError(tag_t<ExceptionType>, F&& func) && { Future<T>::thenError(tag_t<ExceptionType>, F&& func) && {
Promise<T> p; Promise<T> p;
p.core_->setInterruptHandlerNoLock(this->getCore().getInterruptHandler());
auto sf = p.getSemiFuture(); auto sf = p.getSemiFuture();
auto* ePtr = this->getExecutor(); auto* ePtr = this->getExecutor();
auto e = folly::getKeepAliveToken(ePtr ? *ePtr : InlineExecutor::instance()); auto e = folly::getKeepAliveToken(ePtr ? *ePtr : InlineExecutor::instance());
...@@ -1159,6 +1160,7 @@ Future<T>::thenError(F&& func) && { ...@@ -1159,6 +1160,7 @@ Future<T>::thenError(F&& func) && {
auto e = folly::getKeepAliveToken(ePtr ? *ePtr : InlineExecutor::instance()); auto e = folly::getKeepAliveToken(ePtr ? *ePtr : InlineExecutor::instance());
Promise<T> p; Promise<T> p;
p.core_->setInterruptHandlerNoLock(this->getCore().getInterruptHandler());
auto sf = p.getSemiFuture(); auto sf = p.getSemiFuture();
this->setCallback_([state = futures::detail::makeCoreCallbackState( this->setCallback_([state = futures::detail::makeCoreCallbackState(
std::move(p), std::forward<F>(func))]( std::move(p), std::forward<F>(func))](
...@@ -1192,6 +1194,7 @@ Future<T>::thenError(F&& func) && { ...@@ -1192,6 +1194,7 @@ Future<T>::thenError(F&& func) && {
auto e = folly::getKeepAliveToken(ePtr ? *ePtr : InlineExecutor::instance()); auto e = folly::getKeepAliveToken(ePtr ? *ePtr : InlineExecutor::instance());
Promise<T> p; Promise<T> p;
p.core_->setInterruptHandlerNoLock(this->getCore().getInterruptHandler());
auto sf = p.getSemiFuture(); auto sf = p.getSemiFuture();
this->setCallback_([state = futures::detail::makeCoreCallbackState( this->setCallback_([state = futures::detail::makeCoreCallbackState(
std::move(p), std::forward<F>(func))]( std::move(p), std::forward<F>(func))](
......
...@@ -92,3 +92,138 @@ TEST(Interrupt, semiFutureWithinTimedOut) { ...@@ -92,3 +92,138 @@ TEST(Interrupt, semiFutureWithinTimedOut) {
// Give it 100ms to time out and call the interrupt handler // Give it 100ms to time out and call the interrupt handler
EXPECT_TRUE(done.try_wait_for(std::chrono::milliseconds(100))); EXPECT_TRUE(done.try_wait_for(std::chrono::milliseconds(100)));
} }
TEST(Interrupt, futureThenValue) {
folly::TestExecutor ex(1);
Promise<folly::Unit> p;
bool flag = false;
p.setInterruptHandler([&](const exception_wrapper& /* e */) { flag = true; });
p.getFuture().thenValue([](folly::Unit&&) {}).cancel();
EXPECT_TRUE(flag);
}
TEST(Interrupt, semiFutureDeferValue) {
folly::TestExecutor ex(1);
Promise<folly::Unit> p;
bool flag = false;
p.setInterruptHandler([&](const exception_wrapper& /* e */) { flag = true; });
p.getSemiFuture().deferValue([](folly::Unit&&) {}).cancel();
EXPECT_TRUE(flag);
}
TEST(Interrupt, futureThenValueFuture) {
folly::TestExecutor ex(1);
Promise<folly::Unit> p;
bool flag = false;
p.setInterruptHandler([&](const exception_wrapper& /* e */) { flag = true; });
p.getFuture()
.thenValue([](folly::Unit&&) { return folly::makeFuture(); })
.cancel();
EXPECT_TRUE(flag);
}
TEST(Interrupt, semiFutureDeferValueSemiFuture) {
folly::TestExecutor ex(1);
Promise<folly::Unit> p;
bool flag = false;
p.setInterruptHandler([&](const exception_wrapper& /* e */) { flag = true; });
p.getSemiFuture()
.deferValue([](folly::Unit&&) { return folly::makeSemiFuture(); })
.cancel();
EXPECT_TRUE(flag);
}
TEST(Interrupt, futureThenError) {
folly::TestExecutor ex(1);
Promise<folly::Unit> p;
bool flag = false;
p.setInterruptHandler([&](const exception_wrapper& /* e */) { flag = true; });
p.getFuture().thenError([](const exception_wrapper& /* e */) {}).cancel();
EXPECT_TRUE(flag);
}
TEST(Interrupt, semiFutureDeferError) {
folly::TestExecutor ex(1);
Promise<folly::Unit> p;
bool flag = false;
p.setInterruptHandler([&](const exception_wrapper& /* e */) { flag = true; });
p.getSemiFuture()
.deferError([](const exception_wrapper& /* e */) {})
.cancel();
EXPECT_TRUE(flag);
}
TEST(Interrupt, futureThenErrorTagged) {
folly::TestExecutor ex(1);
Promise<folly::Unit> p;
bool flag = false;
p.setInterruptHandler([&](const exception_wrapper& /* e */) { flag = true; });
p.getFuture()
.thenError(
folly::tag_t<std::runtime_error>{},
[](const exception_wrapper& /* e */) {})
.cancel();
EXPECT_TRUE(flag);
}
TEST(Interrupt, semiFutureDeferErrorTagged) {
folly::TestExecutor ex(1);
Promise<folly::Unit> p;
bool flag = false;
p.setInterruptHandler([&](const exception_wrapper& /* e */) { flag = true; });
p.getSemiFuture()
.deferError(
folly::tag_t<std::runtime_error>{},
[](const exception_wrapper& /* e */) {})
.cancel();
EXPECT_TRUE(flag);
}
TEST(Interrupt, futureThenErrorFuture) {
folly::TestExecutor ex(1);
Promise<folly::Unit> p;
bool flag = false;
p.setInterruptHandler([&](const exception_wrapper& /* e */) { flag = true; });
p.getFuture()
.thenError([](const exception_wrapper& /* e */) { return makeFuture(); })
.cancel();
EXPECT_TRUE(flag);
}
TEST(Interrupt, semiFutureDeferErrorSemiFuture) {
folly::TestExecutor ex(1);
Promise<folly::Unit> p;
bool flag = false;
p.setInterruptHandler([&](const exception_wrapper& /* e */) { flag = true; });
p.getSemiFuture()
.deferError(
[](const exception_wrapper& /* e */) { return makeSemiFuture(); })
.cancel();
EXPECT_TRUE(flag);
}
TEST(Interrupt, futureThenErrorTaggedFuture) {
folly::TestExecutor ex(1);
Promise<folly::Unit> p;
bool flag = false;
p.setInterruptHandler([&](const exception_wrapper& /* e */) { flag = true; });
p.getFuture()
.thenError(
folly::tag_t<std::runtime_error>{},
[](const exception_wrapper& /* e */) { return makeFuture(); })
.cancel();
EXPECT_TRUE(flag);
}
TEST(Interrupt, semiFutureDeferErrorTaggedSemiFuture) {
folly::TestExecutor ex(1);
Promise<folly::Unit> p;
bool flag = false;
p.setInterruptHandler([&](const exception_wrapper& /* e */) { flag = true; });
p.getSemiFuture()
.deferError(
folly::tag_t<std::runtime_error>{},
[](const exception_wrapper& /* e */) { return makeSemiFuture(); })
.cancel();
EXPECT_TRUE(flag);
}
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