• 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 "message_loop_thread.h"
18 
19 #include <base/logging.h>
20 #include <base/strings/stringprintf.h>
21 #include <sys/syscall.h>
22 #include <unistd.h>
23 
24 #include <thread>
25 
26 #include "gd/common/init_flags.h"
27 #include "osi/include/log.h"
28 
29 namespace bluetooth {
30 
31 namespace common {
32 
33 static constexpr int kRealTimeFifoSchedulingPriority = 1;
34 
MessageLoopThread(const std::string & thread_name)35 MessageLoopThread::MessageLoopThread(const std::string& thread_name)
36     : MessageLoopThread(thread_name, false) {}
37 
MessageLoopThread(const std::string & thread_name,bool is_main)38 MessageLoopThread::MessageLoopThread(const std::string& thread_name,
39                                      bool is_main)
40     : thread_name_(thread_name),
41       message_loop_(nullptr),
42       run_loop_(nullptr),
43       thread_(nullptr),
44       thread_id_(-1),
45       linux_tid_(-1),
46       weak_ptr_factory_(this),
47       shutting_down_(false),
48       is_main_(is_main) {}
49 
~MessageLoopThread()50 MessageLoopThread::~MessageLoopThread() { ShutDown(); }
51 
StartUp()52 void MessageLoopThread::StartUp() {
53   std::promise<void> start_up_promise;
54   std::future<void> start_up_future = start_up_promise.get_future();
55   {
56     std::lock_guard<std::recursive_mutex> api_lock(api_mutex_);
57     if (thread_ != nullptr) {
58       LOG(WARNING) << __func__ << ": thread " << *this << " is already started";
59 
60       return;
61     }
62     thread_ = new std::thread(&MessageLoopThread::RunThread, this,
63                               std::move(start_up_promise));
64   }
65   start_up_future.wait();
66 }
67 
DoInThread(const base::Location & from_here,base::OnceClosure task)68 bool MessageLoopThread::DoInThread(const base::Location& from_here,
69                                    base::OnceClosure task) {
70   return DoInThreadDelayed(from_here, std::move(task), base::TimeDelta());
71 }
72 
DoInThreadDelayed(const base::Location & from_here,base::OnceClosure task,const base::TimeDelta & delay)73 bool MessageLoopThread::DoInThreadDelayed(const base::Location& from_here,
74                                           base::OnceClosure task,
75                                           const base::TimeDelta& delay) {
76   std::lock_guard<std::recursive_mutex> api_lock(api_mutex_);
77 
78   if (message_loop_ == nullptr) {
79     LOG(ERROR) << __func__ << ": message loop is null for thread " << *this
80                << ", from " << from_here.ToString();
81     return false;
82   }
83   if (!message_loop_->task_runner()->PostDelayedTask(from_here, std::move(task),
84                                                      delay)) {
85     LOG(ERROR) << __func__
86                << ": failed to post task to message loop for thread " << *this
87                << ", from " << from_here.ToString();
88     return false;
89   }
90   return true;
91 }
92 
ShutDown()93 void MessageLoopThread::ShutDown() {
94   {
95     std::lock_guard<std::recursive_mutex> api_lock(api_mutex_);
96     if (thread_ == nullptr) {
97       LOG(INFO) << __func__ << ": thread " << *this << " is already stopped";
98       return;
99     }
100     if (message_loop_ == nullptr) {
101       LOG(INFO) << __func__ << ": message_loop_ is null. Already stopping";
102       return;
103     }
104     if (shutting_down_) {
105       LOG(INFO) << __func__ << ": waiting for thread to join";
106       return;
107     }
108     shutting_down_ = true;
109     CHECK_NE(thread_id_, base::PlatformThread::CurrentId())
110         << __func__ << " should not be called on the thread itself. "
111         << "Otherwise, deadlock may happen.";
112     run_loop_->QuitWhenIdle();
113   }
114   thread_->join();
115   {
116     std::lock_guard<std::recursive_mutex> api_lock(api_mutex_);
117     delete thread_;
118     thread_ = nullptr;
119     shutting_down_ = false;
120   }
121 }
122 
GetThreadId() const123 base::PlatformThreadId MessageLoopThread::GetThreadId() const {
124   std::lock_guard<std::recursive_mutex> api_lock(api_mutex_);
125   return thread_id_;
126 }
127 
GetName() const128 std::string MessageLoopThread::GetName() const { return thread_name_; }
129 
ToString() const130 std::string MessageLoopThread::ToString() const {
131   std::lock_guard<std::recursive_mutex> api_lock(api_mutex_);
132   return base::StringPrintf("%s(%d)", thread_name_.c_str(), thread_id_);
133 }
134 
IsRunning() const135 bool MessageLoopThread::IsRunning() const {
136   std::lock_guard<std::recursive_mutex> api_lock(api_mutex_);
137   return thread_id_ != -1;
138 }
139 
140 // Non API method, should not be protected by API mutex
RunThread(MessageLoopThread * thread,std::promise<void> start_up_promise)141 void MessageLoopThread::RunThread(MessageLoopThread* thread,
142                                   std::promise<void> start_up_promise) {
143   thread->Run(std::move(start_up_promise));
144 }
145 
message_loop() const146 btbase::AbstractMessageLoop* MessageLoopThread::message_loop() const {
147   ASSERT_LOG(!is_main_,
148              "you are not allowed to get the main thread's message loop");
149 
150   std::lock_guard<std::recursive_mutex> api_lock(api_mutex_);
151   return message_loop_;
152 }
153 
EnableRealTimeScheduling()154 bool MessageLoopThread::EnableRealTimeScheduling() {
155   std::lock_guard<std::recursive_mutex> api_lock(api_mutex_);
156 
157   if (!IsRunning()) {
158     LOG(ERROR) << __func__ << ": thread " << *this << " is not running";
159     return false;
160   }
161 
162   struct sched_param rt_params = {.sched_priority =
163                                       kRealTimeFifoSchedulingPriority};
164   int rc = sched_setscheduler(linux_tid_, SCHED_FIFO, &rt_params);
165   if (rc != 0) {
166     LOG(ERROR) << __func__ << ": unable to set SCHED_FIFO priority "
167                << kRealTimeFifoSchedulingPriority << " for linux_tid "
168                << std::to_string(linux_tid_) << ", thread " << *this
169                << ", error: " << strerror(errno);
170     return false;
171   }
172   return true;
173 }
174 
GetWeakPtr()175 base::WeakPtr<MessageLoopThread> MessageLoopThread::GetWeakPtr() {
176   std::lock_guard<std::recursive_mutex> api_lock(api_mutex_);
177   return weak_ptr_factory_.GetWeakPtr();
178 }
179 
Run(std::promise<void> start_up_promise)180 void MessageLoopThread::Run(std::promise<void> start_up_promise) {
181   {
182     std::lock_guard<std::recursive_mutex> api_lock(api_mutex_);
183 
184     LOG(INFO) << __func__ << ": message loop starting for thread "
185               << thread_name_;
186     base::PlatformThread::SetName(thread_name_);
187     message_loop_ = new btbase::AbstractMessageLoop();
188     run_loop_ = new base::RunLoop();
189     thread_id_ = base::PlatformThread::CurrentId();
190     linux_tid_ = static_cast<pid_t>(syscall(SYS_gettid));
191     start_up_promise.set_value();
192   }
193 
194   // Blocking until ShutDown() is called
195   run_loop_->Run();
196 
197   {
198     std::lock_guard<std::recursive_mutex> api_lock(api_mutex_);
199     thread_id_ = -1;
200     linux_tid_ = -1;
201     delete message_loop_;
202     message_loop_ = nullptr;
203     delete run_loop_;
204     run_loop_ = nullptr;
205     LOG(INFO) << __func__ << ": message loop finished for thread "
206               << thread_name_;
207   }
208 }
209 
210 }  // namespace common
211 
212 }  // namespace bluetooth
213