blob: 413dc4447b8d6da94db2f2d4a6ac8337914df3b6 [file] [log] [blame]
Jakub Pawlowski5cf03042018-12-03 16:50:40 +01001/*
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
22namespace bluetooth {
23
24namespace common {
25
26// This runs on user thread
27OnceTimer::~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
35bool 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
67void OnceTimer::Cancel() {
68 std::promise<void> promise;
69 CancelHelper(std::move(promise));
70}
71
72// This runs on user thread
73void 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
81void 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
98void 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
107bool 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
113void 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