summaryrefslogtreecommitdiffstats
path: root/base/message_loop.h
blob: 1610d07008134e943723c14ed5aa0f4c2f143521 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
// Copyright 2008, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//    * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//    * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//    * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#ifndef BASE_MESSAGE_LOOP_H__
#define BASE_MESSAGE_LOOP_H__

#include <windows.h>
#include <deque>
#include <queue>
#include <string>
#include <vector>

#include "base/histogram.h"
#include "base/observer_list.h"
#include "base/id_map.h"
#include "base/task.h"
#include "base/timer.h"
#include "base/thread_local_storage.h"

//
// A MessageLoop is used to process events for a particular thread.
// There is at most one MessageLoop instance per thread.
// Events include Windows Message Queue messages, Tasks submitted to PostTask
// or managed by TimerManager, APC calls (as time permits), and signals sent to
// a registered set of HANDLES.
// Processing events corresponds (respectively) to dispatching Windows messages,
// running Tasks, yielding time to APCs, and calling Watchers when the
// corresponding HANDLE is signaled.

//
// NOTE: Unless otherwise specified, a MessageLoop's methods may only be called
// on the thread where the MessageLoop's Run method executes.
//
// WARNING: MessageLoop has task reentrancy protection. This means that if a
// task is being processed, a second task cannot start until the first task is
// finished. Reentrancy can happen when processing a task, and an inner message
// pump is created.  That inner pump then processes windows messages which could
// implicitly start an inner task. Inner messages pumps are created with dialogs
// (DialogBox), common dialogs (GetOpenFileName), OLE functions (DoDragDrop),
// printer functions (StartDoc) and *many* others.
// Sample workaround when inner task processing is needed:
//   bool old_state = MessageLoop::current()->NestableTasksAllowed();
//   MessageLoop::current()->SetNestableTasksAllowed(true);
//   HRESULT hr = DoDragDrop(...); // Implicitly runs a modal message loop here.
//   MessageLoop::current()->SetNestableTasksAllowed(old_state);
//   // Process hr  (the result returned by DoDragDrop().
//
// Please be **SURE** your task is reentrant and all global variables are stable
// and accessible before calling SetNestableTasksAllowed(true).
//

// Message loop has several distinct functions.  It provides message pumps,
// responds to windows message dispatches, manipulates queues of Tasks.
// The most central operation is the implementation of message pumps, along with
// several subtleties.

// MessageLoop currently implements several different message pumps.  A message
// pump is (traditionally) something that reads from an incoming queue, and then
// dispatches the work.
//
// The first message pump, RunTraditional(), is among other things a
// traditional Windows Message pump.  It contains a nearly infinite loop that
// peeks out messages, and then dispatches them.
// Intermixed with those peeks are checks on a queue of Tasks, checks for
// signaled objects, and checks to see if TimerManager has tasks to run.
// When there are no events to be serviced, this pump goes into a wait state.
// For 99.99% of all events, this first message pump handles all processing.
//
// When a task, or windows event, invokes on the stack a native dialog box or
// such, that window typically provides a bare bones (native?) message pump.
// That bare-bones message pump generally supports little more than a peek of
// the Windows message queue, followed by a dispatch of the peeked message.
// MessageLoop extends that bare-bones message pump to also service Tasks, at
// the cost of some complexity.
// The basic structure of the extension (refered to as a sub-pump) is that a
// special message,kMsgPumpATask, is repeatedly injected into the Windows
// Message queue. Each time the kMsgPumpATask message is peeked, checks are made
// for an extended set of events, including the availability of Tasks to run.
//
// After running a task, the special message kMsgPumpATask is again posted to
// the Windows Message queue, ensuring a future time slice for processing a
// future event.
//
// To prevent flooding the Windows Message queue, care is taken to be sure that
// at most one kMsgPumpATask message is EVER pending in the Winow's Message
// queue.
//
// There are a few additional complexities in this system where, when there are
// no Tasks to run, this otherwise infinite stream of messages which drives the
// sub-pump is halted.  The pump is automatically re-started when Tasks are
// queued.
//
// A second complexity is that the presence of this stream of posted tasks may
// prevent a bare-bones message pump from ever peeking a WM_PAINT or WM_TIMER.
// Such paint and timer events always give priority to a posted message, such as
// kMsgPumpATask messages.  As a result, care is taken to do some peeking in
// between the posting of each kMsgPumpATask message (i.e., after kMsgPumpATask
// is peeked, and before a replacement kMsgPumpATask is posted).
//
//
// NOTE: Although it may seem odd that messages are used to start and stop this
// flow (as opposed to signaling objects, etc.), it should be understood that
// the native message pump will *only* respond to messages.  As a result, it is
// an excellent choice.  It is also helpful that the starter messages that are
// placed in the queue when new task arrive also awakens the RunTraditional()
// loop.

//------------------------------------------------------------------------------
class MessageLoop {
 public:

  // Select a non-default strategy for serving pending requests, that is to be
  // used by all MessageLoop instances.  This is called only once before
  // constructing any instances.
  static void SetStrategy(int strategy);
  static void EnableHistogrammer(bool enable_histogrammer);

  // Used with WatchObject to asynchronously monitor the signaled state of a
  // HANDLE object.
  class Watcher {
   public:
    virtual ~Watcher() {}
    // Called from MessageLoop::Run when a signalled object is detected.
    virtual void OnObjectSignaled(HANDLE object) = 0;
  };

  // Dispatcher is used during a nested invocation of Run to dispatch events.
  // If Run is invoked with a non-NULL Dispatcher, MessageLoop does not
  // dispatch events (or invoke TranslateMessage), rather every message is
  // passed to Dispatcher's Dispatch method for dispatch. It is up to the
  // Dispatcher to dispatch, or not, the event.
  //
  // The nested loop is exited by either posting a quit, or returning false
  // from Dispatch.
  class Dispatcher {
   public:
    // Define a macro for use in the PostTask() or PostDelayedTask()
    // invocations.  The definition varies depending upon mode (DEBUG, etc.),
    // but for now we'll just define it as an int.  In other modes it may
    // encapsulate the file and line number of the source code where it is
    // expanded.

    virtual ~Dispatcher() {}
    // Dispatches the event. If true is returned processing continues as
    // normal. If false is returned, the nested loop exits immediately.
    virtual bool Dispatch(const MSG& msg) = 0;
  };

  // Have the current thread's message loop watch for a signaled object.
  // Pass a null watcher to stop watching the object.
  bool WatchObject(HANDLE, Watcher*);

  // An Observer is an object that receives global notifications from the
  // MessageLoop.
  //
  // NOTE: An Observer implementation should be extremely fast!
  //
  class Observer {
   public:
    virtual ~Observer() {}

    // This method is called before processing a message.
    // The message may be undefined in which case msg.message is 0
    virtual void WillProcessMessage(const MSG& msg) = 0;

    // This method is called when control returns from processing a UI message.
    // The message may be undefined in which case msg.message is 0
    virtual void DidProcessMessage(const MSG& msg) = 0;
  };

  // Add an Observer, which will start receiving notifications immediately.
  void AddObserver(Observer* observer);

  // Remove an Observer.  It is safe to call this method while an Observer is
  // receiving a notification callback.
  void RemoveObserver(Observer* observer);

  // Call the task's Run method asynchronously from within a message loop at
  // some point in the future.  With the PostTask variant, tasks are invoked in
  // FIFO order, inter-mixed with normal UI event processing.  With the
  // PostDelayedTask variant, tasks are called after at least approximately
  // 'delay_ms' have elapsed.
  //
  // The MessageLoop takes ownership of the Task, and deletes it after it
  // has been Run().
  //
  // NOTE: This method may be called on any thread.  The Task will be invoked
  // on the thread that executes MessageLoop::Run().

  void PostTask(const tracked_objects::Location& from_here, Task* task) {
    PostDelayedTask(from_here, task, 0);
  }

  void PostDelayedTask(const tracked_objects::Location& from_here, Task* task,
                       int delay_ms);

  // A variant on PostTask that deletes the given object.  This is useful
  // if the object needs to live until the next run of the MessageLoop (for
  // example, deleting a RenderProcessHost from within an IPC callback is not
  // good).
  //
  // NOTE: This method may be called on any thread.  The object will be deleted
  // on the thread that executes MessageLoop::Run().  If this is not the same
  // as the thread that calls PostDelayedTask(FROM_HERE, ), then T MUST inherit
  // from RefCountedThreadSafe<T>!
  template <class T>
  void DeleteSoon(const tracked_objects::Location& from_here, T* object) {
    PostTask(from_here, new DeleteTask<T>(object));
  }

  // A variant on PostTask that releases the given reference counted object
  // (by calling its Release method).  This is useful if the object needs to
  // live until the next run of the MessageLoop, or if the object needs to be
  // released on a particular thread.
  //
  // NOTE: This method may be called on any thread.  The object will be
  // released (and thus possibly deleted) on the thread that executes
  // MessageLoop::Run().  If this is not the same as the thread that calls
  // PostDelayedTask(FROM_HERE, ), then T MUST inherit from
  // RefCountedThreadSafe<T>!
  template <class T>
  void ReleaseSoon(const tracked_objects::Location& from_here, T* object) {
    PostTask(from_here, new ReleaseTask<T>(object));
  }

  // Run the message loop.
  void Run();

  // Process all pending tasks, windows messages, etc., but don't wait/sleep.
  // Return as soon as all items that can be run are taken care of.
  void RunAllPending();

  // See description of Dispatcher for how Run uses Dispatcher.
  void Run(Dispatcher* dispatcher);

  // Signals the Run method to return after it is done processing all pending
  // messages.  This method may be called from any thread, but no effort is
  // made to support concurrent calls to this method from multiple threads.
  //
  // For example, the first call to Quit may lead to the MessageLoop being
  // deleted once its Run method returns, so a second call from another thread
  // could be problematic.
  void Quit();

  // Invokes Quit on the current MessageLoop when run. Useful to schedule an
  // arbitrary MessageLoop to Quit.
  class QuitTask : public Task {
   public:
    virtual void Run() {
      MessageLoop::current()->Quit();
    }
  };

  // Wnd Proc for message_hwnd_.
  LRESULT MessageWndProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam);

  // Normally, it is not necessary to instantiate a MessageLoop.  Instead, it
  // is typical to make use of the current thread's MessageLoop instance.
  MessageLoop();
  ~MessageLoop();

  // Optional call to connect the thread name with this loop.
  void SetThreadName(const std::string& thread_name);
  std::string thread_name() const { return thread_name_; }

  // Returns the MessageLoop object for the current thread, or null if none.
  static MessageLoop* current() {
    return static_cast<MessageLoop*>(ThreadLocalStorage::Get(tls_index_));
  }

  // Returns the TimerManager object for the current thread.
  TimerManager* timer_manager() { return &timer_manager_; }

  // Give a chance to code processing additional messages to notify the
  // message loop delegates that another message has been processed.
  void WillProcessMessage(const MSG& msg);
  void DidProcessMessage(const MSG& msg);

  // Enables or disables the recursive task processing. This happens in the case
  // of recursive message loops. Some unwanted message loop may occurs when
  // using common controls or printer functions. By default, recursive task
  // processing is disabled.
  //
  // The specific case where tasks get queued is:
  // - The thread is running a message loop.
  // - It receives a task #1 and execute it.
  // - The task #1 implicitly start a message loop, like a MessageBox in the
  //   unit test. This can also be StartDoc or GetSaveFileName.
  // - The thread receives a task #2 before or while in this second message
  //   loop.
  // - With NestableTasksAllowed set to true, the task #2 will run right away.
  //   Otherwise, it will get executed right after task #1 completes at "thread
  //   message loop level".
  void SetNestableTasksAllowed(bool allowed);
  bool NestableTasksAllowed() const;

  // Enables or disables the restoration during an exception of the unhandled
  // exception filter that was active when Run() was called. This can happen
  // if some third party code call SetUnhandledExceptionFilter() and never
  // restores the previous filter.
  void set_exception_restoration(bool restore) {
    exception_restoration_ = restore;
  }

  // Public entry point for TimerManager to request the Run() of a task.  If we
  // created the task during an PostTask(FROM_HERE, ), then we will also perform
  // destructions, and we'll have the option of queueing the task.  If we didn't
  // create the timer, then we will Run it immediately.
  bool RunTimerTask(Timer* timer);

  // Since some Timer's are owned by MessageLoop, the TimerManager (when it is
  // being destructed) passses us the timers to discard (without doing a Run()).
  void DiscardTimer(Timer* timer);

  // Applications can call this to encourage us to process all pending WM_PAINT
  // messages.
  // This method will process all paint messages the Windows Message queue can
  // provide, up to some fixed number (to avoid any infinite loops).
  void PumpOutPendingPaintMessages();

  //----------------------------------------------------------------------------
 private:
  struct ScopedStateSave {
    explicit ScopedStateSave(MessageLoop* loop)
        : loop_(loop),
          dispatcher_(loop->dispatcher_),
          quit_now_(loop->quit_now_),
          quit_received_(loop->quit_received_),
          run_depth_(loop->run_depth_) {
      loop->quit_now_ = loop->quit_received_ = false;
      ++loop->run_depth_;
    }

    ~ScopedStateSave() {
      loop_->run_depth_ = run_depth_;
      loop_->quit_received_ = quit_received_;
      loop_->quit_now_ = quit_now_;
      loop_->dispatcher_ = dispatcher_;
    }

   private:
    MessageLoop* loop_;
    Dispatcher* dispatcher_;
    bool quit_now_;
    bool quit_received_;
    int run_depth_;
  };  // struct ScopedStateSave

  // A prioritized queue with interface that mostly matches std::queue<>.
  // For debugging/performance testing, you can swap in std::queue<Task*>.
  class PrioritizedTaskQueue {
   public:
    PrioritizedTaskQueue() : next_sequence_number_(0) {}
    ~PrioritizedTaskQueue() {}
    void pop()    { queue_.pop(); }
    bool empty()  { return queue_.empty(); }
    size_t size() { return queue_.size(); }
    Task* front() { return queue_.top().task(); }
    void push(Task * task);

   private:
    class PrioritizedTask {
     public:
      PrioritizedTask(Task* task, int sequence_number)
        : task_(task),
          sequence_number_(sequence_number),
          priority_(task->priority()) {}
      Task* task() { return task_; }
      bool operator < (PrioritizedTask const & right) const ;

     private:
      Task* task_;
      // Number to ensure (default) FIFO ordering in a PriorityQueue.
      int sequence_number_;
      // Priority of task when pushed.
      int priority_;
    };  // class PrioritizedTask

    std::priority_queue<PrioritizedTask> queue_;
    // Default sequence number used when push'ing (monotonically decreasing).
    int next_sequence_number_;
    DISALLOW_EVIL_CONSTRUCTORS(PrioritizedTaskQueue);
  };

  // Implementation of a TaskQueue as a null terminated list, with end pointers.
  class TaskQueue {
   public:
    TaskQueue() : first_(NULL), last_(NULL) {}
    void Push(Task* task);
    Task* Pop();  // Extract the next Task from the queue, and return it.
    bool Empty() const { return !first_; }
   private:
    Task* first_;
    Task* last_;
  };

  // Implementation of a Task queue that automatically switches into a priority
  // queue if it observes any non-zero priorities in tasks.
  class OptionallyPrioritizedTaskQueue {
   public:
    OptionallyPrioritizedTaskQueue() : use_priority_queue_(false) {}
    void Push(Task* task);
    Task* Pop();  // Extract next Task from queue, and return it.
    bool Empty();
    bool use_priority_queue() const { return use_priority_queue_; }

   private:
    bool use_priority_queue_;
    PrioritizedTaskQueue prioritized_queue_;
    TaskQueue queue_;
    DISALLOW_EVIL_CONSTRUCTORS(OptionallyPrioritizedTaskQueue);
  };

  void InitMessageWnd();


  // A function to encapsulate all the exception handling capability in the
  // stacks around the running of a main message loop.
  // It will run the message loop in a SEH try block or not depending on the
  // set_SEH_restoration() flag.
  void RunHandler(Dispatcher* dispatcher, bool non_blocking);

  // A surrounding stack frame around the running of the message loop that
  // supports all saving and restoring of state, as is needed for any/all (ugly)
  // recursive calls.
  void RunInternal(Dispatcher* dispatcher, bool non_blocking);

  // An extended message loop (message pump) that loops mostly forever, and
  // processes task, signals, timers, etc.
  // If non-blocking is set, it will return rather than wait for new things to
  // arrive for processing.
  void RunTraditional(bool non_blocking);

  //----------------------------------------------------------------------------
  // A list of method wrappers with identical calling signatures (no arguments)
  // for use in the main message loop.  Method pointers to these methods may be
  // called round-robin from the main message loop, on any desired schedule.

  bool ProcessNextDeferredTask();
  bool ProcessNextDelayedNonNestableTask();
  bool ProcessNextObject();
  bool ProcessSomeTimers();

  //----------------------------------------------------------------------------
  // Process some pending messages.
  // Returns true if a message was processed.
  bool ProcessNextWindowsMessage();

  // Wait until either an object is signaled, a message is available, a timer
  // needs attention, or our incoming_queue_ has gotten a task.
  // Handle (without returning) any APCs (only IO thread currently has APCs.)
  void WaitForWork();

  // Helper function for processing window messages. This includes handling
  // WM_QUIT, message translation and dispatch, etc.
  //
  // If dispatcher_ is non-NULL this method does NOT dispatch the event, instead
  // it invokes Dispatch on the dispatcher_.
  bool ProcessMessageHelper(const MSG& msg);

  // When we encounter a kMsgPumpATask, the following helper can be called to
  // peek and process a replacement message, such as a WM_PAINT or WM_TIMER.
  // The goal is to make the kMsgPumpATask as non-intrusive as possible, even
  // though a continuous stream of such messages are posted.  This method
  // carefully peeks a message while there is no chance for a kMsgPumpATask to
  // be pending, then releases the lock (allowing a replacement kMsgPumpATask to
  // possibly be posted), and finally dispatches that peeked replacement.
  // Note that the re-post of kMsgPumpATask may be asynchronous to this thread!!
  bool ProcessPumpReplacementMessage();

  // Signals a watcher if a wait falls within the range of objects we're
  // waiting on.  object_index is the offset in objects_ that was signaled.
  // Returns true if an object was signaled.
  bool SignalWatcher(size_t object_index);

  // Run a work_queue_ task or new_task, and delete it (if it was processed by
  // PostTask). If there are queued tasks, the oldest one is executed and
  // new_task is queued. new_task is optional and can be NULL. In this NULL
  // case, the method will run one pending task (if any exist). Returns true if
  // it executes a task.
  // Queued tasks accumulate only when there is a nonreentrant task currently
  // processing, in which case the new_task is appended to the list
  // work_queue_.  Such re-entrancy generally happens when an unrequested
  // message pump (typical of a native dialog) is executing in the context of a
  // task.
  bool QueueOrRunTask(Task* new_task);

  // Runs the specified task and deletes it.
  void RunTask(Task* task);

  // Make state adjustments just before and after running tasks so that we can
  // continue to work if a native message loop is employed during a task.
  void BeforeTaskRunSetup();
  void AfterTaskRunRestore();

  // When processing messages in our MessageWndProc(), we are sometimes called
  // by a native message pump (i.e., We are not called out of our Run() pump).
  // In those cases, we need to process tasks during the Windows Message
  // callback.  This method processes a task, and also posts a new kMsgPumpATask
  // messages to the Windows Msg Queue so that we are called back later (to
  // process additional tasks).
  void PumpATaskDuringWndProc();

  // Load tasks from the incoming_queue_ into work_queue_ if the latter is
  // empty.  The former requires a lock to access, while the latter is directly
  // accessible on this thread.
  void ReloadWorkQueue();

  // Delete tasks that haven't run yet without running them.  Used in the
  // destructor to make sure all the task's destructors get called.
  void DeletePendingTasks();

  // Make sure a kPumpATask message is in flight, which starts/continues the
  // sub-pump.
  void EnsurePumpATaskWasPosted();

  // Do a PostMessage(), and crash if we can't eventually do the post.
  void EnsureMessageGetsPosted(int message) const;

  // Post a task to our incomming queue.
  void MessageLoop::PostTaskInternal(Task* task);

  // Start recording histogram info about events and action IF it was enabled
  // and IF the statistics recorder can accept a registration of our histogram.
  void StartHistogrammer();

  // Add occurence of event to our histogram, so that we can see what is being
  // done in a specific MessageLoop instance (i.e., specific thread).
  // If message_histogram_ is NULL, this is a no-op.
  void HistogramEvent(int event);

  static TLSSlot tls_index_;
  static int strategy_selector_;
  static const LinearHistogram::DescriptionPair event_descriptions_[];
  static bool enable_histogrammer_;

  TimerManager timer_manager_;

  // A list of tasks that need to be processed by this instance.  Note that this
  // queue is only accessed (push/pop) by our current thread.
  // As an optimization, when we don't need to use the prioritization of
  // work_queue_, we use a null terminated list (TaskQueue) as our
  // implementation of the queue. This saves on memory (list uses pointers
  // internal to Task) and probably runs faster than the priority queue when
  // there was no real prioritization.
  OptionallyPrioritizedTaskQueue work_queue_;

  // A vector of objects (and corresponding watchers) that are routinely
  // serviced by this message loop's pump.
  std::vector<HANDLE> objects_;
  std::vector<Watcher*> watchers_;

  ObserverList<Observer> observers_;
  HWND message_hwnd_;
  IDMap<Task> timed_tasks_;
  // A recursion block that prevents accidentally running additonal tasks when
  // insider a (accidentally induced?) nested message pump.
  bool nestable_tasks_allowed_;

  bool exception_restoration_;

  Dispatcher* dispatcher_;
  bool quit_received_;
  bool quit_now_;

  std::string thread_name_;
  // A profiling histogram showing the counts of various messages and events.
  scoped_ptr<LinearHistogram> message_histogram_;

  // A null terminated list which creates an incoming_queue of tasks that are
  // aquired under a mutex for processing on this instance's thread. These tasks
  // have not yet been sorted out into items for our work_queue_ vs items that
  // will be handled by the TimerManager.
  TaskQueue incoming_queue_;
  // Protect access to incoming_queue_.
  Lock incoming_queue_lock_;

  // A null terminated list of non-nestable tasks that we had to delay because
  // when it came time to execute them we were in a nested message loop.  They
  // will execute once we're out of nested message loops.
  TaskQueue delayed_non_nestable_queue_;

  // Indicate if there is a kMsgPumpATask message pending in the Windows Message
  // queue.  There is at most one such message, and it can drive execution of
  // tasks when a native message pump is running.
  bool task_pump_message_pending_;
  // Protect access to task_pump_message_pending_.
  Lock task_pump_message_lock_;

  // Used to count how many Run() invocations are on the stack.
  int run_depth_;

  DISALLOW_EVIL_CONSTRUCTORS(MessageLoop);
};

#endif  // BASE_MESSAGE_LOOP_H__