}
}
+size_t HHWheelTimer::cancelAll() {
+ decltype(buckets_) buckets;
+ std::swap(buckets, buckets_);
+ size_t count = 0;
+
+ for (auto& tick : buckets) {
+ for (auto& bucket : tick) {
+ while (!bucket.empty()) {
+ auto& cb = bucket.front();
+ cb.cancelTimeout();
+ cb.callbackCanceled();
+ count++;
+ }
+ }
+ }
+
+ return count;
+}
+
} // folly
*/
virtual void timeoutExpired() noexcept = 0;
+ /// This callback was canceled. The default implementation is to just
+ /// proxy to `timeoutExpired` but if you care about the difference between
+ /// the timeout finishing or being canceled you can override this.
+ virtual void callbackCanceled() noexcept {
+ timeoutExpired();
+ }
+
/**
* Cancel the timeout, if it is running.
*
* Destroy the HHWheelTimer.
*
* A HHWheelTimer should only be destroyed when there are no more
- * callbacks pending in the set.
+ * callbacks pending in the set. (If it helps you may use cancelAll() to
+ * cancel all pending timeouts explicitly before calling this.)
*/
virtual void destroy();
+ /**
+ * Cancel all outstanding timeouts
+ *
+ * @returns the number of timeouts that were cancelled.
+ */
+ size_t cancelAll();
+
/**
* Get the tick interval for this HHWheelTimer.
*
TestTimeout(HHWheelTimer* t, milliseconds timeout) {
t->scheduleTimeout(this, timeout);
}
- virtual void timeoutExpired() noexcept {
+
+ void timeoutExpired() noexcept override {
timestamps.push_back(TimePoint());
if (fn) {
fn();
}
}
+ void callbackCanceled() noexcept override {
+ canceledTimestamps.push_back(TimePoint());
+ if (fn) {
+ fn();
+ }
+ }
+
std::deque<TimePoint> timestamps;
+ std::deque<TimePoint> canceledTimestamps;
std::function<void()> fn;
};
// at the console to confirm logging)
TEST_F(HHWheelTimerTest, lambdaThrows) {
StackWheelTimer t(&eventBase, milliseconds(1));
- t.scheduleTimeoutFn([&]{ throw std::runtime_error("foo"); },
+ t.scheduleTimeoutFn([&]{ throw std::runtime_error("expected"); },
milliseconds(1));
eventBase.loop();
}
+
+TEST_F(HHWheelTimerTest, cancelAll) {
+ StackWheelTimer t(&eventBase);
+ TestTimeout tt;
+ t.scheduleTimeout(&tt, std::chrono::minutes(1));
+ EXPECT_EQ(1, t.cancelAll());
+ EXPECT_EQ(1, tt.canceledTimestamps.size());
+}