message_loop.h (21966B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. 4 // Use of this source code is governed by a BSD-style license that can be 5 // found in the LICENSE file. 6 7 #ifndef BASE_MESSAGE_LOOP_H_ 8 #define BASE_MESSAGE_LOOP_H_ 9 10 #include <deque> 11 #include <queue> 12 #include <string> 13 14 #include "base/message_pump.h" 15 #include "base/observer_list.h" 16 17 #include "mozilla/Mutex.h" 18 19 #if defined(XP_WIN) 20 // We need this to declare base::MessagePumpWin::Dispatcher, which we should 21 // really just eliminate. 22 # include "base/message_pump_win.h" 23 #elif defined(XP_DARWIN) 24 # include "base/message_pump_kqueue.h" 25 #else 26 # include "base/message_pump_libevent.h" 27 #endif 28 29 #include "nsCOMPtr.h" 30 #include "nsIRunnable.h" 31 #include "nsThreadUtils.h" 32 33 class nsISerialEventTarget; 34 35 namespace mozilla { 36 namespace ipc { 37 38 class DoWorkRunnable; 39 40 } /* namespace ipc */ 41 } /* namespace mozilla */ 42 43 // A MessageLoop is used to process events for a particular thread. There is 44 // at most one MessageLoop instance per thread. 45 // 46 // Events include at a minimum Task instances submitted to PostTask or those 47 // managed by TimerManager. Depending on the type of message pump used by the 48 // MessageLoop other events such as UI messages may be processed. On Windows 49 // APC calls (as time permits) and signals sent to a registered set of HANDLEs 50 // may also be processed. 51 // 52 // NOTE: Unless otherwise specified, a MessageLoop's methods may only be called 53 // on the thread where the MessageLoop's Run method executes. 54 // 55 // NOTE: MessageLoop has task reentrancy protection. This means that if a 56 // task is being processed, a second task cannot start until the first task is 57 // finished. Reentrancy can happen when processing a task, and an inner 58 // message pump is created. That inner pump then processes native messages 59 // which could implicitly start an inner task. Inner message pumps are created 60 // with dialogs (DialogBox), common dialogs (GetOpenFileName), OLE functions 61 // (DoDragDrop), printer functions (StartDoc) and *many* others. 62 // 63 // Sample workaround when inner task processing is needed: 64 // bool old_state = MessageLoop::current()->NestableTasksAllowed(); 65 // MessageLoop::current()->SetNestableTasksAllowed(true); 66 // HRESULT hr = DoDragDrop(...); // Implicitly runs a modal message loop here. 67 // MessageLoop::current()->SetNestableTasksAllowed(old_state); 68 // // Process hr (the result returned by DoDragDrop(). 69 // 70 // Please be SURE your task is reentrant (nestable) and all global variables 71 // are stable and accessible before calling SetNestableTasksAllowed(true). 72 // 73 class MessageLoop : public base::MessagePump::Delegate { 74 friend class mozilla::ipc::DoWorkRunnable; 75 76 public: 77 // A DestructionObserver is notified when the current MessageLoop is being 78 // destroyed. These obsevers are notified prior to MessageLoop::current() 79 // being changed to return NULL. This gives interested parties the chance to 80 // do final cleanup that depends on the MessageLoop. 81 // 82 // NOTE: Any tasks posted to the MessageLoop during this notification will 83 // not be run. Instead, they will be deleted. 84 // 85 class DestructionObserver { 86 public: 87 virtual ~DestructionObserver() {} 88 virtual void WillDestroyCurrentMessageLoop() = 0; 89 }; 90 91 // Add a DestructionObserver, which will start receiving notifications 92 // immediately. 93 void AddDestructionObserver(DestructionObserver* destruction_observer); 94 95 // Remove a DestructionObserver. It is safe to call this method while a 96 // DestructionObserver is receiving a notification callback. 97 void RemoveDestructionObserver(DestructionObserver* destruction_observer); 98 99 // The "PostTask" family of methods call the task's Run method asynchronously 100 // from within a message loop at some point in the future. 101 // 102 // With the PostTask variant, tasks are invoked in FIFO order, inter-mixed 103 // with normal UI or IO event processing. With the PostDelayedTask variant, 104 // tasks are called after at least approximately 'delay_ms' have elapsed. 105 // 106 // The NonNestable variants work similarly except that they promise never to 107 // dispatch the task from a nested invocation of MessageLoop::Run. Instead, 108 // such tasks get deferred until the top-most MessageLoop::Run is executing. 109 // 110 // The MessageLoop takes ownership of the Task, and deletes it after it has 111 // been Run(). 112 // 113 // New tasks should not be posted after the invocation of a MessageLoop's 114 // Run method. Otherwise, they may fail to actually run. Callers should check 115 // if the MessageLoop is processing tasks if necessary by calling 116 // IsAcceptingTasks(). 117 // 118 // NOTE: These methods may be called on any thread. The Task will be invoked 119 // on the thread that executes MessageLoop::Run(). 120 121 bool IsAcceptingTasks() const { return !shutting_down_; } 122 123 void PostTask(already_AddRefed<nsIRunnable> task); 124 125 void PostDelayedTask(already_AddRefed<nsIRunnable> task, int delay_ms); 126 127 // PostIdleTask is not thread safe and should be called on this thread 128 void PostIdleTask(already_AddRefed<nsIRunnable> task); 129 130 // Run the message loop. 131 void Run(); 132 133 // Signals the Run method to return after it is done processing all pending 134 // messages. This method may only be called on the same thread that called 135 // Run, and Run must still be on the call stack. 136 // 137 // Use QuitTask if you need to Quit another thread's MessageLoop, but note 138 // that doing so is fairly dangerous if the target thread makes nested calls 139 // to MessageLoop::Run. The problem being that you won't know which nested 140 // run loop you are quiting, so be careful! 141 // 142 void Quit(); 143 144 // Invokes Quit on the current MessageLoop when run. Useful to schedule an 145 // arbitrary MessageLoop to Quit. 146 class QuitTask : public mozilla::Runnable { 147 public: 148 QuitTask() : mozilla::Runnable("QuitTask") {} 149 NS_IMETHOD Run() override { 150 MessageLoop::current()->Quit(); 151 return NS_OK; 152 } 153 }; 154 155 // Return an XPCOM-compatible event target for this thread. 156 nsISerialEventTarget* SerialEventTarget(); 157 158 // A MessageLoop has a particular type, which indicates the set of 159 // asynchronous events it may process in addition to tasks and timers. 160 // 161 // TYPE_DEFAULT 162 // This type of ML only supports tasks and timers. 163 // 164 // TYPE_UI 165 // This type of ML also supports native UI events (e.g., Windows messages). 166 // See also MessageLoopForUI. 167 // 168 // TYPE_IO 169 // This type of ML also supports asynchronous IO. See also 170 // MessageLoopForIO. 171 // 172 // TYPE_MOZILLA_CHILD 173 // This type of ML is used in Mozilla child processes which initialize 174 // XPCOM and use the gecko event loop. 175 // 176 // TYPE_MOZILLA_PARENT 177 // This type of ML is used in Mozilla parent processes which initialize 178 // XPCOM and use the gecko event loop. 179 // 180 // TYPE_MOZILLA_NONMAINTHREAD 181 // This type of ML is used in Mozilla parent processes which initialize 182 // XPCOM and use the nsThread event loop. 183 // 184 // TYPE_MOZILLA_NONMAINUITHREAD 185 // This type of ML is used in Mozilla processes which initialize XPCOM 186 // and use TYPE_UI loop logic. 187 // 188 enum Type { 189 TYPE_DEFAULT, 190 TYPE_UI, 191 TYPE_IO, 192 TYPE_MOZILLA_CHILD, 193 TYPE_MOZILLA_PARENT, 194 TYPE_MOZILLA_NONMAINTHREAD, 195 TYPE_MOZILLA_NONMAINUITHREAD, 196 TYPE_MOZILLA_ANDROID_UI 197 }; 198 199 // Normally, it is not necessary to instantiate a MessageLoop. Instead, it 200 // is typical to make use of the current thread's MessageLoop instance. 201 explicit MessageLoop(Type type = TYPE_DEFAULT, 202 nsISerialEventTarget* aEventTarget = nullptr); 203 ~MessageLoop(); 204 205 // Returns the type passed to the constructor. 206 Type type() const { return type_; } 207 208 // Unique, non-repeating ID for this message loop. 209 int32_t id() const { return id_; } 210 211 // Optional call to connect the thread name with this loop. 212 void set_thread_name(const std::string& aThreadName) { 213 DCHECK(thread_name_.empty()) << "Should not rename this thread!"; 214 thread_name_ = aThreadName; 215 } 216 const std::string& thread_name() const { return thread_name_; } 217 218 // Returns the MessageLoop object for the current thread, or null if none. 219 static MessageLoop* current(); 220 221 static void set_current(MessageLoop* loop); 222 223 // Enables or disables the recursive task processing. This happens in the case 224 // of recursive message loops. Some unwanted message loop may occurs when 225 // using common controls or printer functions. By default, recursive task 226 // processing is disabled. 227 // 228 // The specific case where tasks get queued is: 229 // - The thread is running a message loop. 230 // - It receives a task #1 and execute it. 231 // - The task #1 implicitly start a message loop, like a MessageBox in the 232 // unit test. This can also be StartDoc or GetSaveFileName. 233 // - The thread receives a task #2 before or while in this second message 234 // loop. 235 // - With NestableTasksAllowed set to true, the task #2 will run right away. 236 // Otherwise, it will get executed right after task #1 completes at "thread 237 // message loop level". 238 void SetNestableTasksAllowed(bool allowed); 239 void ScheduleWork(); 240 bool NestableTasksAllowed() const; 241 242 // Enables or disables the restoration during an exception of the unhandled 243 // exception filter that was active when Run() was called. This can happen 244 // if some third party code call SetUnhandledExceptionFilter() and never 245 // restores the previous filter. 246 void set_exception_restoration(bool restore) { 247 exception_restoration_ = restore; 248 } 249 250 #if defined(XP_WIN) 251 void set_os_modal_loop(bool os_modal_loop) { os_modal_loop_ = os_modal_loop; } 252 253 bool& os_modal_loop() { return os_modal_loop_; } 254 #endif // XP_WIN 255 256 // Set the timeouts for background hang monitoring. 257 // A value of 0 indicates there is no timeout. 258 void set_hang_timeouts(uint32_t transient_timeout_ms, 259 uint32_t permanent_timeout_ms) { 260 transient_hang_timeout_ = transient_timeout_ms; 261 permanent_hang_timeout_ = permanent_timeout_ms; 262 } 263 uint32_t transient_hang_timeout() const { return transient_hang_timeout_; } 264 uint32_t permanent_hang_timeout() const { return permanent_hang_timeout_; } 265 266 //---------------------------------------------------------------------------- 267 protected: 268 struct RunState { 269 // Used to count how many Run() invocations are on the stack. 270 int run_depth; 271 272 // Used to record that Quit() was called, or that we should quit the pump 273 // once it becomes idle. 274 bool quit_received; 275 276 #if defined(XP_WIN) 277 base::MessagePumpWin::Dispatcher* dispatcher; 278 #endif 279 }; 280 281 class AutoRunState : RunState { 282 public: 283 explicit AutoRunState(MessageLoop* loop); 284 ~AutoRunState(); 285 286 private: 287 MessageLoop* loop_; 288 RunState* previous_state_; 289 }; 290 291 // This structure is copied around by value. 292 struct PendingTask { 293 nsCOMPtr<nsIRunnable> task; // The task to run. 294 base::TimeTicks delayed_run_time; // The time when the task should be run. 295 int sequence_num; // Secondary sort key for run time. 296 bool nestable; // OK to dispatch from a nested loop. 297 298 PendingTask(already_AddRefed<nsIRunnable> aTask, bool aNestable) 299 : task(aTask), sequence_num(0), nestable(aNestable) {} 300 301 PendingTask(PendingTask&& aOther) 302 : task(std::move(aOther.task)), 303 delayed_run_time(aOther.delayed_run_time), 304 sequence_num(aOther.sequence_num), 305 nestable(aOther.nestable) {} 306 307 // std::priority_queue<T>::top is dumb, so we have to have this. 308 PendingTask(const PendingTask& aOther) 309 : task(aOther.task), 310 delayed_run_time(aOther.delayed_run_time), 311 sequence_num(aOther.sequence_num), 312 nestable(aOther.nestable) {} 313 PendingTask& operator=(const PendingTask& aOther) { 314 task = aOther.task; 315 delayed_run_time = aOther.delayed_run_time; 316 sequence_num = aOther.sequence_num; 317 nestable = aOther.nestable; 318 return *this; 319 } 320 321 // Used to support sorting. 322 bool operator<(const PendingTask& other) const; 323 }; 324 325 typedef std::queue<PendingTask> TaskQueue; 326 typedef std::priority_queue<PendingTask> DelayedTaskQueue; 327 328 #if defined(XP_WIN) 329 base::MessagePumpWin* pump_win() { 330 return static_cast<base::MessagePumpWin*>(pump_.get()); 331 } 332 #elif defined(XP_DARWIN) 333 base::MessagePumpKqueue* pump_kqueue() { 334 return static_cast<base::MessagePumpKqueue*>(pump_.get()); 335 } 336 #else 337 base::MessagePumpLibevent* pump_libevent() { 338 return static_cast<base::MessagePumpLibevent*>(pump_.get()); 339 } 340 #endif 341 342 // A function to encapsulate all the exception handling capability in the 343 // stacks around the running of a main message loop. It will run the message 344 // loop in a SEH try block or not depending on the set_SEH_restoration() 345 // flag. 346 void RunHandler(); 347 348 // A surrounding stack frame around the running of the message loop that 349 // supports all saving and restoring of state, as is needed for any/all (ugly) 350 // recursive calls. 351 void RunInternal(); 352 353 // Called to process any delayed non-nestable tasks. 354 bool ProcessNextDelayedNonNestableTask(); 355 356 //---------------------------------------------------------------------------- 357 // Run a work_queue_ task or new_task, and delete it (if it was processed by 358 // PostTask). If there are queued tasks, the oldest one is executed and 359 // new_task is queued. new_task is optional and can be NULL. In this NULL 360 // case, the method will run one pending task (if any exist). Returns true if 361 // it executes a task. Queued tasks accumulate only when there is a 362 // non-nestable task currently processing, in which case the new_task is 363 // appended to the list work_queue_. Such re-entrancy generally happens when 364 // an unrequested message pump (typical of a native dialog) is executing in 365 // the context of a task. 366 bool QueueOrRunTask(already_AddRefed<nsIRunnable> new_task); 367 368 // Runs the specified task and deletes it. 369 void RunTask(already_AddRefed<nsIRunnable> task); 370 371 // Calls RunTask or queues the pending_task on the deferred task list if it 372 // cannot be run right now. Returns true if the task was run. 373 bool DeferOrRunPendingTask(PendingTask&& pending_task); 374 375 // Adds the pending task to delayed_work_queue_. 376 void AddToDelayedWorkQueue(const PendingTask& pending_task); 377 378 // Load tasks from the incoming_queue_ into work_queue_ if the latter is 379 // empty. The former requires a lock to access, while the latter is directly 380 // accessible on this thread. 381 void ReloadWorkQueue(); 382 383 // Delete tasks that haven't run yet without running them. Used in the 384 // destructor to make sure all the task's destructors get called. Returns 385 // true if some work was done. 386 bool DeletePendingTasks(); 387 388 // Post a task to our incomming queue. 389 void PostTask_Helper(already_AddRefed<nsIRunnable> task, int delay_ms); 390 391 // base::MessagePump::Delegate methods: 392 virtual bool DoWork() override; 393 virtual bool DoDelayedWork(base::TimeTicks* next_delayed_work_time) override; 394 virtual bool DoIdleWork() override; 395 396 Type type_; 397 int32_t id_; 398 399 // A list of tasks that need to be processed by this instance. Note that 400 // this queue is only accessed (push/pop) by our current thread. 401 TaskQueue work_queue_; 402 403 // Contains delayed tasks, sorted by their 'delayed_run_time' property. 404 DelayedTaskQueue delayed_work_queue_; 405 406 // A queue of non-nestable tasks that we had to defer because when it came 407 // time to execute them we were in a nested message loop. They will execute 408 // once we're out of nested message loops. 409 TaskQueue deferred_non_nestable_work_queue_; 410 411 RefPtr<base::MessagePump> pump_; 412 413 base::ObserverList<DestructionObserver> destruction_observers_; 414 415 // A recursion block that prevents accidentally running additonal tasks when 416 // insider a (accidentally induced?) nested message pump. 417 bool nestable_tasks_allowed_; 418 419 bool exception_restoration_; 420 421 std::string thread_name_; 422 423 // A null terminated list which creates an incoming_queue of tasks that are 424 // aquired under a mutex for processing on this instance's thread. These tasks 425 // have not yet been sorted out into items for our work_queue_ vs items that 426 // will be handled by the TimerManager. 427 TaskQueue incoming_queue_ MOZ_GUARDED_BY(incoming_queue_lock_); 428 // Protect access to incoming_queue_. 429 mozilla::Mutex incoming_queue_lock_; 430 431 RunState* state_; 432 int run_depth_base_; 433 bool shutting_down_; 434 435 #if defined(XP_WIN) 436 // Should be set to true before calling Windows APIs like TrackPopupMenu, etc 437 // which enter a modal message loop. 438 bool os_modal_loop_; 439 #endif 440 441 // Timeout values for hang monitoring 442 uint32_t transient_hang_timeout_; 443 uint32_t permanent_hang_timeout_; 444 445 // The next sequence number to use for delayed tasks. 446 int next_sequence_num_; 447 448 class EventTarget; 449 RefPtr<EventTarget> mEventTarget; 450 451 DISALLOW_COPY_AND_ASSIGN(MessageLoop); 452 }; 453 454 //----------------------------------------------------------------------------- 455 // MessageLoopForUI extends MessageLoop with methods that are particular to a 456 // MessageLoop instantiated with TYPE_UI. 457 // 458 // This class is typically used like so: 459 // MessageLoopForUI::current()->...call some method... 460 // 461 class MessageLoopForUI : public MessageLoop { 462 public: 463 explicit MessageLoopForUI(Type aType = TYPE_UI) : MessageLoop(aType) {} 464 465 // Returns the MessageLoopForUI of the current thread. 466 static MessageLoopForUI* current() { 467 MessageLoop* loop = MessageLoop::current(); 468 if (!loop) return NULL; 469 Type type = loop->type(); 470 DCHECK(type == MessageLoop::TYPE_UI || 471 type == MessageLoop::TYPE_MOZILLA_PARENT || 472 type == MessageLoop::TYPE_MOZILLA_CHILD); 473 return static_cast<MessageLoopForUI*>(loop); 474 } 475 476 #if defined(XP_WIN) 477 typedef base::MessagePumpWin::Dispatcher Dispatcher; 478 typedef base::MessagePumpWin::Observer Observer; 479 480 // Please see MessagePumpWin for definitions of these methods. 481 void Run(Dispatcher* dispatcher); 482 void AddObserver(Observer* observer); 483 void RemoveObserver(Observer* observer); 484 void WillProcessMessage(const MSG& message); 485 void DidProcessMessage(const MSG& message); 486 void PumpOutPendingPaintMessages(); 487 488 protected: 489 // TODO(rvargas): Make this platform independent. 490 base::MessagePumpForUI* pump_ui() { 491 return static_cast<base::MessagePumpForUI*>(pump_.get()); 492 } 493 #endif // defined(XP_WIN) 494 }; 495 496 // Do not add any member variables to MessageLoopForUI! This is important b/c 497 // MessageLoopForUI is often allocated via MessageLoop(TYPE_UI). Any extra 498 // data that you need should be stored on the MessageLoop's pump_ instance. 499 COMPILE_ASSERT(sizeof(MessageLoop) == sizeof(MessageLoopForUI), 500 MessageLoopForUI_should_not_have_extra_member_variables); 501 502 //----------------------------------------------------------------------------- 503 // MessageLoopForIO extends MessageLoop with methods that are particular to a 504 // MessageLoop instantiated with TYPE_IO. 505 // 506 // This class is typically used like so: 507 // MessageLoopForIO::current()->...call some method... 508 // 509 class MessageLoopForIO : public MessageLoop { 510 public: 511 MessageLoopForIO() : MessageLoop(TYPE_IO) {} 512 513 // Returns the MessageLoopForIO of the current thread. 514 static MessageLoopForIO* current() { 515 MessageLoop* loop = MessageLoop::current(); 516 DCHECK_EQ(MessageLoop::TYPE_IO, loop->type()); 517 return static_cast<MessageLoopForIO*>(loop); 518 } 519 520 #if defined(XP_WIN) 521 typedef base::MessagePumpForIO::IOHandler IOHandler; 522 typedef base::MessagePumpForIO::IOContext IOContext; 523 524 // Please see MessagePumpWin for definitions of these methods. 525 void RegisterIOHandler(HANDLE file_handle, IOHandler* handler); 526 bool WaitForIOCompletion(DWORD timeout, IOHandler* filter); 527 528 protected: 529 // TODO(rvargas): Make this platform independent. 530 base::MessagePumpForIO* pump_io() { 531 return static_cast<base::MessagePumpForIO*>(pump_.get()); 532 } 533 534 #elif defined(XP_DARWIN) 535 536 typedef base::MessagePumpKqueue::Watcher Watcher; 537 typedef base::MessagePumpKqueue::FileDescriptorWatcher FileDescriptorWatcher; 538 typedef base::MessagePumpKqueue::MachPortWatcher MachPortWatcher; 539 typedef base::MessagePumpKqueue::MachPortWatchController 540 MachPortWatchController; 541 542 enum Mode { 543 WATCH_READ = base::MessagePumpKqueue::WATCH_READ, 544 WATCH_WRITE = base::MessagePumpKqueue::WATCH_WRITE, 545 WATCH_READ_WRITE = base::MessagePumpKqueue::WATCH_READ_WRITE 546 }; 547 548 // Please see MessagePumpKqueue for definition. 549 bool WatchFileDescriptor(int fd, bool persistent, Mode mode, 550 FileDescriptorWatcher* controller, 551 Watcher* delegate); 552 bool WatchMachReceivePort(mach_port_t port, 553 MachPortWatchController* controller, 554 MachPortWatcher* delegate); 555 556 #else 557 typedef base::MessagePumpLibevent::Watcher Watcher; 558 typedef base::MessagePumpLibevent::FileDescriptorWatcher 559 FileDescriptorWatcher; 560 561 enum Mode { 562 WATCH_READ = base::MessagePumpLibevent::WATCH_READ, 563 WATCH_WRITE = base::MessagePumpLibevent::WATCH_WRITE, 564 WATCH_READ_WRITE = base::MessagePumpLibevent::WATCH_READ_WRITE 565 }; 566 567 // Please see MessagePumpLibevent for definition. 568 bool WatchFileDescriptor(int fd, bool persistent, Mode mode, 569 FileDescriptorWatcher* controller, 570 Watcher* delegate); 571 #endif 572 }; 573 574 // Do not add any member variables to MessageLoopForIO! This is important b/c 575 // MessageLoopForIO is often allocated via MessageLoop(TYPE_IO). Any extra 576 // data that you need should be stored on the MessageLoop's pump_ instance. 577 COMPILE_ASSERT(sizeof(MessageLoop) == sizeof(MessageLoopForIO), 578 MessageLoopForIO_should_not_have_extra_member_variables); 579 580 #endif // BASE_MESSAGE_LOOP_H_