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