Simplify ThreadedRepeatingFunctionRunner by requiring classes that contain it to...
[folly.git] / folly / experimental / ThreadedRepeatingFunctionRunner.cpp
1 /*
2  * Copyright 2015-present Facebook, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *   http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 #include "folly/experimental/ThreadedRepeatingFunctionRunner.h"
17
18 #include <glog/logging.h>
19 #include <iostream>
20
21 namespace folly {
22
23 ThreadedRepeatingFunctionRunner::ThreadedRepeatingFunctionRunner() {}
24
25 ThreadedRepeatingFunctionRunner::~ThreadedRepeatingFunctionRunner() {
26   if (stopImpl()) {
27     LOG(ERROR)
28         << "ThreadedRepeatingFunctionRunner::stop() should already have been "
29         << "called, since we are now in the Runner's destructor. This is "
30         << "because it means that its threads may be accessing object state "
31         << "that was already destroyed -- e.g. members that were declared "
32         << "after the ThreadedRepeatingFunctionRunner.";
33   }
34 }
35
36 void ThreadedRepeatingFunctionRunner::stop() {
37   stopImpl();
38 }
39
40 bool ThreadedRepeatingFunctionRunner::stopImpl() {
41   {
42     std::unique_lock<std::mutex> lock(stopMutex_);
43     if (stopping_) {
44       return false; // Do nothing if stop() is called twice.
45     }
46     stopping_ = true;
47   }
48   stopCv_.notify_all();
49   for (auto& t : threads_) {
50     t.join();
51   }
52   return true;
53 }
54
55 void ThreadedRepeatingFunctionRunner::add(
56     RepeatingFn fn,
57     std::chrono::milliseconds initialSleep) {
58   threads_.emplace_back(
59       &ThreadedRepeatingFunctionRunner::executeInLoop,
60       this,
61       std::move(fn),
62       initialSleep);
63 }
64
65 bool ThreadedRepeatingFunctionRunner::waitFor(
66     std::chrono::milliseconds duration) noexcept {
67   using clock = std::chrono::steady_clock;
68   const auto deadline = clock::now() + duration;
69   std::unique_lock<std::mutex> lock(stopMutex_);
70   stopCv_.wait_until(
71       lock, deadline, [&] { return stopping_ || clock::now() > deadline; });
72   return !stopping_;
73 }
74
75 void ThreadedRepeatingFunctionRunner::executeInLoop(
76     RepeatingFn fn,
77     std::chrono::milliseconds initialSleep) noexcept {
78   auto duration = initialSleep;
79   while (waitFor(duration)) {
80     duration = fn();
81   }
82 }
83
84 } // namespace folly