接下来分析 MessagePumpForUI
上一篇分析MessagePumpWin,可以参考chromium之message_pump_win之一
根据对MessagePumpWin的分析,MessagePumpForUI肯定要继承MessagePumpWin,且实现三个接口
  // MessagePump methods:
virtual void ScheduleWork();
virtual void ScheduleDelayedWork(const Time& delayed_work_time); virtual void DoRunLoop();

先看看介绍,有点长

//-----------------------------------------------------------------------------
// MessagePumpForUI extends MessagePumpWin with methods that are particular to a
// MessageLoop instantiated with TYPE_UI.
//
// MessagePumpForUI implements a "traditional" Windows message pump. It contains
// a nearly infinite loop that peeks out messages, and then dispatches them.
// Intermixed with those peeks are callouts to DoWork for pending tasks, and
// DoDelayedWork for pending timers. When there are no events to be serviced,
// this pump goes into a wait state. In most cases, this message pump handles
// all processing.
//
// However, 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, kMsgHaveWork, is repeatedly injected into the Windows
// Message queue. Each time the kMsgHaveWork 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 kMsgHaveWork 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 kMsgHaveWork message is EVER pending in the
// Window'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
// kMsgHaveWork messages. As a result, care is taken to do some peeking in
// between the posting of each kMsgHaveWork message (i.e., after kMsgHaveWork
// is peeked, and before a replacement kMsgHaveWork 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 DoRunLoop.
//

看不下去了,看代码把,

总共两个步骤:

1) have_work_ = 1;

2) 发送一个kMsgHaveWork消息,通知MessagePump 工作

void MessagePumpForUI::ScheduleWork() {
if (InterlockedExchange(&have_work_, ))
return; // Someone else continued the pumping. // Make sure the MessagePump does some work for us.
PostMessage(message_hwnd_, kMsgHaveWork, reinterpret_cast<WPARAM>(this), );
}

接下来是ScheduleDelayedWork

SetTimer, https://msdn.microsoft.com/en-us/library/windows/desktop/ms644906(v=vs.85).aspx

SetTimer的精度是10ms,通过SetTimer来设置延时任务,SetTimer的第四个参数是NULL,定时到的时候,

系统会发一个WM_TIMER消息到消息队列

void MessagePumpForUI::ScheduleDelayedWork(const Time& delayed_work_time) {
//
// We would *like* to provide high resolution timers. Windows timers using
// SetTimer() have a 10ms granularity. We have to use WM_TIMER as a wakeup
// mechanism because the application can enter modal windows loops where it
// is not running our MessageLoop; the only way to have our timers fire in
// these cases is to post messages there.
//
// To provide sub-10ms timers, we process timers directly from our run loop.
// For the common case, timers will be processed there as the run loop does
// its normal work. However, we *also* set the system timer so that WM_TIMER
// events fire. This mops up the case of timers not being able to work in
// modal message loops. It is possible for the SetTimer to pop and have no
// pending timers, because they could have already been processed by the
// run loop itself.
//
// We use a single SetTimer corresponding to the timer that will expire
// soonest. As new timers are created and destroyed, we update SetTimer.
// Getting a spurrious SetTimer event firing is benign, as we'll just be
// processing an empty timer queue.
//
delayed_work_time_ = delayed_work_time; int delay_msec = GetCurrentDelay();
DCHECK(delay_msec >= );
if (delay_msec < USER_TIMER_MINIMUM)
delay_msec = USER_TIMER_MINIMUM; // Create a WM_TIMER event that will wake us up to check for any pending
// timers (in case we are running within a nested, external sub-pump).
SetTimer(message_hwnd_, reinterpret_cast<UINT_PTR>(this), delay_msec, NULL);
}

最后一个需要实现的函数DoMainLoop

void MessagePumpForUI::DoRunLoop() {
// IF this was just a simple PeekMessage() loop (servicing all possible work
// queues), then Windows would try to achieve the following order according
// to MSDN documentation about PeekMessage with no filter):
// * Sent messages
// * Posted messages
// * Sent messages (again)
// * WM_PAINT messages
// * WM_TIMER messages
//
// Summary: none of the above classes is starved, and sent messages has twice
// the chance of being processed (i.e., reduced service time). for (;;) {
// If we do any work, we may create more messages etc., and more work may
// possibly be waiting in another task group. When we (for example)
// ProcessNextWindowsMessage(), there is a good chance there are still more
// messages waiting. On the other hand, when any of these methods return
// having done no work, then it is pretty unlikely that calling them again
// quickly will find any work to do. Finally, if they all say they had no
// work, then it is a good time to consider sleeping (waiting) for more
// work. bool more_work_is_plausible = ProcessNextWindowsMessage();
if (state_->should_quit)
break; more_work_is_plausible |= state_->delegate->DoWork();
if (state_->should_quit)
break; more_work_is_plausible |=
state_->delegate->DoDelayedWork(&delayed_work_time_);
// If we did not process any delayed work, then we can assume that our
// existing WM_TIMER if any will fire when delayed work should run. We
// don't want to disturb that timer if it is already in flight. However,
// if we did do all remaining delayed work, then lets kill the WM_TIMER.
if (more_work_is_plausible && delayed_work_time_.is_null())
KillTimer(message_hwnd_, reinterpret_cast<UINT_PTR>(this));
if (state_->should_quit)
break; if (more_work_is_plausible)
continue; more_work_is_plausible = state_->delegate->DoIdleWork();
if (state_->should_quit)
break; if (more_work_is_plausible)
continue; WaitForWork(); // Wait (sleep) until we have work to do again.
}
}
05-11 20:37