Commit 0dd7a9a6 authored by Igor Zinkovsky's avatar Igor Zinkovsky Committed by Facebook Github Bot

allow run-once callbacks

Summary: Adding new `addFunctionOnce` method that executes provided callback only once.

Reviewed By: yfeldblum

Differential Revision: D4315635

fbshipit-source-id: 4819ec30b4f2e4ab3185a37158404e1c7a96758a
parent 344088dc
...@@ -96,12 +96,13 @@ void FunctionScheduler::addFunction(Function<void()>&& cb, ...@@ -96,12 +96,13 @@ void FunctionScheduler::addFunction(Function<void()>&& cb,
milliseconds interval, milliseconds interval,
StringPiece nameID, StringPiece nameID,
milliseconds startDelay) { milliseconds startDelay) {
addFunctionGenericDistribution( addFunctionInternal(
std::move(cb), std::move(cb),
ConstIntervalFunctor(interval), ConstIntervalFunctor(interval),
nameID.str(), nameID.str(),
to<std::string>(interval.count(), "ms"), to<std::string>(interval.count(), "ms"),
startDelay); startDelay,
false /*runOnce*/);
} }
void FunctionScheduler::addFunction(Function<void()>&& cb, void FunctionScheduler::addFunction(Function<void()>&& cb,
...@@ -110,30 +111,45 @@ void FunctionScheduler::addFunction(Function<void()>&& cb, ...@@ -110,30 +111,45 @@ void FunctionScheduler::addFunction(Function<void()>&& cb,
StringPiece nameID, StringPiece nameID,
milliseconds startDelay) { milliseconds startDelay) {
if (latencyDistr.isPoisson) { if (latencyDistr.isPoisson) {
addFunctionGenericDistribution( addFunctionInternal(
std::move(cb), std::move(cb),
PoissonDistributionFunctor(latencyDistr.poissonMean), PoissonDistributionFunctor(latencyDistr.poissonMean),
nameID.str(), nameID.str(),
to<std::string>(latencyDistr.poissonMean, "ms (Poisson mean)"), to<std::string>(latencyDistr.poissonMean, "ms (Poisson mean)"),
startDelay); startDelay,
false /*runOnce*/);
} else { } else {
addFunction(std::move(cb), interval, nameID, startDelay); addFunction(std::move(cb), interval, nameID, startDelay);
} }
} }
void FunctionScheduler::addFunctionOnce(
Function<void()>&& cb,
StringPiece nameID,
milliseconds startDelay) {
addFunctionInternal(
std::move(cb),
ConstIntervalFunctor(milliseconds::zero()),
nameID.str(),
"once",
startDelay,
true /*runOnce*/);
}
void FunctionScheduler::addFunctionUniformDistribution( void FunctionScheduler::addFunctionUniformDistribution(
Function<void()>&& cb, Function<void()>&& cb,
milliseconds minInterval, milliseconds minInterval,
milliseconds maxInterval, milliseconds maxInterval,
StringPiece nameID, StringPiece nameID,
milliseconds startDelay) { milliseconds startDelay) {
addFunctionGenericDistribution( addFunctionInternal(
std::move(cb), std::move(cb),
UniformDistributionFunctor(minInterval, maxInterval), UniformDistributionFunctor(minInterval, maxInterval),
nameID.str(), nameID.str(),
to<std::string>( to<std::string>(
"[", minInterval.count(), " , ", maxInterval.count(), "] ms"), "[", minInterval.count(), " , ", maxInterval.count(), "] ms"),
startDelay); startDelay,
false /*runOnce*/);
} }
void FunctionScheduler::addFunctionGenericDistribution( void FunctionScheduler::addFunctionGenericDistribution(
...@@ -142,6 +158,22 @@ void FunctionScheduler::addFunctionGenericDistribution( ...@@ -142,6 +158,22 @@ void FunctionScheduler::addFunctionGenericDistribution(
const std::string& nameID, const std::string& nameID,
const std::string& intervalDescr, const std::string& intervalDescr,
milliseconds startDelay) { milliseconds startDelay) {
addFunctionInternal(
std::move(cb),
std::move(intervalFunc),
nameID,
intervalDescr,
startDelay,
false /*runOnce*/);
}
void FunctionScheduler::addFunctionInternal(
Function<void()>&& cb,
IntervalDistributionFunc&& intervalFunc,
const std::string& nameID,
const std::string& intervalDescr,
milliseconds startDelay,
bool runOnce) {
if (!cb) { if (!cb) {
throw std::invalid_argument( throw std::invalid_argument(
"FunctionScheduler: Scheduled function must be set"); "FunctionScheduler: Scheduled function must be set");
...@@ -177,7 +209,8 @@ void FunctionScheduler::addFunctionGenericDistribution( ...@@ -177,7 +209,8 @@ void FunctionScheduler::addFunctionGenericDistribution(
std::move(intervalFunc), std::move(intervalFunc),
nameID, nameID,
intervalDescr, intervalDescr,
startDelay)); startDelay,
runOnce));
} }
bool FunctionScheduler::cancelFunction(StringPiece nameID) { bool FunctionScheduler::cancelFunction(StringPiece nameID) {
...@@ -382,6 +415,10 @@ void FunctionScheduler::runOneFunction(std::unique_lock<std::mutex>& lock, ...@@ -382,6 +415,10 @@ void FunctionScheduler::runOneFunction(std::unique_lock<std::mutex>& lock,
// We shouldn't reschedule it; // We shouldn't reschedule it;
return; return;
} }
if (currentFunction_->runOnce) {
// Don't reschedule if the function only needed to run once.
return;
}
// Clear currentFunction_ // Clear currentFunction_
CHECK_EQ(currentFunction_, &func); CHECK_EQ(currentFunction_, &func);
currentFunction_ = nullptr; currentFunction_ = nullptr;
......
...@@ -110,6 +110,14 @@ class FunctionScheduler { ...@@ -110,6 +110,14 @@ class FunctionScheduler {
StringPiece nameID = StringPiece(), StringPiece nameID = StringPiece(),
std::chrono::milliseconds startDelay = std::chrono::milliseconds(0)); std::chrono::milliseconds startDelay = std::chrono::milliseconds(0));
/**
* Adds a new function to the FunctionScheduler to run only once.
*/
void addFunctionOnce(
Function<void()>&& cb,
StringPiece nameID = StringPiece(),
std::chrono::milliseconds startDelay = std::chrono::milliseconds(0));
/** /**
* Add a new function to the FunctionScheduler with the time * Add a new function to the FunctionScheduler with the time
* interval being distributed uniformly within the given interval * interval being distributed uniformly within the given interval
...@@ -194,18 +202,22 @@ class FunctionScheduler { ...@@ -194,18 +202,22 @@ class FunctionScheduler {
std::string name; std::string name;
std::chrono::milliseconds startDelay; std::chrono::milliseconds startDelay;
std::string intervalDescr; std::string intervalDescr;
bool runOnce;
RepeatFunc(Function<void()>&& cback, RepeatFunc(
IntervalDistributionFunc&& intervalFn, Function<void()>&& cback,
const std::string& nameID, IntervalDistributionFunc&& intervalFn,
const std::string& intervalDistDescription, const std::string& nameID,
std::chrono::milliseconds delay) const std::string& intervalDistDescription,
std::chrono::milliseconds delay,
bool once)
: cb(std::move(cback)), : cb(std::move(cback)),
intervalFunc(std::move(intervalFn)), intervalFunc(std::move(intervalFn)),
nextRunTime(), nextRunTime(),
name(nameID), name(nameID),
startDelay(delay), startDelay(delay),
intervalDescr(intervalDistDescription) {} intervalDescr(intervalDistDescription),
runOnce(once) {}
std::chrono::steady_clock::time_point getNextRunTime() const { std::chrono::steady_clock::time_point getNextRunTime() const {
return nextRunTime; return nextRunTime;
...@@ -240,6 +252,14 @@ class FunctionScheduler { ...@@ -240,6 +252,14 @@ class FunctionScheduler {
void addFunctionToHeap(const std::unique_lock<std::mutex>& lock, void addFunctionToHeap(const std::unique_lock<std::mutex>& lock,
RepeatFunc&& func); RepeatFunc&& func);
void addFunctionInternal(
Function<void()>&& cb,
IntervalDistributionFunc&& intervalFunc,
const std::string& nameID,
const std::string& intervalDescr,
std::chrono::milliseconds startDelay,
bool runOnce);
std::thread thread_; std::thread thread_;
// Mutex to protect our member variables. // Mutex to protect our member variables.
......
...@@ -446,3 +446,15 @@ TEST(FunctionScheduler, GammaIntervalDistribution) { ...@@ -446,3 +446,15 @@ TEST(FunctionScheduler, GammaIntervalDistribution) {
delay(2); delay(2);
EXPECT_EQ(6, total); EXPECT_EQ(6, total);
} }
TEST(FunctionScheduler, AddWithRunOnce) {
int total = 0;
FunctionScheduler fs;
fs.addFunctionOnce([&] { total += 2; }, "add2");
fs.start();
delay(1);
EXPECT_EQ(2, total);
delay(2);
EXPECT_EQ(2, total);
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