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 | |
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([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 | |
69 | bool 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 | |
79 | void 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 | |