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 "once_timer.h"
18
19 #include "message_loop_thread.h"
20 #include "time_util.h"
21
22 namespace bluetooth {
23
24 namespace common {
25
26 // This runs on user thread
~OnceTimer()27 OnceTimer::~OnceTimer() {
28 std::lock_guard<std::recursive_mutex> api_lock(api_mutex_);
29 if (message_loop_thread_ != nullptr && message_loop_thread_->IsRunning()) {
30 CancelAndWait();
31 }
32 }
33
34 // This runs on user thread
Schedule(const base::WeakPtr<MessageLoopThread> & thread,const base::Location & from_here,base::OnceClosure task,base::TimeDelta delay)35 bool OnceTimer::Schedule(const base::WeakPtr<MessageLoopThread>& thread,
36 const base::Location& from_here,
37 base::OnceClosure task, base::TimeDelta delay) {
38 uint64_t time_now_us = time_get_os_boottime_us();
39 uint64_t time_next_task_us = time_now_us + delay.InMicroseconds();
40 std::lock_guard<std::recursive_mutex> api_lock(api_mutex_);
41 if (thread == nullptr) {
42 LOG(ERROR) << __func__ << ": thread must be non-null";
43 return false;
44 }
45 CancelAndWait();
46 task_ = std::move(task);
47 task_wrapper_.Reset(
48 base::BindOnce(&OnceTimer::RunTask, base::Unretained(this)));
49 message_loop_thread_ = thread;
50 delay_ = delay;
51 uint64_t time_until_next_us = time_next_task_us - time_get_os_boottime_us();
52 if (!thread->DoInThreadDelayed(
53 from_here, task_wrapper_.callback(),
54 base::TimeDelta::FromMicroseconds(time_until_next_us))) {
55 LOG(ERROR) << __func__
56 << ": failed to post task to message loop for thread " << *thread
57 << ", from " << from_here.ToString();
58 task_wrapper_.Cancel();
59 message_loop_thread_ = nullptr;
60 delay_ = {};
61 return false;
62 }
63 return true;
64 }
65
66 // This runs on user thread
Cancel()67 void OnceTimer::Cancel() {
68 std::promise<void> promise;
69 CancelHelper(std::move(promise));
70 }
71
72 // This runs on user thread
CancelAndWait()73 void OnceTimer::CancelAndWait() {
74 std::promise<void> promise;
75 auto future = promise.get_future();
76 CancelHelper(std::move(promise));
77 future.wait();
78 }
79
80 // This runs on user thread
CancelHelper(std::promise<void> promise)81 void OnceTimer::CancelHelper(std::promise<void> promise) {
82 std::lock_guard<std::recursive_mutex> api_lock(api_mutex_);
83 MessageLoopThread* scheduled_thread = message_loop_thread_.get();
84 if (scheduled_thread == nullptr) {
85 promise.set_value();
86 return;
87 }
88 if (scheduled_thread->GetThreadId() == base::PlatformThread::CurrentId()) {
89 CancelClosure(std::move(promise));
90 return;
91 }
92 scheduled_thread->DoInThread(
93 FROM_HERE, base::BindOnce(&OnceTimer::CancelClosure,
94 base::Unretained(this), std::move(promise)));
95 }
96
97 // This runs on message loop thread
CancelClosure(std::promise<void> promise)98 void OnceTimer::CancelClosure(std::promise<void> promise) {
99 message_loop_thread_ = nullptr;
100 task_wrapper_.Cancel();
101 std::move(task_);
102 delay_ = base::TimeDelta();
103 promise.set_value();
104 }
105
106 // This runs on user thread
IsScheduled() const107 bool OnceTimer::IsScheduled() const {
108 std::lock_guard<std::recursive_mutex> api_lock(api_mutex_);
109 return message_loop_thread_ != nullptr && message_loop_thread_->IsRunning();
110 }
111
112 // This runs on message loop thread
RunTask()113 void OnceTimer::RunTask() {
114 if (message_loop_thread_ == nullptr || !message_loop_thread_->IsRunning()) {
115 LOG(ERROR) << __func__
116 << ": message_loop_thread_ is null or is not running";
117 return;
118 }
119 CHECK_EQ(message_loop_thread_->GetThreadId(),
120 base::PlatformThread::CurrentId())
121 << ": task must run on message loop thread";
122
123 task_wrapper_.Cancel();
124 std::move(task_).Run();
125 message_loop_thread_ = nullptr;
126 }
127
128 } // namespace common
129
130 } // namespace bluetooth
131