blob: e34dabc45cde81c367a3a32de7be68f72ca9681a [file] [log] [blame]
Hansong Zhang438b08c2018-08-14 14:29:23 -07001/*
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
Jakub Pawlowski5cf03042018-12-03 16:50:40 +010017#include "repeating_timer.h"
18
Hansong Zhang438b08c2018-08-14 14:29:23 -070019#include "message_loop_thread.h"
20#include "time_util.h"
21
22namespace bluetooth {
23
24namespace common {
25
26constexpr base::TimeDelta kMinimumPeriod = base::TimeDelta::FromMicroseconds(1);
27
Hansong Zhang68f91132018-09-20 10:15:12 -070028// This runs on user thread
Jakub Pawlowski5cf03042018-12-03 16:50:40 +010029RepeatingTimer::~RepeatingTimer() {
Hansong Zhang438b08c2018-08-14 14:29:23 -070030 std::lock_guard<std::recursive_mutex> api_lock(api_mutex_);
31 if (message_loop_thread_ != nullptr && message_loop_thread_->IsRunning()) {
32 CancelAndWait();
33 }
34}
35
36// This runs on user thread
Jakub Pawlowski5cf03042018-12-03 16:50:40 +010037bool RepeatingTimer::SchedulePeriodic(
38 const base::WeakPtr<MessageLoopThread>& thread,
39 const base::Location& from_here, base::Closure task,
40 base::TimeDelta period) {
Hansong Zhang438b08c2018-08-14 14:29:23 -070041 if (period < kMinimumPeriod) {
42 LOG(ERROR) << __func__ << ": period must be at least " << kMinimumPeriod;
43 return false;
44 }
Hansong Zhang438b08c2018-08-14 14:29:23 -070045
Hansong Zhang438b08c2018-08-14 14:29:23 -070046 uint64_t time_now_us = time_get_os_boottime_us();
Jakub Pawlowski5cf03042018-12-03 16:50:40 +010047 uint64_t time_next_task_us = time_now_us + period.InMicroseconds();
Hansong Zhang438b08c2018-08-14 14:29:23 -070048 std::lock_guard<std::recursive_mutex> api_lock(api_mutex_);
49 if (thread == nullptr) {
50 LOG(ERROR) << __func__ << ": thread must be non-null";
51 return false;
52 }
53 CancelAndWait();
54 expected_time_next_task_us_ = time_next_task_us;
55 task_ = std::move(task);
Jakub Pawlowski5cf03042018-12-03 16:50:40 +010056 task_wrapper_.Reset(
57 base::Bind(&RepeatingTimer::RunTask, base::Unretained(this)));
Hansong Zhang1773dd82018-09-28 12:10:15 -070058 message_loop_thread_ = thread;
Jakub Pawlowski5cf03042018-12-03 16:50:40 +010059 period_ = period;
Hansong Zhang438b08c2018-08-14 14:29:23 -070060 uint64_t time_until_next_us = time_next_task_us - time_get_os_boottime_us();
61 if (!thread->DoInThreadDelayed(
Hansong Zhang85ea7632018-09-20 10:15:12 -070062 from_here, task_wrapper_.callback(),
Hansong Zhang438b08c2018-08-14 14:29:23 -070063 base::TimeDelta::FromMicroseconds(time_until_next_us))) {
64 LOG(ERROR) << __func__
65 << ": failed to post task to message loop for thread " << *thread
66 << ", from " << from_here.ToString();
67 expected_time_next_task_us_ = 0;
Hansong Zhang85ea7632018-09-20 10:15:12 -070068 task_wrapper_.Cancel();
Hansong Zhang1773dd82018-09-28 12:10:15 -070069 message_loop_thread_ = nullptr;
70 period_ = {};
Hansong Zhang438b08c2018-08-14 14:29:23 -070071 return false;
72 }
Hansong Zhang438b08c2018-08-14 14:29:23 -070073 return true;
74}
75
76// This runs on user thread
Jakub Pawlowski5cf03042018-12-03 16:50:40 +010077void RepeatingTimer::Cancel() {
Hansong Zhang68f91132018-09-20 10:15:12 -070078 std::promise<void> promise;
79 CancelHelper(std::move(promise));
Hansong Zhang438b08c2018-08-14 14:29:23 -070080}
81
82// This runs on user thread
Jakub Pawlowski5cf03042018-12-03 16:50:40 +010083void RepeatingTimer::CancelAndWait() {
Hansong Zhang68f91132018-09-20 10:15:12 -070084 std::promise<void> promise;
85 auto future = promise.get_future();
86 CancelHelper(std::move(promise));
87 future.wait();
Hansong Zhang438b08c2018-08-14 14:29:23 -070088}
89
90// This runs on user thread
Jakub Pawlowski5cf03042018-12-03 16:50:40 +010091void RepeatingTimer::CancelHelper(std::promise<void> promise) {
Hansong Zhang68f91132018-09-20 10:15:12 -070092 std::lock_guard<std::recursive_mutex> api_lock(api_mutex_);
Hansong Zhang85ea7632018-09-20 10:15:12 -070093 MessageLoopThread* scheduled_thread = message_loop_thread_.get();
94 if (scheduled_thread == nullptr) {
Hansong Zhang68f91132018-09-20 10:15:12 -070095 promise.set_value();
Hansong Zhang438b08c2018-08-14 14:29:23 -070096 return;
97 }
Hansong Zhang85ea7632018-09-20 10:15:12 -070098 if (scheduled_thread->GetThreadId() == base::PlatformThread::CurrentId()) {
Hansong Zhang438b08c2018-08-14 14:29:23 -070099 CancelClosure(std::move(promise));
100 return;
101 }
Hansong Zhang85ea7632018-09-20 10:15:12 -0700102 scheduled_thread->DoInThread(
Jakub Pawlowski5cf03042018-12-03 16:50:40 +0100103 FROM_HERE, base::BindOnce(&RepeatingTimer::CancelClosure,
104 base::Unretained(this), std::move(promise)));
Hansong Zhang438b08c2018-08-14 14:29:23 -0700105}
106
107// This runs on message loop thread
Jakub Pawlowski5cf03042018-12-03 16:50:40 +0100108void RepeatingTimer::CancelClosure(std::promise<void> promise) {
Hansong Zhang438b08c2018-08-14 14:29:23 -0700109 message_loop_thread_ = nullptr;
Hansong Zhang85ea7632018-09-20 10:15:12 -0700110 task_wrapper_.Cancel();
111 task_ = {};
Hansong Zhang438b08c2018-08-14 14:29:23 -0700112 period_ = base::TimeDelta();
Hansong Zhang438b08c2018-08-14 14:29:23 -0700113 expected_time_next_task_us_ = 0;
114 promise.set_value();
115}
116
Hansong Zhang68f91132018-09-20 10:15:12 -0700117// This runs on user thread
Jakub Pawlowski5cf03042018-12-03 16:50:40 +0100118bool RepeatingTimer::IsScheduled() const {
Hansong Zhang438b08c2018-08-14 14:29:23 -0700119 std::lock_guard<std::recursive_mutex> api_lock(api_mutex_);
120 return message_loop_thread_ != nullptr && message_loop_thread_->IsRunning();
121}
122
Hansong Zhang68f91132018-09-20 10:15:12 -0700123// This runs on message loop thread
Jakub Pawlowski5cf03042018-12-03 16:50:40 +0100124void RepeatingTimer::RunTask() {
Hansong Zhang438b08c2018-08-14 14:29:23 -0700125 if (message_loop_thread_ == nullptr || !message_loop_thread_->IsRunning()) {
126 LOG(ERROR) << __func__
127 << ": message_loop_thread_ is null or is not running";
128 return;
129 }
Hansong Zhang68f91132018-09-20 10:15:12 -0700130 CHECK_EQ(message_loop_thread_->GetThreadId(),
131 base::PlatformThread::CurrentId())
132 << ": task must run on message loop thread";
Hansong Zhang68f91132018-09-20 10:15:12 -0700133
Hansong Zhang68f91132018-09-20 10:15:12 -0700134 int64_t period_us = period_.InMicroseconds();
135 expected_time_next_task_us_ += period_us;
136 uint64_t time_now_us = time_get_os_boottime_us();
137 int64_t remaining_time_us = expected_time_next_task_us_ - time_now_us;
138 if (remaining_time_us < 0) {
139 // if remaining_time_us is negative, schedule the task to the nearest
140 // multiple of period
141 remaining_time_us = (remaining_time_us % period_us + period_us) % period_us;
142 }
143 message_loop_thread_->DoInThreadDelayed(
Hansong Zhang85ea7632018-09-20 10:15:12 -0700144 FROM_HERE, task_wrapper_.callback(),
Hansong Zhang68f91132018-09-20 10:15:12 -0700145 base::TimeDelta::FromMicroseconds(remaining_time_us));
146
Hansong Zhang438b08c2018-08-14 14:29:23 -0700147 uint64_t time_before_task_us = time_get_os_boottime_us();
148 task_.Run();
149 uint64_t time_after_task_us = time_get_os_boottime_us();
Hansong Zhang68f91132018-09-20 10:15:12 -0700150 auto task_time_us =
Hansong Zhang438b08c2018-08-14 14:29:23 -0700151 static_cast<int64_t>(time_after_task_us - time_before_task_us);
Hansong Zhang68f91132018-09-20 10:15:12 -0700152 if (task_time_us > period_.InMicroseconds()) {
Hansong Zhang438b08c2018-08-14 14:29:23 -0700153 LOG(ERROR) << __func__ << ": Periodic task execution took " << task_time_us
154 << " microseconds, longer than interval "
155 << period_.InMicroseconds() << " microseconds";
156 }
Hansong Zhang68f91132018-09-20 10:15:12 -0700157}
158
Hansong Zhang438b08c2018-08-14 14:29:23 -0700159} // namespace common
160
161} // namespace bluetooth