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