Simplify BackgroundThreads, move them to folly/experimental/ThreadedRepeatingFunction...
[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   stopAndWarn("ThreadedRepeatingFunctionRunner");
27 }
28
29 void ThreadedRepeatingFunctionRunner::stopAndWarn(
30     const std::string& class_of_destructor) {
31   if (stopImpl()) {
32     LOG(ERROR)
33         << "ThreadedRepeatingFunctionRunner::stop() should already have been "
34         << "called, since the " << class_of_destructor << " destructor is now "
35         << "running. This is unsafe because it means that its threads "
36         << "may be accessing class state that was already destroyed "
37         << "(e.g. derived class members, or members that were declared after "
38         << "the " << class_of_destructor << ") .";
39     stop();
40   }
41 }
42
43 void ThreadedRepeatingFunctionRunner::stop() {
44   stopImpl();
45 }
46
47 bool ThreadedRepeatingFunctionRunner::stopImpl() {
48   {
49     std::unique_lock<std::mutex> lock(stopMutex_);
50     if (stopping_) {
51       return false; // Do nothing if stop() is called twice.
52     }
53     stopping_ = true;
54   }
55   stopCv_.notify_all();
56   for (auto& t : threads_) {
57     t.join();
58   }
59   return true;
60 }
61
62 void ThreadedRepeatingFunctionRunner::add(
63     RepeatingFn fn,
64     std::chrono::milliseconds initialSleep) {
65   threads_.emplace_back(
66       &ThreadedRepeatingFunctionRunner::executeInLoop,
67       this,
68       std::move(fn),
69       initialSleep);
70 }
71
72 bool ThreadedRepeatingFunctionRunner::waitFor(
73     std::chrono::milliseconds duration) noexcept {
74   using clock = std::chrono::steady_clock;
75   const auto deadline = clock::now() + duration;
76   std::unique_lock<std::mutex> lock(stopMutex_);
77   stopCv_.wait_until(
78       lock, deadline, [&] { return stopping_ || clock::now() > deadline; });
79   return !stopping_;
80 }
81
82 void ThreadedRepeatingFunctionRunner::executeInLoop(
83     RepeatingFn fn,
84     std::chrono::milliseconds initialSleep) noexcept {
85   auto duration = initialSleep;
86   while (waitFor(duration)) {
87     duration = fn();
88   }
89 }
90
91 } // namespace folly