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