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