• 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 #pragma once
18 
19 #include <unistd.h>
20 #include <future>
21 #include <memory>
22 #include <string>
23 #include <thread>
24 
25 #include <base/bind.h>
26 #include <base/location.h>
27 #include <base/run_loop.h>
28 #include <base/threading/platform_thread.h>
29 #include "src/message_loop_thread.rs.h"
30 
31 #include "abstract_message_loop.h"
32 
33 namespace bluetooth {
34 
35 namespace common {
36 
37 /**
38  * An interface to various thread related functionality
39  */
40 class MessageLoopThread final {
41  public:
42   /**
43    * Create a message loop thread with name. Thread won't be running until
44    * StartUp is called.
45    *
46    * @param thread_name name of this worker thread
47    */
48   explicit MessageLoopThread(const std::string& thread_name);
49   explicit MessageLoopThread(const std::string& thread_name, bool is_main);
50 
51   MessageLoopThread(const MessageLoopThread&) = delete;
52   MessageLoopThread& operator=(const MessageLoopThread&) = delete;
53 
54   /**
55    * Destroys the message loop thread automatically when it goes out of scope
56    */
57   ~MessageLoopThread();
58 
59   /**
60    * Start the underlying thread. Blocks until all thread infrastructure is
61    * setup. IsRunning() and DoInThread() should return true after this call.
62    * Blocks until the thread is successfully started.
63    *
64    * Repeated call to this method will only start this thread once
65    */
66   void StartUp();
67 
68   /**
69    * Post a task to run on this thread
70    *
71    * @param from_here location where this task is originated
72    * @param task task created through base::Bind()
73    * @return true if task is successfully scheduled, false if task cannot be
74    * scheduled
75    */
76   bool DoInThread(const base::Location& from_here, base::OnceClosure task);
77 
78   /**
79    * Shutdown the current thread as if it is never started. IsRunning() and
80    * DoInThread() will return false after this call. Blocks until the thread is
81    * joined and freed. This thread can be re-started again using StartUp()
82    *
83    * Repeated call to this method will only stop this thread once
84    *
85    * NOTE: Should never be called on the thread itself to avoid deadlock
86    */
87   void ShutDown();
88 
89   /**
90    * Get the current thread ID returned by PlatformThread::CurrentId()
91    *
92    * On Android platform, this value should be the same as the tid logged by
93    * logcat, which is returned by gettid(). On other platform, this thread id
94    * may have different meanings. Therefore, this ID is only good for logging
95    * and thread comparison purpose
96    *
97    * @return this thread's ID
98    */
99   base::PlatformThreadId GetThreadId() const;
100 
101   /**
102    * Get this thread's name set in constructor
103    *
104    * @return this thread's name set in constructor
105    */
106   std::string GetName() const;
107 
108   /**
109    * Get a string representation of this thread
110    *
111    * @return a string representation of this thread
112    */
113   std::string ToString() const;
114 
115   /**
116    * Check if this thread is running
117    *
118    * @return true iff this thread is running and is able to do task
119    */
120   bool IsRunning() const;
121 
122   /**
123    * Attempt to make scheduling for this thread real time
124    *
125    * @return true on success, false otherwise
126    */
127   bool EnableRealTimeScheduling();
128 
129   /**
130    * Return the weak pointer to this object. This can be useful when posting
131    * delayed tasks to this MessageLoopThread using Timer.
132    */
133   base::WeakPtr<MessageLoopThread> GetWeakPtr();
134 
135   /**
136    * Return the message loop for this thread. Accessing raw message loop is not
137    * recommended as message loop can be freed internally.
138    *
139    * @return message loop associated with this thread, nullptr if thread is not
140    * running
141    */
142   btbase::AbstractMessageLoop* message_loop() const;
143 
144   /**
145    * Post a task to run on this thread after a specified delay. If the task
146    * needs to be cancelable before it's run, use base::CancelableClosure type
147    * for task closure. For example:
148    * <code>
149    * base::CancelableClosure cancelable_task;
150    * cancelable_task.Reset(base::Bind(...)); // bind the task
151    * same_thread->DoInThreadDelayed(FROM_HERE,
152    *                                cancelable_task.callback(), delay);
153    * ...
154    * // Cancel the task closure
155    * same_thread->DoInThread(FROM_HERE,
156    *                         base::Bind(&base::CancelableClosure::Cancel,
157    *                                    base::Unretained(&cancelable_task)));
158    * </code>
159    *
160    * Warning: base::CancelableClosure objects must be created on, posted to,
161    * cancelled on, and destroyed on the same thread.
162    *
163    * @param from_here location where this task is originated
164    * @param task task created through base::Bind()
165    * @param delay delay for the task to be executed
166    * @return true if task is successfully scheduled, false if task cannot be
167    * scheduled
168    */
169   bool DoInThreadDelayed(const base::Location& from_here,
170                          base::OnceClosure task, const base::TimeDelta& delay);
171 
172  private:
173   /**
174    * Static method to run the thread
175    *
176    * This is used instead of a C++ lambda because of the use of std::shared_ptr
177    *
178    * @param context needs to be a pointer to an instance of MessageLoopThread
179    * @param start_up_promise a std::promise that is used to notify calling
180    * thread the completion of message loop start-up
181    */
182   static void RunThread(MessageLoopThread* context,
183                         std::promise<void> start_up_promise);
184 
185   /**
186    * Actual method to run the thread, blocking until ShutDown() is called
187    *
188    * @param start_up_promise a std::promise that is used to notify calling
189    * thread the completion of message loop start-up
190    */
191   void Run(std::promise<void> start_up_promise);
192 
193   mutable std::recursive_mutex api_mutex_;
194   const std::string thread_name_;
195   btbase::AbstractMessageLoop* message_loop_;
196   base::RunLoop* run_loop_;
197   std::thread* thread_;
198   base::PlatformThreadId thread_id_;
199   // Linux specific abstractions
200   pid_t linux_tid_;
201   base::WeakPtrFactory<MessageLoopThread> weak_ptr_factory_;
202   bool shutting_down_;
203   bool is_main_;
204   ::rust::Box<shim::rust::MessageLoopThread>* rust_thread_ = nullptr;
205 };
206 
207 inline std::ostream& operator<<(std::ostream& os,
208                                 const bluetooth::common::MessageLoopThread& a) {
209   os << a.ToString();
210   return os;
211 }
212 
213 }  // namespace common
214 
215 }  // namespace bluetooth
216