Commit 2a7bf484 authored by Junlin Zhang's avatar Junlin Zhang Committed by Facebook Github Bot

add cancelFunctionAndWait and cancelAllFunctionsAndWait to FunctionScheduler

Summary: In FunctionScheduler, cancelFunction and cancelAllFunction will not wait for current running function, which will lead to segmentation fault if the function captures resource to be destructed right after calling cancelFunction or cancelAllFunction. This diff introduces cancelFunctionAndWait and cancelAllFunctionsAndWait, making it possible to wait for completion of current running function.

Reviewed By: yfeldblum

Differential Revision: D4324384

fbshipit-source-id: ac4b272894f753ef3bb175173f10d1ca20c17c41
parent 2b06a716
...@@ -232,6 +232,25 @@ bool FunctionScheduler::cancelFunction(StringPiece nameID) { ...@@ -232,6 +232,25 @@ bool FunctionScheduler::cancelFunction(StringPiece nameID) {
return false; return false;
} }
bool FunctionScheduler::cancelFunctionAndWait(StringPiece nameID) {
std::unique_lock<std::mutex> l(mutex_);
auto* currentFunction = currentFunction_;
if (currentFunction && currentFunction->name == nameID) {
runningCondvar_.wait(l, [currentFunction, this]() {
return currentFunction != currentFunction_;
});
}
for (auto it = functions_.begin(); it != functions_.end(); ++it) {
if (it->isValid() && it->name == nameID) {
cancelFunction(l, it);
return true;
}
}
return false;
}
void FunctionScheduler::cancelFunction(const std::unique_lock<std::mutex>& l, void FunctionScheduler::cancelFunction(const std::unique_lock<std::mutex>& l,
FunctionHeap::iterator it) { FunctionHeap::iterator it) {
// This function should only be called with mutex_ already locked. // This function should only be called with mutex_ already locked.
...@@ -259,6 +278,14 @@ void FunctionScheduler::cancelAllFunctions() { ...@@ -259,6 +278,14 @@ void FunctionScheduler::cancelAllFunctions() {
currentFunction_ = nullptr; currentFunction_ = nullptr;
} }
void FunctionScheduler::cancelAllFunctionsAndWait() {
std::unique_lock<std::mutex> l(mutex_);
if (currentFunction_) {
runningCondvar_.wait(l, [this]() { return currentFunction_ == nullptr; });
}
functions_.clear();
}
bool FunctionScheduler::resetFunctionTimer(StringPiece nameID) { bool FunctionScheduler::resetFunctionTimer(StringPiece nameID) {
std::unique_lock<std::mutex> l(mutex_); std::unique_lock<std::mutex> l(mutex_);
if (currentFunction_ && currentFunction_->name == nameID) { if (currentFunction_ && currentFunction_->name == nameID) {
...@@ -355,6 +382,7 @@ void FunctionScheduler::run() { ...@@ -355,6 +382,7 @@ void FunctionScheduler::run() {
if (sleepTime < milliseconds::zero()) { if (sleepTime < milliseconds::zero()) {
// We need to run this function now // We need to run this function now
runOneFunction(lock, now); runOneFunction(lock, now);
runningCondvar_.notify_all();
} else { } else {
// Re-add the function to the heap, and wait until we actually // Re-add the function to the heap, and wait until we actually
// need to run it. // need to run it.
......
...@@ -157,11 +157,13 @@ class FunctionScheduler { ...@@ -157,11 +157,13 @@ class FunctionScheduler {
* Returns false if no function exists with the specified name. * Returns false if no function exists with the specified name.
*/ */
bool cancelFunction(StringPiece nameID); bool cancelFunction(StringPiece nameID);
bool cancelFunctionAndWait(StringPiece nameID);
/** /**
* All functions registered will be canceled. * All functions registered will be canceled.
*/ */
void cancelAllFunctions(); void cancelAllFunctions();
void cancelAllFunctionsAndWait();
/** /**
* Resets the specified function's timer. * Resets the specified function's timer.
......
...@@ -458,3 +458,48 @@ TEST(FunctionScheduler, AddWithRunOnce) { ...@@ -458,3 +458,48 @@ TEST(FunctionScheduler, AddWithRunOnce) {
EXPECT_EQ(2, total); EXPECT_EQ(2, total);
fs.shutdown(); fs.shutdown();
} }
TEST(FunctionScheduler, cancelFunctionAndWait) {
int total = 0;
FunctionScheduler fs;
fs.addFunction(
[&] {
delay(5);
total += 2;
},
testInterval(100),
"add2");
fs.start();
delay(1);
EXPECT_EQ(0, total); // add2 is still sleeping
EXPECT_TRUE(fs.cancelFunctionAndWait("add2"));
EXPECT_EQ(2, total); // add2 should have completed
EXPECT_FALSE(fs.cancelFunction("add2")); // add2 has been canceled
fs.shutdown();
}
TEST(FunctionScheduler, cancelAllFunctionsAndWait) {
int total = 0;
FunctionScheduler fs;
fs.addFunction(
[&] {
delay(5);
total += 2;
},
testInterval(100),
"add2");
fs.start();
delay(1);
EXPECT_EQ(0, total); // add2 is still sleeping
fs.cancelAllFunctionsAndWait();
EXPECT_EQ(2, total);
EXPECT_FALSE(fs.cancelFunction("add2")); // add2 has been canceled
fs.shutdown();
}
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