1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef CONTENT_PUBLIC_BROWSER_BROWSER_THREAD_H_ 6 #define CONTENT_PUBLIC_BROWSER_BROWSER_THREAD_H_ 7 8 #include <string> 9 10 #include "base/basictypes.h" 11 #include "base/callback.h" 12 #include "base/location.h" 13 #include "base/logging.h" 14 #include "base/message_loop/message_loop_proxy.h" 15 #include "base/task_runner_util.h" 16 #include "base/time/time.h" 17 #include "content/common/content_export.h" 18 19 namespace base { 20 class MessageLoop; 21 class SequencedWorkerPool; 22 class Thread; 23 } 24 25 namespace content { 26 27 class BrowserThreadDelegate; 28 class BrowserThreadImpl; 29 30 // Use DCHECK_CURRENTLY_ON(BrowserThread::ID) to assert that a function can only 31 // be called on the named BrowserThread. 32 #define DCHECK_CURRENTLY_ON(thread_identifier) \ 33 (DCHECK(::content::BrowserThread::CurrentlyOn(thread_identifier)) \ 34 << ::content::BrowserThread::GetDCheckCurrentlyOnErrorMessage( \ 35 thread_identifier)) 36 37 /////////////////////////////////////////////////////////////////////////////// 38 // BrowserThread 39 // 40 // Utility functions for threads that are known by a browser-wide 41 // name. For example, there is one IO thread for the entire browser 42 // process, and various pieces of code find it useful to retrieve a 43 // pointer to the IO thread's message loop. 44 // 45 // Invoke a task by thread ID: 46 // 47 // BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, task); 48 // 49 // The return value is false if the task couldn't be posted because the target 50 // thread doesn't exist. If this could lead to data loss, you need to check the 51 // result and restructure the code to ensure it doesn't occur. 52 // 53 // This class automatically handles the lifetime of different threads. 54 // It's always safe to call PostTask on any thread. If it's not yet created, 55 // the task is deleted. There are no race conditions. If the thread that the 56 // task is posted to is guaranteed to outlive the current thread, then no locks 57 // are used. You should never need to cache pointers to MessageLoops, since 58 // they're not thread safe. 59 class CONTENT_EXPORT BrowserThread { 60 public: 61 // An enumeration of the well-known threads. 62 // NOTE: threads must be listed in the order of their life-time, with each 63 // thread outliving every other thread below it. 64 enum ID { 65 // The main thread in the browser. 66 UI, 67 68 // This is the thread that interacts with the database. 69 DB, 70 71 // This is the thread that interacts with the file system. 72 FILE, 73 74 // Used for file system operations that block user interactions. 75 // Responsiveness of this thread affect users. 76 FILE_USER_BLOCKING, 77 78 // Used to launch and terminate Chrome processes. 79 PROCESS_LAUNCHER, 80 81 // This is the thread to handle slow HTTP cache operations. 82 CACHE, 83 84 // This is the thread that processes IPC and network messages. 85 IO, 86 87 // NOTE: do not add new threads here that are only used by a small number of 88 // files. Instead you should just use a Thread class and pass its 89 // MessageLoopProxy around. Named threads there are only for threads that 90 // are used in many places. 91 92 // This identifier does not represent a thread. Instead it counts the 93 // number of well-known threads. Insert new well-known threads before this 94 // identifier. 95 ID_COUNT 96 }; 97 98 // These are the same methods in message_loop.h, but are guaranteed to either 99 // get posted to the MessageLoop if it's still alive, or be deleted otherwise. 100 // They return true iff the thread existed and the task was posted. Note that 101 // even if the task is posted, there's no guarantee that it will run, since 102 // the target thread may already have a Quit message in its queue. 103 static bool PostTask(ID identifier, 104 const tracked_objects::Location& from_here, 105 const base::Closure& task); 106 static bool PostDelayedTask(ID identifier, 107 const tracked_objects::Location& from_here, 108 const base::Closure& task, 109 base::TimeDelta delay); 110 static bool PostNonNestableTask(ID identifier, 111 const tracked_objects::Location& from_here, 112 const base::Closure& task); 113 static bool PostNonNestableDelayedTask( 114 ID identifier, 115 const tracked_objects::Location& from_here, 116 const base::Closure& task, 117 base::TimeDelta delay); 118 119 static bool PostTaskAndReply( 120 ID identifier, 121 const tracked_objects::Location& from_here, 122 const base::Closure& task, 123 const base::Closure& reply); 124 125 template <typename ReturnType, typename ReplyArgType> PostTaskAndReplyWithResult(ID identifier,const tracked_objects::Location & from_here,const base::Callback<ReturnType (void)> & task,const base::Callback<void (ReplyArgType)> & reply)126 static bool PostTaskAndReplyWithResult( 127 ID identifier, 128 const tracked_objects::Location& from_here, 129 const base::Callback<ReturnType(void)>& task, 130 const base::Callback<void(ReplyArgType)>& reply) { 131 scoped_refptr<base::MessageLoopProxy> message_loop_proxy = 132 GetMessageLoopProxyForThread(identifier); 133 return base::PostTaskAndReplyWithResult( 134 message_loop_proxy.get(), from_here, task, reply); 135 } 136 137 template <class T> DeleteSoon(ID identifier,const tracked_objects::Location & from_here,const T * object)138 static bool DeleteSoon(ID identifier, 139 const tracked_objects::Location& from_here, 140 const T* object) { 141 return GetMessageLoopProxyForThread(identifier)->DeleteSoon( 142 from_here, object); 143 } 144 145 template <class T> ReleaseSoon(ID identifier,const tracked_objects::Location & from_here,const T * object)146 static bool ReleaseSoon(ID identifier, 147 const tracked_objects::Location& from_here, 148 const T* object) { 149 return GetMessageLoopProxyForThread(identifier)->ReleaseSoon( 150 from_here, object); 151 } 152 153 // Simplified wrappers for posting to the blocking thread pool. Use this 154 // for doing things like blocking I/O. 155 // 156 // The first variant will run the task in the pool with no sequencing 157 // semantics, so may get run in parallel with other posted tasks. The second 158 // variant will all post a task with no sequencing semantics, and will post a 159 // reply task to the origin TaskRunner upon completion. The third variant 160 // provides sequencing between tasks with the same sequence token name. 161 // 162 // These tasks are guaranteed to run before shutdown. 163 // 164 // If you need to provide different shutdown semantics (like you have 165 // something slow and noncritical that doesn't need to block shutdown), 166 // or you want to manually provide a sequence token (which saves a map 167 // lookup and is guaranteed unique without you having to come up with a 168 // unique string), you can access the sequenced worker pool directly via 169 // GetBlockingPool(). 170 // 171 // If you need to PostTaskAndReplyWithResult, use 172 // base::PostTaskAndReplyWithResult() with GetBlockingPool() as the task 173 // runner. 174 static bool PostBlockingPoolTask(const tracked_objects::Location& from_here, 175 const base::Closure& task); 176 static bool PostBlockingPoolTaskAndReply( 177 const tracked_objects::Location& from_here, 178 const base::Closure& task, 179 const base::Closure& reply); 180 static bool PostBlockingPoolSequencedTask( 181 const std::string& sequence_token_name, 182 const tracked_objects::Location& from_here, 183 const base::Closure& task); 184 185 // Returns the thread pool used for blocking file I/O. Use this object to 186 // perform random blocking operations such as file writes or querying the 187 // Windows registry. 188 static base::SequencedWorkerPool* GetBlockingPool() WARN_UNUSED_RESULT; 189 190 // Callable on any thread. Returns whether the given well-known thread is 191 // initialized. 192 static bool IsThreadInitialized(ID identifier) WARN_UNUSED_RESULT; 193 194 // Callable on any thread. Returns whether you're currently on a particular 195 // thread. To DCHECK this, use the DCHECK_CURRENTLY_ON() macro above. 196 static bool CurrentlyOn(ID identifier) WARN_UNUSED_RESULT; 197 198 // Callable on any thread. Returns whether the threads message loop is valid. 199 // If this returns false it means the thread is in the process of shutting 200 // down. 201 static bool IsMessageLoopValid(ID identifier) WARN_UNUSED_RESULT; 202 203 // If the current message loop is one of the known threads, returns true and 204 // sets identifier to its ID. Otherwise returns false. 205 static bool GetCurrentThreadIdentifier(ID* identifier) WARN_UNUSED_RESULT; 206 207 // Callers can hold on to a refcounted MessageLoopProxy beyond the lifetime 208 // of the thread. 209 static scoped_refptr<base::MessageLoopProxy> GetMessageLoopProxyForThread( 210 ID identifier); 211 212 // Returns a pointer to the thread's message loop, which will become 213 // invalid during shutdown, so you probably shouldn't hold onto it. 214 // 215 // This must not be called before the thread is started, or after 216 // the thread is stopped, or it will DCHECK. 217 // 218 // Ownership remains with the BrowserThread implementation, so you 219 // must not delete the pointer. 220 static base::MessageLoop* UnsafeGetMessageLoopForThread(ID identifier); 221 222 // Sets the delegate for the specified BrowserThread. 223 // 224 // Only one delegate may be registered at a time. Delegates may be 225 // unregistered by providing a NULL pointer. 226 // 227 // If the caller unregisters a delegate before CleanUp has been 228 // called, it must perform its own locking to ensure the delegate is 229 // not deleted while unregistering. 230 static void SetDelegate(ID identifier, BrowserThreadDelegate* delegate); 231 232 // Use these templates in conjuction with RefCountedThreadSafe when you want 233 // to ensure that an object is deleted on a specific thread. This is needed 234 // when an object can hop between threads (i.e. IO -> FILE -> IO), and thread 235 // switching delays can mean that the final IO tasks executes before the FILE 236 // task's stack unwinds. This would lead to the object destructing on the 237 // FILE thread, which often is not what you want (i.e. to unregister from 238 // NotificationService, to notify other objects on the creating thread etc). 239 template<ID thread> 240 struct DeleteOnThread { 241 template<typename T> DestructDeleteOnThread242 static void Destruct(const T* x) { 243 if (CurrentlyOn(thread)) { 244 delete x; 245 } else { 246 if (!DeleteSoon(thread, FROM_HERE, x)) { 247 #if defined(UNIT_TEST) 248 // Only logged under unit testing because leaks at shutdown 249 // are acceptable under normal circumstances. 250 LOG(ERROR) << "DeleteSoon failed on thread " << thread; 251 #endif // UNIT_TEST 252 } 253 } 254 } 255 }; 256 257 // Sample usage: 258 // class Foo 259 // : public base::RefCountedThreadSafe< 260 // Foo, BrowserThread::DeleteOnIOThread> { 261 // 262 // ... 263 // private: 264 // friend struct BrowserThread::DeleteOnThread<BrowserThread::IO>; 265 // friend class base::DeleteHelper<Foo>; 266 // 267 // ~Foo(); 268 struct DeleteOnUIThread : public DeleteOnThread<UI> { }; 269 struct DeleteOnIOThread : public DeleteOnThread<IO> { }; 270 struct DeleteOnFileThread : public DeleteOnThread<FILE> { }; 271 struct DeleteOnDBThread : public DeleteOnThread<DB> { }; 272 273 // Returns an appropriate error message for when DCHECK_CURRENTLY_ON() fails. 274 static std::string GetDCheckCurrentlyOnErrorMessage(ID expected); 275 276 private: 277 friend class BrowserThreadImpl; 278 BrowserThread()279 BrowserThread() {} 280 DISALLOW_COPY_AND_ASSIGN(BrowserThread); 281 }; 282 283 } // namespace content 284 285 #endif // CONTENT_PUBLIC_BROWSER_BROWSER_THREAD_H_ 286