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