1 /*
2  * Copyright 2018 The Android Open Source Project
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 
17 #include "repeating_timer.h"
18 
19 #include <base/functional/callback.h>
20 #include <bluetooth/log.h>
21 
22 #include "message_loop_thread.h"
23 
24 namespace bluetooth {
25 
26 namespace common {
27 
28 constexpr std::chrono::microseconds kMinimumPeriod =
29     std::chrono::microseconds(1);
30 
31 // This runs on user thread
~RepeatingTimer()32 RepeatingTimer::~RepeatingTimer() {
33   std::lock_guard<std::recursive_mutex> api_lock(api_mutex_);
34   if (message_loop_thread_ != nullptr && message_loop_thread_->IsRunning()) {
35     CancelAndWait();
36   }
37 }
38 
39 // This runs on user thread
SchedulePeriodic(const base::WeakPtr<MessageLoopThread> & thread,const base::Location & from_here,base::RepeatingClosure task,std::chrono::microseconds period)40 bool RepeatingTimer::SchedulePeriodic(
41     const base::WeakPtr<MessageLoopThread>& thread,
42     const base::Location& from_here, base::RepeatingClosure task,
43     std::chrono::microseconds period) {
44   if (period < kMinimumPeriod) {
45     log::error("period must be at least {}", kMinimumPeriod.count());
46     return false;
47   }
48 
49   uint64_t time_now_us = clock_tick_us_();
50   uint64_t time_next_task_us = time_now_us + period.count();
51   std::lock_guard<std::recursive_mutex> api_lock(api_mutex_);
52   if (thread == nullptr) {
53     log::error("thread must be non-null");
54     return false;
55   }
56   CancelAndWait();
57   expected_time_next_task_us_ = time_next_task_us;
58   task_ = std::move(task);
59   task_wrapper_.Reset(
60       base::Bind(&RepeatingTimer::RunTask, base::Unretained(this)));
61   message_loop_thread_ = thread;
62   period_ = period;
63   uint64_t time_until_next_us = time_next_task_us - clock_tick_us_();
64   if (!thread->DoInThreadDelayed(
65           from_here, task_wrapper_.callback(),
66           std::chrono::microseconds(time_until_next_us))) {
67     log::error("failed to post task to message loop for thread {}, from {}",
68                *thread, from_here.ToString());
69     expected_time_next_task_us_ = 0;
70     task_wrapper_.Cancel();
71     message_loop_thread_ = nullptr;
72     period_ = {};
73     return false;
74   }
75   return true;
76 }
77 
78 // This runs on user thread
Cancel()79 void RepeatingTimer::Cancel() {
80   std::promise<void> promise;
81   CancelHelper(std::move(promise));
82 }
83 
84 // This runs on user thread
CancelAndWait()85 void RepeatingTimer::CancelAndWait() {
86   std::promise<void> promise;
87   auto future = promise.get_future();
88   CancelHelper(std::move(promise));
89   future.wait();
90 }
91 
92 // This runs on user thread
CancelHelper(std::promise<void> promise)93 void RepeatingTimer::CancelHelper(std::promise<void> promise) {
94   std::lock_guard<std::recursive_mutex> api_lock(api_mutex_);
95   MessageLoopThread* scheduled_thread = message_loop_thread_.get();
96   if (scheduled_thread == nullptr) {
97     promise.set_value();
98     return;
99   }
100   if (scheduled_thread->GetThreadId() == base::PlatformThread::CurrentId()) {
101     CancelClosure(std::move(promise));
102     return;
103   }
104   scheduled_thread->DoInThread(
105       FROM_HERE, base::BindOnce(&RepeatingTimer::CancelClosure,
106                                 base::Unretained(this), std::move(promise)));
107 }
108 
109 // This runs on message loop thread
CancelClosure(std::promise<void> promise)110 void RepeatingTimer::CancelClosure(std::promise<void> promise) {
111   message_loop_thread_ = nullptr;
112   task_wrapper_.Cancel();
113 #if BASE_VER < 927031
114   task_ = {};
115 #else
116   task_ = base::NullCallback();
117 #endif
118   period_ = std::chrono::microseconds(0);
119   expected_time_next_task_us_ = 0;
120   promise.set_value();
121 }
122 
123 // This runs on user thread
IsScheduled() const124 bool RepeatingTimer::IsScheduled() const {
125   std::lock_guard<std::recursive_mutex> api_lock(api_mutex_);
126   return message_loop_thread_ != nullptr && message_loop_thread_->IsRunning();
127 }
128 
129 // This runs on message loop thread
RunTask()130 void RepeatingTimer::RunTask() {
131   if (message_loop_thread_ == nullptr || !message_loop_thread_->IsRunning()) {
132     log::error("message_loop_thread_ is null or is not running");
133     return;
134   }
135   log::assert_that(
136       message_loop_thread_->GetThreadId() == base::PlatformThread::CurrentId(),
137       "task must run on message loop thread");
138 
139   int64_t period_us = period_.count();
140   expected_time_next_task_us_ += period_us;
141   uint64_t time_now_us = clock_tick_us_();
142   int64_t remaining_time_us = expected_time_next_task_us_ - time_now_us;
143   if (remaining_time_us < 0) {
144     // if remaining_time_us is negative, schedule the task to the nearest
145     // multiple of period
146     remaining_time_us = (remaining_time_us % period_us + period_us) % period_us;
147   }
148   message_loop_thread_->DoInThreadDelayed(
149       FROM_HERE, task_wrapper_.callback(),
150       std::chrono::microseconds(remaining_time_us));
151 
152   uint64_t time_before_task_us = clock_tick_us_();
153   task_.Run();
154   uint64_t time_after_task_us = clock_tick_us_();
155   auto task_time_us =
156       static_cast<int64_t>(time_after_task_us - time_before_task_us);
157   if (task_time_us > period_.count()) {
158     log::error(
159         "Periodic task execution took {} microseconds, longer than interval {} "
160         "microseconds",
161         task_time_us, period_.count());
162   }
163 }
164 
165 }  // namespace common
166 
167 }  // namespace bluetooth
168