1/*
2 * Copyright 2014-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
22namespace folly {
23
24ThreadedRepeatingFunctionRunner::ThreadedRepeatingFunctionRunner() {}
25
26ThreadedRepeatingFunctionRunner::~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
37void ThreadedRepeatingFunctionRunner::stop() {
38 stopImpl();
39}
40
41bool 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
56void ThreadedRepeatingFunctionRunner::add(
57 std::string name,
58 RepeatingFn fn,
59 std::chrono::milliseconds initialSleep) {
60 threads_.emplace_back([name = std::move(name),
61 fn = std::move(fn),
62 initialSleep,
63 this]() mutable {
64 setThreadName(name);
65 executeInLoop(std::move(fn), initialSleep);
66 });
67}
68
69bool ThreadedRepeatingFunctionRunner::waitFor(
70 std::chrono::milliseconds duration) noexcept {
71 using clock = std::chrono::steady_clock;
72 const auto deadline = clock::now() + duration;
73 std::unique_lock<std::mutex> lock(stopMutex_);
74 stopCv_.wait_until(
75 lock, deadline, [&] { return stopping_ || clock::now() > deadline; });
76 return !stopping_;
77}
78
79void ThreadedRepeatingFunctionRunner::executeInLoop(
80 RepeatingFn fn,
81 std::chrono::milliseconds initialSleep) noexcept {
82 auto duration = initialSleep;
83 while (waitFor(duration)) {
84 duration = fn();
85 }
86}
87
88} // namespace folly
89