1 // Copyright (c) 2011 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 BASE_MESSAGE_LOOP_H_ 6 #define BASE_MESSAGE_LOOP_H_ 7 #pragma once 8 9 #include <queue> 10 #include <string> 11 12 #include "base/base_api.h" 13 #include "base/basictypes.h" 14 #include "base/memory/ref_counted.h" 15 #include "base/message_pump.h" 16 #include "base/observer_list.h" 17 #include "base/synchronization/lock.h" 18 #include "base/task.h" 19 20 #if defined(OS_WIN) 21 // We need this to declare base::MessagePumpWin::Dispatcher, which we should 22 // really just eliminate. 23 #include "base/message_pump_win.h" 24 #elif defined(OS_POSIX) 25 #include "base/message_pump_libevent.h" 26 #if !defined(OS_MACOSX) 27 #include "base/message_pump_glib.h" 28 typedef struct _XDisplay Display; 29 #endif 30 #endif 31 #if defined(TOUCH_UI) 32 #include "base/message_pump_glib_x_dispatch.h" 33 #endif 34 35 namespace base { 36 class Histogram; 37 } 38 39 // A MessageLoop is used to process events for a particular thread. There is 40 // at most one MessageLoop instance per thread. 41 // 42 // Events include at a minimum Task instances submitted to PostTask or those 43 // managed by TimerManager. Depending on the type of message pump used by the 44 // MessageLoop other events such as UI messages may be processed. On Windows 45 // APC calls (as time permits) and signals sent to a registered set of HANDLEs 46 // may also be processed. 47 // 48 // NOTE: Unless otherwise specified, a MessageLoop's methods may only be called 49 // on the thread where the MessageLoop's Run method executes. 50 // 51 // NOTE: MessageLoop has task reentrancy protection. This means that if a 52 // task is being processed, a second task cannot start until the first task is 53 // finished. Reentrancy can happen when processing a task, and an inner 54 // message pump is created. That inner pump then processes native messages 55 // which could implicitly start an inner task. Inner message pumps are created 56 // with dialogs (DialogBox), common dialogs (GetOpenFileName), OLE functions 57 // (DoDragDrop), printer functions (StartDoc) and *many* others. 58 // 59 // Sample workaround when inner task processing is needed: 60 // bool old_state = MessageLoop::current()->NestableTasksAllowed(); 61 // MessageLoop::current()->SetNestableTasksAllowed(true); 62 // HRESULT hr = DoDragDrop(...); // Implicitly runs a modal message loop here. 63 // MessageLoop::current()->SetNestableTasksAllowed(old_state); 64 // // Process hr (the result returned by DoDragDrop(). 65 // 66 // Please be SURE your task is reentrant (nestable) and all global variables 67 // are stable and accessible before calling SetNestableTasksAllowed(true). 68 // 69 class BASE_API MessageLoop : public base::MessagePump::Delegate { 70 public: 71 #if defined(OS_WIN) 72 typedef base::MessagePumpWin::Dispatcher Dispatcher; 73 typedef base::MessagePumpForUI::Observer Observer; 74 #elif !defined(OS_MACOSX) 75 #if defined(TOUCH_UI) 76 typedef base::MessagePumpGlibXDispatcher Dispatcher; 77 #else 78 typedef base::MessagePumpForUI::Dispatcher Dispatcher; 79 #endif 80 typedef base::MessagePumpForUI::Observer Observer; 81 #endif 82 83 // A MessageLoop has a particular type, which indicates the set of 84 // asynchronous events it may process in addition to tasks and timers. 85 // 86 // TYPE_DEFAULT 87 // This type of ML only supports tasks and timers. 88 // 89 // TYPE_UI 90 // This type of ML also supports native UI events (e.g., Windows messages). 91 // See also MessageLoopForUI. 92 // 93 // TYPE_IO 94 // This type of ML also supports asynchronous IO. See also 95 // MessageLoopForIO. 96 // 97 enum Type { 98 TYPE_DEFAULT, 99 TYPE_UI, 100 TYPE_IO 101 }; 102 103 // Normally, it is not necessary to instantiate a MessageLoop. Instead, it 104 // is typical to make use of the current thread's MessageLoop instance. 105 explicit MessageLoop(Type type = TYPE_DEFAULT); 106 ~MessageLoop(); 107 108 // Returns the MessageLoop object for the current thread, or null if none. 109 static MessageLoop* current(); 110 111 static void EnableHistogrammer(bool enable_histogrammer); 112 113 // A DestructionObserver is notified when the current MessageLoop is being 114 // destroyed. These obsevers are notified prior to MessageLoop::current() 115 // being changed to return NULL. This gives interested parties the chance to 116 // do final cleanup that depends on the MessageLoop. 117 // 118 // NOTE: Any tasks posted to the MessageLoop during this notification will 119 // not be run. Instead, they will be deleted. 120 // 121 class BASE_API DestructionObserver { 122 public: 123 virtual void WillDestroyCurrentMessageLoop() = 0; 124 125 protected: 126 virtual ~DestructionObserver(); 127 }; 128 129 // Add a DestructionObserver, which will start receiving notifications 130 // immediately. 131 void AddDestructionObserver(DestructionObserver* destruction_observer); 132 133 // Remove a DestructionObserver. It is safe to call this method while a 134 // DestructionObserver is receiving a notification callback. 135 void RemoveDestructionObserver(DestructionObserver* destruction_observer); 136 137 // The "PostTask" family of methods call the task's Run method asynchronously 138 // from within a message loop at some point in the future. 139 // 140 // With the PostTask variant, tasks are invoked in FIFO order, inter-mixed 141 // with normal UI or IO event processing. With the PostDelayedTask variant, 142 // tasks are called after at least approximately 'delay_ms' have elapsed. 143 // 144 // The NonNestable variants work similarly except that they promise never to 145 // dispatch the task from a nested invocation of MessageLoop::Run. Instead, 146 // such tasks get deferred until the top-most MessageLoop::Run is executing. 147 // 148 // The MessageLoop takes ownership of the Task, and deletes it after it has 149 // been Run(). 150 // 151 // NOTE: These methods may be called on any thread. The Task will be invoked 152 // on the thread that executes MessageLoop::Run(). 153 154 void PostTask( 155 const tracked_objects::Location& from_here, Task* task); 156 157 void PostDelayedTask( 158 const tracked_objects::Location& from_here, Task* task, int64 delay_ms); 159 160 void PostNonNestableTask( 161 const tracked_objects::Location& from_here, Task* task); 162 163 void PostNonNestableDelayedTask( 164 const tracked_objects::Location& from_here, Task* task, int64 delay_ms); 165 166 // A variant on PostTask that deletes the given object. This is useful 167 // if the object needs to live until the next run of the MessageLoop (for 168 // example, deleting a RenderProcessHost from within an IPC callback is not 169 // good). 170 // 171 // NOTE: This method may be called on any thread. The object will be deleted 172 // on the thread that executes MessageLoop::Run(). If this is not the same 173 // as the thread that calls PostDelayedTask(FROM_HERE, ), then T MUST inherit 174 // from RefCountedThreadSafe<T>! 175 template <class T> DeleteSoon(const tracked_objects::Location & from_here,const T * object)176 void DeleteSoon(const tracked_objects::Location& from_here, const T* object) { 177 PostNonNestableTask(from_here, new DeleteTask<T>(object)); 178 } 179 180 // A variant on PostTask that releases the given reference counted object 181 // (by calling its Release method). This is useful if the object needs to 182 // live until the next run of the MessageLoop, or if the object needs to be 183 // released on a particular thread. 184 // 185 // NOTE: This method may be called on any thread. The object will be 186 // released (and thus possibly deleted) on the thread that executes 187 // MessageLoop::Run(). If this is not the same as the thread that calls 188 // PostDelayedTask(FROM_HERE, ), then T MUST inherit from 189 // RefCountedThreadSafe<T>! 190 template <class T> ReleaseSoon(const tracked_objects::Location & from_here,const T * object)191 void ReleaseSoon(const tracked_objects::Location& from_here, 192 const T* object) { 193 PostNonNestableTask(from_here, new ReleaseTask<T>(object)); 194 } 195 196 // Run the message loop. 197 void Run(); 198 199 // Process all pending tasks, windows messages, etc., but don't wait/sleep. 200 // Return as soon as all items that can be run are taken care of. 201 void RunAllPending(); 202 203 // Signals the Run method to return after it is done processing all pending 204 // messages. This method may only be called on the same thread that called 205 // Run, and Run must still be on the call stack. 206 // 207 // Use QuitTask if you need to Quit another thread's MessageLoop, but note 208 // that doing so is fairly dangerous if the target thread makes nested calls 209 // to MessageLoop::Run. The problem being that you won't know which nested 210 // run loop you are quiting, so be careful! 211 // 212 void Quit(); 213 214 // This method is a variant of Quit, that does not wait for pending messages 215 // to be processed before returning from Run. 216 void QuitNow(); 217 218 // Invokes Quit on the current MessageLoop when run. Useful to schedule an 219 // arbitrary MessageLoop to Quit. 220 class QuitTask : public Task { 221 public: Run()222 virtual void Run() { 223 MessageLoop::current()->Quit(); 224 } 225 }; 226 227 // Returns the type passed to the constructor. type()228 Type type() const { return type_; } 229 230 // Optional call to connect the thread name with this loop. set_thread_name(const std::string & thread_name)231 void set_thread_name(const std::string& thread_name) { 232 DCHECK(thread_name_.empty()) << "Should not rename this thread!"; 233 thread_name_ = thread_name; 234 } thread_name()235 const std::string& thread_name() const { return thread_name_; } 236 237 // Enables or disables the recursive task processing. This happens in the case 238 // of recursive message loops. Some unwanted message loop may occurs when 239 // using common controls or printer functions. By default, recursive task 240 // processing is disabled. 241 // 242 // The specific case where tasks get queued is: 243 // - The thread is running a message loop. 244 // - It receives a task #1 and execute it. 245 // - The task #1 implicitly start a message loop, like a MessageBox in the 246 // unit test. This can also be StartDoc or GetSaveFileName. 247 // - The thread receives a task #2 before or while in this second message 248 // loop. 249 // - With NestableTasksAllowed set to true, the task #2 will run right away. 250 // Otherwise, it will get executed right after task #1 completes at "thread 251 // message loop level". 252 void SetNestableTasksAllowed(bool allowed); 253 bool NestableTasksAllowed() const; 254 255 // Enables nestable tasks on |loop| while in scope. 256 class ScopedNestableTaskAllower { 257 public: ScopedNestableTaskAllower(MessageLoop * loop)258 explicit ScopedNestableTaskAllower(MessageLoop* loop) 259 : loop_(loop), 260 old_state_(loop_->NestableTasksAllowed()) { 261 loop_->SetNestableTasksAllowed(true); 262 } ~ScopedNestableTaskAllower()263 ~ScopedNestableTaskAllower() { 264 loop_->SetNestableTasksAllowed(old_state_); 265 } 266 267 private: 268 MessageLoop* loop_; 269 bool old_state_; 270 }; 271 272 // Enables or disables the restoration during an exception of the unhandled 273 // exception filter that was active when Run() was called. This can happen 274 // if some third party code call SetUnhandledExceptionFilter() and never 275 // restores the previous filter. set_exception_restoration(bool restore)276 void set_exception_restoration(bool restore) { 277 exception_restoration_ = restore; 278 } 279 280 // Returns true if we are currently running a nested message loop. 281 bool IsNested(); 282 283 // A TaskObserver is an object that receives task notifications from the 284 // MessageLoop. 285 // 286 // NOTE: A TaskObserver implementation should be extremely fast! 287 class BASE_API TaskObserver { 288 public: 289 TaskObserver(); 290 291 // This method is called before processing a task. 292 virtual void WillProcessTask(const Task* task) = 0; 293 294 // This method is called after processing a task. 295 virtual void DidProcessTask(const Task* task) = 0; 296 297 protected: 298 virtual ~TaskObserver(); 299 }; 300 301 // These functions can only be called on the same thread that |this| is 302 // running on. 303 void AddTaskObserver(TaskObserver* task_observer); 304 void RemoveTaskObserver(TaskObserver* task_observer); 305 306 // Returns true if the message loop has high resolution timers enabled. 307 // Provided for testing. high_resolution_timers_enabled()308 bool high_resolution_timers_enabled() { 309 #if defined(OS_WIN) 310 return !high_resolution_timer_expiration_.is_null(); 311 #else 312 return true; 313 #endif 314 } 315 316 // When we go into high resolution timer mode, we will stay in hi-res mode 317 // for at least 1s. 318 static const int kHighResolutionTimerModeLeaseTimeMs = 1000; 319 320 // Asserts that the MessageLoop is "idle". 321 void AssertIdle() const; 322 323 #if defined(OS_WIN) set_os_modal_loop(bool os_modal_loop)324 void set_os_modal_loop(bool os_modal_loop) { 325 os_modal_loop_ = os_modal_loop; 326 } 327 os_modal_loop()328 bool os_modal_loop() const { 329 return os_modal_loop_; 330 } 331 #endif // OS_WIN 332 333 //---------------------------------------------------------------------------- 334 protected: 335 struct RunState { 336 // Used to count how many Run() invocations are on the stack. 337 int run_depth; 338 339 // Used to record that Quit() was called, or that we should quit the pump 340 // once it becomes idle. 341 bool quit_received; 342 343 #if !defined(OS_MACOSX) 344 Dispatcher* dispatcher; 345 #endif 346 }; 347 348 class AutoRunState : RunState { 349 public: 350 explicit AutoRunState(MessageLoop* loop); 351 ~AutoRunState(); 352 private: 353 MessageLoop* loop_; 354 RunState* previous_state_; 355 }; 356 357 // This structure is copied around by value. 358 struct PendingTask { PendingTaskPendingTask359 PendingTask(Task* task, bool nestable) 360 : task(task), sequence_num(0), nestable(nestable) { 361 } 362 363 // Used to support sorting. 364 bool operator<(const PendingTask& other) const; 365 366 Task* task; // The task to run. 367 base::TimeTicks delayed_run_time; // The time when the task should be run. 368 int sequence_num; // Secondary sort key for run time. 369 bool nestable; // OK to dispatch from a nested loop. 370 }; 371 372 class TaskQueue : public std::queue<PendingTask> { 373 public: Swap(TaskQueue * queue)374 void Swap(TaskQueue* queue) { 375 c.swap(queue->c); // Calls std::deque::swap 376 } 377 }; 378 379 typedef std::priority_queue<PendingTask> DelayedTaskQueue; 380 381 #if defined(OS_WIN) pump_win()382 base::MessagePumpWin* pump_win() { 383 return static_cast<base::MessagePumpWin*>(pump_.get()); 384 } 385 #elif defined(OS_POSIX) pump_libevent()386 base::MessagePumpLibevent* pump_libevent() { 387 return static_cast<base::MessagePumpLibevent*>(pump_.get()); 388 } 389 #endif 390 391 // A function to encapsulate all the exception handling capability in the 392 // stacks around the running of a main message loop. It will run the message 393 // loop in a SEH try block or not depending on the set_SEH_restoration() 394 // flag invoking respectively RunInternalInSEHFrame() or RunInternal(). 395 void RunHandler(); 396 397 #if defined(OS_WIN) 398 __declspec(noinline) void RunInternalInSEHFrame(); 399 #endif 400 401 // A surrounding stack frame around the running of the message loop that 402 // supports all saving and restoring of state, as is needed for any/all (ugly) 403 // recursive calls. 404 void RunInternal(); 405 406 // Called to process any delayed non-nestable tasks. 407 bool ProcessNextDelayedNonNestableTask(); 408 409 // Runs the specified task and deletes it. 410 void RunTask(Task* task); 411 412 // Calls RunTask or queues the pending_task on the deferred task list if it 413 // cannot be run right now. Returns true if the task was run. 414 bool DeferOrRunPendingTask(const PendingTask& pending_task); 415 416 // Adds the pending task to delayed_work_queue_. 417 void AddToDelayedWorkQueue(const PendingTask& pending_task); 418 419 // Load tasks from the incoming_queue_ into work_queue_ if the latter is 420 // empty. The former requires a lock to access, while the latter is directly 421 // accessible on this thread. 422 void ReloadWorkQueue(); 423 424 // Delete tasks that haven't run yet without running them. Used in the 425 // destructor to make sure all the task's destructors get called. Returns 426 // true if some work was done. 427 bool DeletePendingTasks(); 428 429 // Post a task to our incomming queue. 430 void PostTask_Helper(const tracked_objects::Location& from_here, Task* task, 431 int64 delay_ms, bool nestable); 432 433 // Start recording histogram info about events and action IF it was enabled 434 // and IF the statistics recorder can accept a registration of our histogram. 435 void StartHistogrammer(); 436 437 // Add occurence of event to our histogram, so that we can see what is being 438 // done in a specific MessageLoop instance (i.e., specific thread). 439 // If message_histogram_ is NULL, this is a no-op. 440 void HistogramEvent(int event); 441 442 // base::MessagePump::Delegate methods: 443 virtual bool DoWork(); 444 virtual bool DoDelayedWork(base::TimeTicks* next_delayed_work_time); 445 virtual bool DoIdleWork(); 446 447 Type type_; 448 449 // A list of tasks that need to be processed by this instance. Note that 450 // this queue is only accessed (push/pop) by our current thread. 451 TaskQueue work_queue_; 452 453 // Contains delayed tasks, sorted by their 'delayed_run_time' property. 454 DelayedTaskQueue delayed_work_queue_; 455 456 // A recent snapshot of Time::Now(), used to check delayed_work_queue_. 457 base::TimeTicks recent_time_; 458 459 // A queue of non-nestable tasks that we had to defer because when it came 460 // time to execute them we were in a nested message loop. They will execute 461 // once we're out of nested message loops. 462 TaskQueue deferred_non_nestable_work_queue_; 463 464 scoped_refptr<base::MessagePump> pump_; 465 466 ObserverList<DestructionObserver> destruction_observers_; 467 468 // A recursion block that prevents accidentally running additonal tasks when 469 // insider a (accidentally induced?) nested message pump. 470 bool nestable_tasks_allowed_; 471 472 bool exception_restoration_; 473 474 std::string thread_name_; 475 // A profiling histogram showing the counts of various messages and events. 476 base::Histogram* message_histogram_; 477 478 // A null terminated list which creates an incoming_queue of tasks that are 479 // acquired under a mutex for processing on this instance's thread. These 480 // tasks have not yet been sorted out into items for our work_queue_ vs 481 // items that will be handled by the TimerManager. 482 TaskQueue incoming_queue_; 483 // Protect access to incoming_queue_. 484 mutable base::Lock incoming_queue_lock_; 485 486 RunState* state_; 487 488 #if defined(OS_WIN) 489 base::TimeTicks high_resolution_timer_expiration_; 490 // Should be set to true before calling Windows APIs like TrackPopupMenu, etc 491 // which enter a modal message loop. 492 bool os_modal_loop_; 493 #endif 494 495 // The next sequence number to use for delayed tasks. 496 int next_sequence_num_; 497 498 ObserverList<TaskObserver> task_observers_; 499 500 private: 501 DISALLOW_COPY_AND_ASSIGN(MessageLoop); 502 }; 503 504 //----------------------------------------------------------------------------- 505 // MessageLoopForUI extends MessageLoop with methods that are particular to a 506 // MessageLoop instantiated with TYPE_UI. 507 // 508 // This class is typically used like so: 509 // MessageLoopForUI::current()->...call some method... 510 // 511 class BASE_API MessageLoopForUI : public MessageLoop { 512 public: MessageLoopForUI()513 MessageLoopForUI() : MessageLoop(TYPE_UI) { 514 } 515 516 // Returns the MessageLoopForUI of the current thread. current()517 static MessageLoopForUI* current() { 518 MessageLoop* loop = MessageLoop::current(); 519 #ifdef ANDROID 520 DCHECK_EQ(static_cast<int>(MessageLoop::TYPE_UI), 521 static_cast<int>(loop->type())); 522 #else 523 DCHECK_EQ(MessageLoop::TYPE_UI, loop->type()); 524 #endif 525 return static_cast<MessageLoopForUI*>(loop); 526 } 527 528 #if defined(OS_WIN) 529 void DidProcessMessage(const MSG& message); 530 #endif // defined(OS_WIN) 531 532 #if defined(USE_X11) 533 // Returns the Xlib Display that backs the MessagePump for this MessageLoop. 534 // 535 // This allows for raw access to the X11 server in situations where our 536 // abstractions do not provide enough power. 537 // 538 // Be careful how this is used. The MessagePump in general expects 539 // exclusive access to the Display. Calling things like XNextEvent() will 540 // likely break things in subtle, hard to detect, ways. 541 Display* GetDisplay(); 542 #endif // defined(OS_X11) 543 544 #if !defined(OS_MACOSX) 545 // Please see message_pump_win/message_pump_glib for definitions of these 546 // methods. 547 void AddObserver(Observer* observer); 548 void RemoveObserver(Observer* observer); 549 void Run(Dispatcher* dispatcher); 550 551 protected: 552 // TODO(rvargas): Make this platform independent. pump_ui()553 base::MessagePumpForUI* pump_ui() { 554 return static_cast<base::MessagePumpForUI*>(pump_.get()); 555 } 556 #endif // !defined(OS_MACOSX) 557 }; 558 559 // Do not add any member variables to MessageLoopForUI! This is important b/c 560 // MessageLoopForUI is often allocated via MessageLoop(TYPE_UI). Any extra 561 // data that you need should be stored on the MessageLoop's pump_ instance. 562 COMPILE_ASSERT(sizeof(MessageLoop) == sizeof(MessageLoopForUI), 563 MessageLoopForUI_should_not_have_extra_member_variables); 564 565 //----------------------------------------------------------------------------- 566 // MessageLoopForIO extends MessageLoop with methods that are particular to a 567 // MessageLoop instantiated with TYPE_IO. 568 // 569 // This class is typically used like so: 570 // MessageLoopForIO::current()->...call some method... 571 // 572 class BASE_API MessageLoopForIO : public MessageLoop { 573 public: 574 #if defined(OS_WIN) 575 typedef base::MessagePumpForIO::IOHandler IOHandler; 576 typedef base::MessagePumpForIO::IOContext IOContext; 577 typedef base::MessagePumpForIO::IOObserver IOObserver; 578 #elif defined(OS_POSIX) 579 typedef base::MessagePumpLibevent::Watcher Watcher; 580 typedef base::MessagePumpLibevent::FileDescriptorWatcher 581 FileDescriptorWatcher; 582 typedef base::MessagePumpLibevent::IOObserver IOObserver; 583 584 enum Mode { 585 WATCH_READ = base::MessagePumpLibevent::WATCH_READ, 586 WATCH_WRITE = base::MessagePumpLibevent::WATCH_WRITE, 587 WATCH_READ_WRITE = base::MessagePumpLibevent::WATCH_READ_WRITE 588 }; 589 590 #endif 591 MessageLoopForIO()592 MessageLoopForIO() : MessageLoop(TYPE_IO) { 593 } 594 595 // Returns the MessageLoopForIO of the current thread. current()596 static MessageLoopForIO* current() { 597 MessageLoop* loop = MessageLoop::current(); 598 #ifdef ANDROID 599 DCHECK_EQ(static_cast<int>(MessageLoop::TYPE_IO), 600 static_cast<int>(loop->type())); 601 #else 602 DCHECK_EQ(MessageLoop::TYPE_IO, loop->type()); 603 #endif 604 return static_cast<MessageLoopForIO*>(loop); 605 } 606 AddIOObserver(IOObserver * io_observer)607 void AddIOObserver(IOObserver* io_observer) { 608 pump_io()->AddIOObserver(io_observer); 609 } 610 RemoveIOObserver(IOObserver * io_observer)611 void RemoveIOObserver(IOObserver* io_observer) { 612 pump_io()->RemoveIOObserver(io_observer); 613 } 614 615 #if defined(OS_WIN) 616 // Please see MessagePumpWin for definitions of these methods. 617 void RegisterIOHandler(HANDLE file_handle, IOHandler* handler); 618 bool WaitForIOCompletion(DWORD timeout, IOHandler* filter); 619 620 protected: 621 // TODO(rvargas): Make this platform independent. pump_io()622 base::MessagePumpForIO* pump_io() { 623 return static_cast<base::MessagePumpForIO*>(pump_.get()); 624 } 625 626 #elif defined(OS_POSIX) 627 // Please see MessagePumpLibevent for definition. 628 bool WatchFileDescriptor(int fd, 629 bool persistent, 630 Mode mode, 631 FileDescriptorWatcher *controller, 632 Watcher *delegate); 633 634 private: pump_io()635 base::MessagePumpLibevent* pump_io() { 636 return static_cast<base::MessagePumpLibevent*>(pump_.get()); 637 } 638 #endif // defined(OS_POSIX) 639 }; 640 641 // Do not add any member variables to MessageLoopForIO! This is important b/c 642 // MessageLoopForIO is often allocated via MessageLoop(TYPE_IO). Any extra 643 // data that you need should be stored on the MessageLoop's pump_ instance. 644 COMPILE_ASSERT(sizeof(MessageLoop) == sizeof(MessageLoopForIO), 645 MessageLoopForIO_should_not_have_extra_member_variables); 646 647 #endif // BASE_MESSAGE_LOOP_H_ 648