Fix SignalHandlerTest with ASAN
[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 <folly/system/ThreadName.h>
19 #include <glog/logging.h>
20 #include <iostream>
21
22 namespace folly {
23
24 ThreadedRepeatingFunctionRunner::ThreadedRepeatingFunctionRunner() {}
25
26 ThreadedRepeatingFunctionRunner::~ThreadedRepeatingFunctionRunner() {
27   if (stopImpl()) {
28     LOG(ERROR)
29         << "ThreadedRepeatingFunctionRunner::stop() should already have been "
30         << "called, since we are now in the Runner's destructor. This is "
31         << "because it means that its threads may be accessing object state "
32         << "that was already destroyed -- e.g. members that were declared "
33         << "after the ThreadedRepeatingFunctionRunner.";
34   }
35 }
36
37 void ThreadedRepeatingFunctionRunner::stop() {
38   stopImpl();
39 }
40
41 bool ThreadedRepeatingFunctionRunner::stopImpl() {
42   {
43     std::unique_lock<std::mutex> lock(stopMutex_);
44     if (stopping_) {
45       return false; // Do nothing if stop() is called twice.
46     }
47     stopping_ = true;
48   }
49   stopCv_.notify_all();
50   for (auto& t : threads_) {
51     t.join();
52   }
53   return true;
54 }
55
56 void ThreadedRepeatingFunctionRunner::add(
57     std::string name,
58     RepeatingFn fn,
59     std::chrono::milliseconds initialSleep) {
60   threads_.emplace_back([
61     name = std::move(name),
62     fn = std::move(fn),
63     initialSleep,
64     this
65   ]() mutable {
66     setThreadName(name);
67     executeInLoop(std::move(fn), initialSleep);
68   });
69 }
70
71 bool ThreadedRepeatingFunctionRunner::waitFor(
72     std::chrono::milliseconds duration) noexcept {
73   using clock = std::chrono::steady_clock;
74   const auto deadline = clock::now() + duration;
75   std::unique_lock<std::mutex> lock(stopMutex_);
76   stopCv_.wait_until(
77       lock, deadline, [&] { return stopping_ || clock::now() > deadline; });
78   return !stopping_;
79 }
80
81 void ThreadedRepeatingFunctionRunner::executeInLoop(
82     RepeatingFn fn,
83     std::chrono::milliseconds initialSleep) noexcept {
84   auto duration = initialSleep;
85   while (waitFor(duration)) {
86     duration = fn();
87   }
88 }
89
90 } // namespace folly