Commit b61fcc11 authored by Francois Doray's avatar Francois Doray Committed by Commit Bot

[base] Remove MessagePump::DoWork/DoDelayedWork.

All MessagePumps now use DoSomeWork.

In a future, CL:
- DoSomeWork will be renamed to DoWork
- Complexity of ThreadControllerWithMessagePump and SequenceManager
  can be reduced. For example, WorkDeduplicator can be simplified.
These changes will be done separately to minimize the size of this CL.

Bug: 885371
Change-Id: I3c557e19bf8da6dc21c655202d3572a71a23c0a1
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2070716
Commit-Queue: François Doray <fdoray@chromium.org>
Reviewed-by: default avatarGabriel Charette <gab@chromium.org>
Cr-Commit-Position: refs/heads/master@{#753371}
parent 2c73fbed
...@@ -39,8 +39,7 @@ class BASE_EXPORT MessagePump { ...@@ -39,8 +39,7 @@ class BASE_EXPORT MessagePump {
// Called before a unit of work internal to the message pump is executed. // Called before a unit of work internal to the message pump is executed.
// This allows reports about individual units of work to be produced. // This allows reports about individual units of work to be produced.
// The unit of work ends when BeforeDoInternalWork() is called again, or // The unit of work ends when BeforeDoInternalWork() is called again, or
// when BeforeWait(), DoSomeWork(), DoWork(), DoDelayedWork() or // when BeforeWait(), DoSomeWork(), or DoIdleWork() is called.
// DoIdleWork() is called.
// TODO(crbug.com/851163): Place calls for all platforms. // TODO(crbug.com/851163): Place calls for all platforms.
virtual void BeforeDoInternalWork() = 0; virtual void BeforeDoInternalWork() = 0;
...@@ -72,39 +71,16 @@ class BASE_EXPORT MessagePump { ...@@ -72,39 +71,16 @@ class BASE_EXPORT MessagePump {
TimeTicks recent_now; TimeTicks recent_now;
}; };
// The latest model of MessagePumps will invoke this instead of // Executes an immediate task or a ripe delayed task. Returns information
// DoWork()/DoDelayedWork(). Executes an immediate task or a ripe delayed // about when DoSomeWork() should be called again. If the returned
// task. Returns a struct which indicates |delayed_run_time|. DoSomeWork() // NextWorkInfo is_immediate(), DoSomeWork() must be invoked again shortly.
// will be invoked again shortly if is_immediate(); it will be invoked after // Else, DoSomeWork() must be invoked at |NextWorkInfo::delayed_run_time| or
// |delayed_run_time| (or ScheduleWork()) if there isn't immediate work and // when ScheduleWork() is invoked, whichever comes first. Redundant/spurious
// |!delayed_run_time.is_max()|; and it will not be invoked again until // invocations of DoSomeWork() outside of those requirements are tolerated.
// ScheduleWork() otherwise. Redundant/spurious invocations outside of those // DoIdleWork() will not be called so long as this returns a NextWorkInfo
// guarantees are not impossible however. DoIdleWork() will not be called so // which is_immediate().
// long as this returns a NextWorkInfo which is_immediate(). See design doc
// for details :
// https://docs.google.com/document/d/1no1JMli6F1r8gTF9KDIOvoWkUUZcXDktPf4A1IXYc3M/edit#
virtual NextWorkInfo DoSomeWork() = 0; virtual NextWorkInfo DoSomeWork() = 0;
// Called from within Run in response to ScheduleWork or when the message
// pump would otherwise call DoDelayedWork. Returns true to indicate that
// work was done. DoDelayedWork will still be called if DoWork returns
// true, but DoIdleWork will not.
// Used in conjunction with DoDelayedWork() by old MessagePumps.
// TODO(gab): Migrate such pumps to DoSomeWork().
virtual bool DoWork() = 0;
// Called from within Run in response to ScheduleDelayedWork or when the
// message pump would otherwise sleep waiting for more work. Returns true
// to indicate that delayed work was done. DoIdleWork will not be called
// if DoDelayedWork returns true. Upon return |next_delayed_work_time|
// indicates the time when DoDelayedWork should be called again. If
// |next_delayed_work_time| is null (per Time::is_null), then the queue of
// future delayed work (timer events) is currently empty, and no additional
// calls to this function need to be scheduled.
// Used in conjunction with DoWork() by old MessagePumps.
// TODO(gab): Migrate such pumps to DoSomeWork().
virtual bool DoDelayedWork(TimeTicks* next_delayed_work_time) = 0;
// Called from within Run just before the message pump goes to sleep. // Called from within Run just before the message pump goes to sleep.
// Returns true to indicate that idle work was done. Returning false means // Returns true to indicate that idle work was done. Returning false means
// the pump will now wait. // the pump will now wait.
...@@ -118,63 +94,64 @@ class BASE_EXPORT MessagePump { ...@@ -118,63 +94,64 @@ class BASE_EXPORT MessagePump {
// //
// Within the method, the message pump is responsible for processing native // Within the method, the message pump is responsible for processing native
// messages as well as for giving cycles to the delegate periodically. The // messages as well as for giving cycles to the delegate periodically. The
// message pump should take care to mix delegate callbacks with native // message pump should take care to mix delegate callbacks with native message
// message processing so neither type of event starves the other of cycles. // processing so neither type of event starves the other of cycles. Each call
// Each call to a delegate function or DoInternalWork() is considered // to a delegate function or DoInternalWork() is considered the beginning of a
// the beginning of a new "unit of work". // new "unit of work".
// //
// The anatomy of a typical run loop: // The anatomy of a typical run loop:
// //
// for (;;) { // for (;;) {
// bool did_work = DoInternalWork(); // bool did_internal_work = DoInternalWork();
// if (should_quit_) // if (should_quit_)
// break; // break;
// //
// did_work |= delegate_->DoWork(); // Delegate::NextWorkInfo next_work_info = delegate->DoSomeWork();
// if (should_quit_) // if (should_quit_)
// break; // break;
// //
// TimeTicks next_time; // if (did_internal_work || next_work_info.is_immediate())
// did_work |= delegate_->DoDelayedWork(&next_time);
// if (should_quit_)
// break;
//
// if (did_work)
// continue; // continue;
// //
// did_work = delegate_->DoIdleWork(); // bool did_idle_work = delegate_->DoIdleWork();
// if (should_quit_) // if (should_quit_)
// break; // break;
// //
// if (did_work) // if (did_idle_work)
// continue; // continue;
// //
// WaitForWork(); // WaitForWork();
// } // }
// //
// Here, DoInternalWork is some private method of the message pump that is // Here, DoInternalWork is some private method of the message pump that is
// responsible for dispatching the next UI message or notifying the next IO // responsible for dispatching the next UI message or notifying the next IO
// completion (for example). WaitForWork is a private method that simply // completion (for example). WaitForWork is a private method that simply
// blocks until there is more work of any type to do. // blocks until there is more work of any type to do.
// //
// Notice that the run loop cycles between calling DoInternalWork, DoWork, // Notice that the run loop cycles between calling DoInternalWork and
// and DoDelayedWork methods. This helps ensure that none of these work // DoSomeWork methods. This helps ensure that none of these work queues starve
// queues starve the others. This is important for message pumps that are // the others. This is important for message pumps that are used to drive
// used to drive animations, for example. // animations, for example.
// //
// Notice also that after each callout to foreign code, the run loop checks // Notice also that after each callout to foreign code, the run loop checks to
// to see if it should quit. The Quit method is responsible for setting this // see if it should quit. The Quit method is responsible for setting this
// flag. No further work is done once the quit flag is set. // flag. No further work is done once the quit flag is set.
// //
// NOTE: Care must be taken to handle Run being called again from within any // NOTE 1: Run may be called reentrantly from any of the callouts to foreign
// of the callouts to foreign code. Native message pumps may also need to // code (internal work, DoSomeWork, DoIdleWork). As a result, DoSomeWork and
// deal with other native message pumps being run outside their control // DoIdleWork must be reentrant.
// (e.g., the MessageBox API on Windows pumps UI messages!). To be specific,
// the callouts (DoWork and DoDelayedWork) MUST still be provided even in
// nested sub-loops that are "seemingly" outside the control of this message
// pump. DoWork in particular must never be starved for time slices unless
// it returns false (meaning it has run out of things to do).
// //
// NOTE 2: Run implementations must arrange for DoSomeWork to be invoked as
// expected if a callout to foreign code enters a message pump outside their
// control. For example, the MessageBox API on Windows pumps UI messages. If
// the MessageBox API is called (indirectly) from within Run, it is expected
// that DoSomeWork will be invoked from within that call in response to
// ScheduleWork or as requested by the last NextWorkInfo returned by
// DoSomeWork. The MessagePump::Delegate may then elect to do nested work or
// not depending on its policy in that context. Regardless of that decision
// (and return value of the nested DoSomeWork() call), DoSomeWork() will be
// invoked again when the nested loop unwinds.
virtual void Run(Delegate* delegate) = 0; virtual void Run(Delegate* delegate) = 0;
// Quit immediately from the most recently entered run loop. This method may // Quit immediately from the most recently entered run loop. This method may
...@@ -184,23 +161,23 @@ class BASE_EXPORT MessagePump { ...@@ -184,23 +161,23 @@ class BASE_EXPORT MessagePump {
// Schedule a DoSomeWork callback to happen reasonably soon. Does nothing if // Schedule a DoSomeWork callback to happen reasonably soon. Does nothing if
// a DoSomeWork callback is already scheduled. Once this call is made, // a DoSomeWork callback is already scheduled. Once this call is made,
// DoSomeWork is guaranteed to be called repeatedly at least until it returns // DoSomeWork is guaranteed to be called repeatedly at least until it returns
// a non-immediate NextWorkInfo (or, if this pump wasn't yet migrated, // a non-immediate NextWorkInfo. This call can be expensive and callers should
// DoWork() will be called until it returns false). This call can be expensive // attempt not to invoke it again before a non-immediate NextWorkInfo was
// and callers should attempt not to invoke it again before a non-immediate // returned from DoSomeWork(). Thread-safe (and callers should avoid holding a
// NextWorkInfo was returned from DoSomeWork(). Thread-safe (and callers // Lock at all cost while making this call as some platforms' priority
// should avoid holding a Lock at all cost while making this call as some // boosting features have been observed to cause the caller to get descheduled
// platforms' priority boosting features have been observed to cause the // : https://crbug.com/890978).
// caller to get descheduled : https://crbug.com/890978).
virtual void ScheduleWork() = 0; virtual void ScheduleWork() = 0;
// Schedule a DoDelayedWork callback to happen at the specified time, // Schedule a DoSomeWork callback to happen at the specified time, cancelling
// cancelling any pending DoDelayedWork callback. This method may only be used // any pending callback scheduled by this method. This method may only be used
// on the thread that called Run. // on the thread that called Run.
// //
// This is mostly a no-op in the DoSomeWork() world but must still be invoked // It isn't necessary to call this during normal execution, as the pump wakes
// when the new |delayed_work_time| is sooner than the last one returned from // up as requested by the return value of DoSomeWork().
// DoSomeWork(). TODO(gab): Clarify this API once all pumps have been // TODO(crbug.com/885371): Determine if this must be called to ensure that
// migrated. // delayed tasks run when a message pump outside the control of Run is
// entered.
virtual void ScheduleDelayedWork(const TimeTicks& delayed_work_time) = 0; virtual void ScheduleDelayedWork(const TimeTicks& delayed_work_time) = 0;
// Sets the timer slack to the specified value. // Sets the timer slack to the specified value.
......
...@@ -32,12 +32,6 @@ namespace base { ...@@ -32,12 +32,6 @@ namespace base {
namespace { namespace {
bool PumpTypeUsesDoSomeWork(MessagePumpType type) {
// TODO(https://crbug.com/885371): All MessagePumps use DoSomeWork(). As a
// result, tests should be simplified.
return true;
}
class MockMessagePumpDelegate : public MessagePump::Delegate { class MockMessagePumpDelegate : public MessagePump::Delegate {
public: public:
MockMessagePumpDelegate() = default; MockMessagePumpDelegate() = default;
...@@ -46,8 +40,6 @@ class MockMessagePumpDelegate : public MessagePump::Delegate { ...@@ -46,8 +40,6 @@ class MockMessagePumpDelegate : public MessagePump::Delegate {
void BeforeDoInternalWork() override {} void BeforeDoInternalWork() override {}
void BeforeWait() override {} void BeforeWait() override {}
MOCK_METHOD0(DoSomeWork, MessagePump::Delegate::NextWorkInfo()); MOCK_METHOD0(DoSomeWork, MessagePump::Delegate::NextWorkInfo());
MOCK_METHOD0(DoWork, bool());
MOCK_METHOD1(DoDelayedWork, bool(TimeTicks*));
MOCK_METHOD0(DoIdleWork, bool()); MOCK_METHOD0(DoIdleWork, bool());
private: private:
...@@ -59,8 +51,6 @@ class MessagePumpTest : public ::testing::TestWithParam<MessagePumpType> { ...@@ -59,8 +51,6 @@ class MessagePumpTest : public ::testing::TestWithParam<MessagePumpType> {
MessagePumpTest() : message_pump_(MessagePump::Create(GetParam())) {} MessagePumpTest() : message_pump_(MessagePump::Create(GetParam())) {}
protected: protected:
const bool pump_uses_do_some_work_ = PumpTypeUsesDoSomeWork(GetParam());
std::unique_ptr<MessagePump> message_pump_; std::unique_ptr<MessagePump> message_pump_;
}; };
...@@ -69,19 +59,11 @@ class MessagePumpTest : public ::testing::TestWithParam<MessagePumpType> { ...@@ -69,19 +59,11 @@ class MessagePumpTest : public ::testing::TestWithParam<MessagePumpType> {
TEST_P(MessagePumpTest, QuitStopsWork) { TEST_P(MessagePumpTest, QuitStopsWork) {
testing::StrictMock<MockMessagePumpDelegate> delegate; testing::StrictMock<MockMessagePumpDelegate> delegate;
// Not expecting any calls to DoDelayedWork or DoIdleWork after quitting. // Not expecting any calls to DoIdleWork after quitting.
if (pump_uses_do_some_work_) {
EXPECT_CALL(delegate, DoSomeWork).WillOnce(Invoke([this] { EXPECT_CALL(delegate, DoSomeWork).WillOnce(Invoke([this] {
message_pump_->Quit(); message_pump_->Quit();
return MessagePump::Delegate::NextWorkInfo{TimeTicks::Max()}; return MessagePump::Delegate::NextWorkInfo{TimeTicks::Max()};
})); }));
} else {
EXPECT_CALL(delegate, DoWork).WillOnce(Invoke([this] {
message_pump_->Quit();
return false;
}));
}
EXPECT_CALL(delegate, DoDelayedWork(_)).Times(0);
EXPECT_CALL(delegate, DoIdleWork()).Times(0); EXPECT_CALL(delegate, DoIdleWork()).Times(0);
message_pump_->ScheduleWork(); message_pump_->ScheduleWork();
...@@ -93,11 +75,10 @@ TEST_P(MessagePumpTest, QuitStopsWorkWithNestedRunLoop) { ...@@ -93,11 +75,10 @@ TEST_P(MessagePumpTest, QuitStopsWorkWithNestedRunLoop) {
testing::StrictMock<MockMessagePumpDelegate> delegate; testing::StrictMock<MockMessagePumpDelegate> delegate;
testing::StrictMock<MockMessagePumpDelegate> nested_delegate; testing::StrictMock<MockMessagePumpDelegate> nested_delegate;
// We first schedule a call to DoWork, which runs a nested run loop. After the // We first schedule a call to DoSomeWork, which runs a nested run loop. After
// nested loop exits, we schedule another DoWork which quits the outer // the nested loop exits, we schedule another DoSomeWork which quits the outer
// (original) run loop. The test verifies that there are no extra calls to // (original) run loop. The test verifies that there are no extra calls to
// DoWork after the outer loop quits. // DoSomeWork after the outer loop quits.
if (pump_uses_do_some_work_) {
EXPECT_CALL(delegate, DoSomeWork).WillOnce(Invoke([&] { EXPECT_CALL(delegate, DoSomeWork).WillOnce(Invoke([&] {
message_pump_->ScheduleWork(); message_pump_->ScheduleWork();
message_pump_->Run(&nested_delegate); message_pump_->Run(&nested_delegate);
...@@ -109,35 +90,13 @@ TEST_P(MessagePumpTest, QuitStopsWorkWithNestedRunLoop) { ...@@ -109,35 +90,13 @@ TEST_P(MessagePumpTest, QuitStopsWorkWithNestedRunLoop) {
message_pump_->Quit(); message_pump_->Quit();
return MessagePump::Delegate::NextWorkInfo{TimeTicks::Max()}; return MessagePump::Delegate::NextWorkInfo{TimeTicks::Max()};
})); }));
} else {
EXPECT_CALL(delegate, DoWork).WillOnce(Invoke([&] {
message_pump_->ScheduleWork();
message_pump_->Run(&nested_delegate);
message_pump_->ScheduleWork();
return false;
}));
EXPECT_CALL(nested_delegate, DoWork).WillOnce(Invoke([&] {
// Quit the nested run loop.
message_pump_->Quit();
return false;
}));
EXPECT_CALL(delegate, DoDelayedWork(_)).WillOnce(Return(false));
}
// The outer pump may or may not trigger idle work at this point. // The outer pump may or may not trigger idle work at this point.
EXPECT_CALL(delegate, DoIdleWork()).Times(AnyNumber()); EXPECT_CALL(delegate, DoIdleWork()).Times(AnyNumber());
if (pump_uses_do_some_work_) {
EXPECT_CALL(delegate, DoSomeWork).WillOnce(Invoke([this] { EXPECT_CALL(delegate, DoSomeWork).WillOnce(Invoke([this] {
message_pump_->Quit(); message_pump_->Quit();
return MessagePump::Delegate::NextWorkInfo{TimeTicks::Max()}; return MessagePump::Delegate::NextWorkInfo{TimeTicks::Max()};
})); }));
} else {
EXPECT_CALL(delegate, DoWork).WillOnce(Invoke([this] {
message_pump_->Quit();
return false;
}));
}
message_pump_->ScheduleWork(); message_pump_->ScheduleWork();
message_pump_->Run(&delegate); message_pump_->Run(&delegate);
...@@ -182,25 +141,6 @@ class TimerSlackTestDelegate : public MessagePump::Delegate { ...@@ -182,25 +141,6 @@ class TimerSlackTestDelegate : public MessagePump::Delegate {
return MessagePump::Delegate::NextWorkInfo{TimeTicks::Max()}; return MessagePump::Delegate::NextWorkInfo{TimeTicks::Max()};
} }
bool DoWork() override {
switch (action_.load()) {
case NONE:
break;
case SCHEDULE_DELAYED_WORK:
// After being woken up by the other thread, we schedule work after a
// short delay. If the pump refreshes its timer correctly, it will wake
// up shortly, finishing the test.
action_.store(QUIT);
message_pump_->ScheduleDelayedWork(TimeTicks::Now() +
TimeDelta::FromMilliseconds(50));
break;
case QUIT:
message_pump_->Quit();
break;
}
return false;
}
bool DoDelayedWork(base::TimeTicks*) override { return false; }
bool DoIdleWork() override { return false; } bool DoIdleWork() override { return false; }
void WakeUpFromOtherThread() { void WakeUpFromOtherThread() {
...@@ -253,17 +193,10 @@ TEST_P(MessagePumpTest, RunWithoutScheduleWorkInvokesDoWork) { ...@@ -253,17 +193,10 @@ TEST_P(MessagePumpTest, RunWithoutScheduleWorkInvokesDoWork) {
#if defined(OS_IOS) #if defined(OS_IOS)
EXPECT_CALL(delegate, DoIdleWork).Times(AnyNumber()); EXPECT_CALL(delegate, DoIdleWork).Times(AnyNumber());
#endif #endif
if (pump_uses_do_some_work_) {
EXPECT_CALL(delegate, DoSomeWork).WillOnce(Invoke([this] { EXPECT_CALL(delegate, DoSomeWork).WillOnce(Invoke([this] {
message_pump_->Quit(); message_pump_->Quit();
return MessagePump::Delegate::NextWorkInfo{TimeTicks::Max()}; return MessagePump::Delegate::NextWorkInfo{TimeTicks::Max()};
})); }));
} else {
EXPECT_CALL(delegate, DoWork).WillOnce(Invoke([this] {
message_pump_->Quit();
return false;
}));
}
message_pump_->Run(&delegate); message_pump_->Run(&delegate);
} }
...@@ -272,7 +205,6 @@ TEST_P(MessagePumpTest, NestedRunWithoutScheduleWorkInvokesDoWork) { ...@@ -272,7 +205,6 @@ TEST_P(MessagePumpTest, NestedRunWithoutScheduleWorkInvokesDoWork) {
#if defined(OS_IOS) #if defined(OS_IOS)
EXPECT_CALL(delegate, DoIdleWork).Times(AnyNumber()); EXPECT_CALL(delegate, DoIdleWork).Times(AnyNumber());
#endif #endif
if (pump_uses_do_some_work_) {
EXPECT_CALL(delegate, DoSomeWork).WillOnce(Invoke([this] { EXPECT_CALL(delegate, DoSomeWork).WillOnce(Invoke([this] {
testing::StrictMock<MockMessagePumpDelegate> nested_delegate; testing::StrictMock<MockMessagePumpDelegate> nested_delegate;
#if defined(OS_IOS) #if defined(OS_IOS)
...@@ -286,21 +218,6 @@ TEST_P(MessagePumpTest, NestedRunWithoutScheduleWorkInvokesDoWork) { ...@@ -286,21 +218,6 @@ TEST_P(MessagePumpTest, NestedRunWithoutScheduleWorkInvokesDoWork) {
message_pump_->Quit(); message_pump_->Quit();
return MessagePump::Delegate::NextWorkInfo{TimeTicks::Max()}; return MessagePump::Delegate::NextWorkInfo{TimeTicks::Max()};
})); }));
} else {
EXPECT_CALL(delegate, DoWork).WillOnce(Invoke([this] {
testing::StrictMock<MockMessagePumpDelegate> nested_delegate;
#if defined(OS_IOS)
EXPECT_CALL(nested_delegate, DoIdleWork).Times(AnyNumber());
#endif
EXPECT_CALL(nested_delegate, DoWork).WillOnce(Invoke([this] {
message_pump_->Quit();
return false;
}));
message_pump_->Run(&nested_delegate);
message_pump_->Quit();
return false;
}));
}
message_pump_->Run(&delegate); message_pump_->Run(&delegate);
} }
......
...@@ -82,10 +82,9 @@ class BASE_EXPORT MessagePumpWin : public MessagePump { ...@@ -82,10 +82,9 @@ class BASE_EXPORT MessagePumpWin : public MessagePump {
// //
// MessagePumpForUI implements a "traditional" Windows message pump. It contains // MessagePumpForUI implements a "traditional" Windows message pump. It contains
// a nearly infinite loop that peeks out messages, and then dispatches them. // a nearly infinite loop that peeks out messages, and then dispatches them.
// Intermixed with those peeks are callouts to DoWork for pending tasks, and // Intermixed with those peeks are callouts to DoSomeWork. When there are no
// DoDelayedWork for pending timers. When there are no events to be serviced, // events to be serviced, this pump goes into a wait state. In most cases, this
// this pump goes into a wait state. In most cases, this message pump handles // message pump handles all processing.
// all processing.
// //
// However, when a task, or windows event, invokes on the stack a native dialog // 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 // box or such, that window typically provides a bare bones (native?) message
...@@ -96,15 +95,14 @@ class BASE_EXPORT MessagePumpWin : public MessagePump { ...@@ -96,15 +95,14 @@ class BASE_EXPORT MessagePumpWin : public MessagePump {
// //
// The basic structure of the extension (referred to as a sub-pump) is that a // The basic structure of the extension (referred to as a sub-pump) is that a
// special message, kMsgHaveWork, is repeatedly injected into the Windows // special message, kMsgHaveWork, is repeatedly injected into the Windows
// Message queue. Each time the kMsgHaveWork message is peeked, checks are // Message queue. Each time the kMsgHaveWork message is peeked, checks are made
// made for an extended set of events, including the availability of Tasks to // for an extended set of events, including the availability of Tasks to run.
// run.
// //
// After running a task, the special message kMsgHaveWork is again posted to // After running a task, the special message kMsgHaveWork is again posted to the
// the Windows Message queue, ensuring a future time slice for processing a // Windows Message queue, ensuring a future time slice for processing a future
// future event. To prevent flooding the Windows Message queue, care is taken // event. To prevent flooding the Windows Message queue, care is taken to be
// to be sure that at most one kMsgHaveWork message is EVER pending in the // sure that at most one kMsgHaveWork message is EVER pending in the Window's
// Window's Message queue. // Message queue.
// //
// There are a few additional complexities in this system where, when there are // 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 // no Tasks to run, this otherwise infinite stream of messages which drives the
...@@ -115,8 +113,8 @@ class BASE_EXPORT MessagePumpWin : public MessagePump { ...@@ -115,8 +113,8 @@ class BASE_EXPORT MessagePumpWin : public MessagePump {
// prevent a bare-bones message pump from ever peeking a WM_PAINT or WM_TIMER. // 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 // 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 // kMsgHaveWork messages. As a result, care is taken to do some peeking in
// between the posting of each kMsgHaveWork message (i.e., after kMsgHaveWork // between the posting of each kMsgHaveWork message (i.e., after kMsgHaveWork is
// is peeked, and before a replacement kMsgHaveWork is posted). // peeked, and before a replacement kMsgHaveWork is posted).
// //
// NOTE: Although it may seem odd that messages are used to start and stop this // 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 // flow (as opposed to signaling objects, etc.), it should be understood that
...@@ -148,8 +146,10 @@ class BASE_EXPORT MessagePumpForUI : public MessagePumpWin { ...@@ -148,8 +146,10 @@ class BASE_EXPORT MessagePumpForUI : public MessagePumpWin {
void RemoveObserver(Observer* obseerver); void RemoveObserver(Observer* obseerver);
private: private:
bool MessageCallback( bool MessageCallback(UINT message,
UINT message, WPARAM wparam, LPARAM lparam, LRESULT* result); WPARAM wparam,
LPARAM lparam,
LRESULT* result);
void DoRunLoop() override; void DoRunLoop() override;
void WaitForWork(Delegate::NextWorkInfo next_work_info); void WaitForWork(Delegate::NextWorkInfo next_work_info);
void HandleWorkMessage(); void HandleWorkMessage();
...@@ -235,7 +235,8 @@ class BASE_EXPORT MessagePumpForIO : public MessagePumpWin { ...@@ -235,7 +235,8 @@ class BASE_EXPORT MessagePumpForIO : public MessagePumpWin {
// |context| completes. |error| is the Win32 error code of the IO operation // |context| completes. |error| is the Win32 error code of the IO operation
// (ERROR_SUCCESS if there was no error). |bytes_transfered| will be zero // (ERROR_SUCCESS if there was no error). |bytes_transfered| will be zero
// on error. // on error.
virtual void OnIOCompleted(IOContext* context, DWORD bytes_transfered, virtual void OnIOCompleted(IOContext* context,
DWORD bytes_transfered,
DWORD error) = 0; DWORD error) = 0;
}; };
......
...@@ -24,8 +24,6 @@ class MockMessagePumpDelegate : public MessagePump::Delegate { ...@@ -24,8 +24,6 @@ class MockMessagePumpDelegate : public MessagePump::Delegate {
public: public:
MOCK_METHOD0(BeforeDoInternalWork, void()); MOCK_METHOD0(BeforeDoInternalWork, void());
MOCK_METHOD0(BeforeWait, void()); MOCK_METHOD0(BeforeWait, void());
MOCK_METHOD0(DoWork, bool());
MOCK_METHOD1(DoDelayedWork, bool(TimeTicks*));
MOCK_METHOD0(DoSomeWork, NextWorkInfo()); MOCK_METHOD0(DoSomeWork, NextWorkInfo());
MOCK_METHOD0(DoIdleWork, bool()); MOCK_METHOD0(DoIdleWork, bool());
}; };
......
...@@ -286,90 +286,6 @@ ThreadControllerWithMessagePumpImpl::DoSomeWork() { ...@@ -286,90 +286,6 @@ ThreadControllerWithMessagePumpImpl::DoSomeWork() {
continuation_lazy_now.Now()}; continuation_lazy_now.Now()};
} }
bool ThreadControllerWithMessagePumpImpl::DoWork() {
// Nested runloops are covered by the parent loop hang watch scope.
// TODO(crbug/1034046): Provide more granular scoping that reuses the parent
// scope deadline.
if (main_thread_only().runloop_count == 1) {
hang_watch_scope_.emplace(base::HangWatchScope::kDefaultHangWatchTime);
}
work_deduplicator_.OnWorkStarted();
bool ran_task = false;
LazyNow continuation_lazy_now(time_source_);
TimeDelta delay_till_next_task =
DoWorkImpl(&continuation_lazy_now, &ran_task);
// Schedule a continuation.
// TODO(altimin, gab): Make this more efficient by merging DoWork
// and DoDelayedWork and allowing returning base::TimeTicks() when we have
// immediate work.
if (delay_till_next_task.is_zero()) {
// Need to run new work immediately, but due to the contract of DoWork we
// only need to return true to ensure that happens.
ran_task = true;
}
// DoDelayedWork always follows DoWork, (although the inverse is not true) so
// we don't need to schedule a delayed wakeup here.
WorkDeduplicator::NextTask next_task =
ran_task ? WorkDeduplicator::NextTask::kIsImmediate
: WorkDeduplicator::NextTask::kIsDelayed;
return work_deduplicator_.DidCheckForMoreWork(next_task) ==
ShouldScheduleWork::kScheduleImmediate;
}
bool ThreadControllerWithMessagePumpImpl::DoDelayedWork(
TimeTicks* next_run_time) {
// Nested runloops are covered by the parent loop hang watch scope.
// TODO(crbug/1034046): Provide more granular scoping that reuses the parent
// scope deadline.
if (main_thread_only().runloop_count == 1) {
hang_watch_scope_.emplace(base::HangWatchScope::kDefaultHangWatchTime);
}
work_deduplicator_.OnDelayedWorkStarted();
LazyNow continuation_lazy_now(time_source_);
bool ran_task = false;
WorkDeduplicator::NextTask next_task = WorkDeduplicator::NextTask::kIsDelayed;
TimeDelta delay_till_next_task =
DoWorkImpl(&continuation_lazy_now, &ran_task);
// Schedule a continuation.
// TODO(altimin, gab): Make this more efficient by merging DoWork
// and DoDelayedWork and allowing returning base::TimeTicks() when we have
// immediate work.
if (delay_till_next_task.is_zero()) {
*next_run_time = TimeTicks();
next_task = WorkDeduplicator::NextTask::kIsImmediate;
} else if (delay_till_next_task != TimeDelta::Max()) {
// Cancels any previously scheduled delayed wake-ups.
*next_run_time =
CapAtOneDay(delay_till_next_task + continuation_lazy_now.Now(),
&continuation_lazy_now);
// Don't request a run time past |main_thread_only().quit_runloop_after|.
if (*next_run_time > main_thread_only().quit_runloop_after) {
*next_run_time = main_thread_only().quit_runloop_after;
// If we've passed |quit_runloop_after| there's no more work to do.
if (continuation_lazy_now.Now() >= main_thread_only().quit_runloop_after)
*next_run_time = TimeTicks();
}
// The MessagePump will call ScheduleDelayedWork on our behalf, so we need
// to update |main_thread_only().next_delayed_do_work|.
main_thread_only().next_delayed_do_work = *next_run_time;
} else {
// There's no more work to do.
*next_run_time = TimeTicks();
}
// Figure out if we need to post an immediate continuation.
if (work_deduplicator_.OnDelayedWorkEnded(next_task) ==
ShouldScheduleWork::kScheduleImmediate) {
pump_->ScheduleWork();
}
return ran_task;
}
TimeDelta ThreadControllerWithMessagePumpImpl::DoWorkImpl( TimeDelta ThreadControllerWithMessagePumpImpl::DoWorkImpl(
LazyNow* continuation_lazy_now, LazyNow* continuation_lazy_now,
bool* ran_task) { bool* ran_task) {
......
...@@ -87,8 +87,6 @@ class BASE_EXPORT ThreadControllerWithMessagePumpImpl ...@@ -87,8 +87,6 @@ class BASE_EXPORT ThreadControllerWithMessagePumpImpl
void BeforeDoInternalWork() override; void BeforeDoInternalWork() override;
void BeforeWait() override; void BeforeWait() override;
MessagePump::Delegate::NextWorkInfo DoSomeWork() override; MessagePump::Delegate::NextWorkInfo DoSomeWork() override;
bool DoWork() override;
bool DoDelayedWork(TimeTicks* next_run_time) override;
bool DoIdleWork() override; bool DoIdleWork() override;
// RunLoop::Delegate implementation. // RunLoop::Delegate implementation.
......
...@@ -33,9 +33,8 @@ class ThreadControllerForTest ...@@ -33,9 +33,8 @@ class ThreadControllerForTest
SequenceManager::Settings& settings) SequenceManager::Settings& settings)
: ThreadControllerWithMessagePumpImpl(std::move(pump), settings) {} : ThreadControllerWithMessagePumpImpl(std::move(pump), settings) {}
using ThreadControllerWithMessagePumpImpl::DoDelayedWork;
using ThreadControllerWithMessagePumpImpl::DoIdleWork; using ThreadControllerWithMessagePumpImpl::DoIdleWork;
using ThreadControllerWithMessagePumpImpl::DoWork; using ThreadControllerWithMessagePumpImpl::DoSomeWork;
using ThreadControllerWithMessagePumpImpl::EnsureWorkScheduled; using ThreadControllerWithMessagePumpImpl::EnsureWorkScheduled;
using ThreadControllerWithMessagePumpImpl::Quit; using ThreadControllerWithMessagePumpImpl::Quit;
using ThreadControllerWithMessagePumpImpl::Run; using ThreadControllerWithMessagePumpImpl::Run;
...@@ -153,8 +152,6 @@ class ThreadControllerWithMessagePumpTest : public testing::Test { ...@@ -153,8 +152,6 @@ class ThreadControllerWithMessagePumpTest : public testing::Test {
}; };
TEST_F(ThreadControllerWithMessagePumpTest, ScheduleDelayedWork) { TEST_F(ThreadControllerWithMessagePumpTest, ScheduleDelayedWork) {
TimeTicks next_run_time;
MockCallback<OnceClosure> task1; MockCallback<OnceClosure> task1;
task_source_.AddTask(FROM_HERE, task1.Get(), Seconds(10)); task_source_.AddTask(FROM_HERE, task1.Get(), Seconds(10));
MockCallback<OnceClosure> task2; MockCallback<OnceClosure> task2;
...@@ -162,49 +159,46 @@ TEST_F(ThreadControllerWithMessagePumpTest, ScheduleDelayedWork) { ...@@ -162,49 +159,46 @@ TEST_F(ThreadControllerWithMessagePumpTest, ScheduleDelayedWork) {
MockCallback<OnceClosure> task3; MockCallback<OnceClosure> task3;
task_source_.AddTask(FROM_HERE, task3.Get(), Seconds(20)); task_source_.AddTask(FROM_HERE, task3.Get(), Seconds(20));
// Call a no-op DoWork. Expect that it doesn't do any work. // Call a no-op DoSomeWork. Expect that it doesn't do any work.
clock_.SetNowTicks(Seconds(5)); clock_.SetNowTicks(Seconds(5));
EXPECT_CALL(*message_pump_, ScheduleDelayedWork(_)).Times(0); EXPECT_CALL(*message_pump_, ScheduleDelayedWork(_)).Times(0);
EXPECT_FALSE(thread_controller_.DoWork()); {
testing::Mock::VerifyAndClearExpectations(message_pump_); auto next_work_info = thread_controller_.DoSomeWork();
EXPECT_FALSE(next_work_info.is_immediate());
// DoDelayedWork is always called after DoWork. Expect that it doesn't do EXPECT_EQ(next_work_info.delayed_run_time, Seconds(10));
// any work, but schedules a delayed wake-up appropriately. }
EXPECT_FALSE(thread_controller_.DoDelayedWork(&next_run_time));
EXPECT_EQ(next_run_time, Seconds(10));
testing::Mock::VerifyAndClearExpectations(message_pump_); testing::Mock::VerifyAndClearExpectations(message_pump_);
// Call DoDelayedWork after the expiration of the delay. // Call DoSomeWork after the expiration of the delay.
// Expect that a task will run and the next delay will equal to // Expect that |task1| runs and the return value indicates that |task2| can
// TimeTicks() as we have immediate work to do. // run immediately.
clock_.SetNowTicks(Seconds(11)); clock_.SetNowTicks(Seconds(11));
EXPECT_CALL(task1, Run()).Times(1); EXPECT_CALL(task1, Run()).Times(1);
// There's no pending DoWork so a ScheduleWork gets called. {
EXPECT_CALL(*message_pump_, ScheduleWork()); auto next_work_info = thread_controller_.DoSomeWork();
EXPECT_TRUE(thread_controller_.DoDelayedWork(&next_run_time)); EXPECT_TRUE(next_work_info.is_immediate());
EXPECT_EQ(next_run_time, TimeTicks()); }
testing::Mock::VerifyAndClearExpectations(message_pump_);
testing::Mock::VerifyAndClearExpectations(&task1); testing::Mock::VerifyAndClearExpectations(&task1);
// Call DoWork immediately after the previous call. Expect a new task // Call DoSomeWork. Expect |task2| to be run and the delayed run time of
// to be run. // |task3| to be returned.
EXPECT_CALL(task2, Run()).Times(1); EXPECT_CALL(task2, Run()).Times(1);
EXPECT_TRUE(thread_controller_.DoWork()); {
testing::Mock::VerifyAndClearExpectations(message_pump_); auto next_work_info = thread_controller_.DoSomeWork();
EXPECT_FALSE(next_work_info.is_immediate());
EXPECT_EQ(next_work_info.delayed_run_time, Seconds(20));
}
testing::Mock::VerifyAndClearExpectations(&task2); testing::Mock::VerifyAndClearExpectations(&task2);
// DoDelayedWork is always called after DoWork. // Call DoSomeWork for the last task and expect to be told
EXPECT_FALSE(thread_controller_.DoDelayedWork(&next_run_time));
EXPECT_EQ(next_run_time, Seconds(20));
testing::Mock::VerifyAndClearExpectations(message_pump_);
// Call DoDelayedWork for the last task and expect to be told
// about the lack of further delayed work (next run time being TimeTicks()). // about the lack of further delayed work (next run time being TimeTicks()).
clock_.SetNowTicks(Seconds(21)); clock_.SetNowTicks(Seconds(21));
EXPECT_CALL(task3, Run()).Times(1); EXPECT_CALL(task3, Run()).Times(1);
EXPECT_TRUE(thread_controller_.DoDelayedWork(&next_run_time)); {
EXPECT_EQ(next_run_time, TimeTicks()); auto next_work_info = thread_controller_.DoSomeWork();
testing::Mock::VerifyAndClearExpectations(message_pump_); EXPECT_FALSE(next_work_info.is_immediate());
EXPECT_EQ(next_work_info.delayed_run_time, TimeTicks::Max());
}
testing::Mock::VerifyAndClearExpectations(&task3); testing::Mock::VerifyAndClearExpectations(&task3);
} }
...@@ -226,17 +220,18 @@ TEST_F(ThreadControllerWithMessagePumpTest, DelayedWork_CapAtOneDay) { ...@@ -226,17 +220,18 @@ TEST_F(ThreadControllerWithMessagePumpTest, DelayedWork_CapAtOneDay) {
MockCallback<OnceClosure> task1; MockCallback<OnceClosure> task1;
task_source_.AddTask(FROM_HERE, task1.Get(), Days(10)); task_source_.AddTask(FROM_HERE, task1.Get(), Days(10));
TimeTicks next_run_time; auto next_work_info = thread_controller_.DoSomeWork();
EXPECT_FALSE(thread_controller_.DoDelayedWork(&next_run_time)); EXPECT_EQ(next_work_info.delayed_run_time, Days(1));
EXPECT_EQ(next_run_time, Days(1));
} }
TEST_F(ThreadControllerWithMessagePumpTest, DoWorkDoesntScheduleDelayedWork) { TEST_F(ThreadControllerWithMessagePumpTest,
DoSomeWorkDoesntScheduleDelayedWork) {
MockCallback<OnceClosure> task1; MockCallback<OnceClosure> task1;
task_source_.AddTask(FROM_HERE, task1.Get(), Seconds(10)); task_source_.AddTask(FROM_HERE, task1.Get(), Seconds(10));
EXPECT_CALL(*message_pump_, ScheduleDelayedWork(_)).Times(0); EXPECT_CALL(*message_pump_, ScheduleDelayedWork(_)).Times(0);
EXPECT_FALSE(thread_controller_.DoWork()); auto next_work_info = thread_controller_.DoSomeWork();
EXPECT_EQ(next_work_info.delayed_run_time, Seconds(10));
} }
TEST_F(ThreadControllerWithMessagePumpTest, NestedExecution) { TEST_F(ThreadControllerWithMessagePumpTest, NestedExecution) {
...@@ -251,17 +246,16 @@ TEST_F(ThreadControllerWithMessagePumpTest, NestedExecution) { ...@@ -251,17 +246,16 @@ TEST_F(ThreadControllerWithMessagePumpTest, NestedExecution) {
.WillOnce(Invoke([&log, this](MessagePump::Delegate* delegate) { .WillOnce(Invoke([&log, this](MessagePump::Delegate* delegate) {
log.push_back("entering top-level runloop"); log.push_back("entering top-level runloop");
EXPECT_EQ(delegate, &thread_controller_); EXPECT_EQ(delegate, &thread_controller_);
EXPECT_TRUE(delegate->DoWork()); EXPECT_TRUE(delegate->DoSomeWork().is_immediate());
EXPECT_TRUE(delegate->DoWork()); EXPECT_TRUE(delegate->DoSomeWork().is_immediate());
EXPECT_TRUE(delegate->DoWork()); EXPECT_EQ(delegate->DoSomeWork().delayed_run_time, TimeTicks::Max());
EXPECT_FALSE(delegate->DoWork());
log.push_back("exiting top-level runloop"); log.push_back("exiting top-level runloop");
})) }))
.WillOnce(Invoke([&log, this](MessagePump::Delegate* delegate) { .WillOnce(Invoke([&log, this](MessagePump::Delegate* delegate) {
log.push_back("entering nested runloop"); log.push_back("entering nested runloop");
EXPECT_EQ(delegate, &thread_controller_); EXPECT_EQ(delegate, &thread_controller_);
EXPECT_FALSE(thread_controller_.IsTaskExecutionAllowed()); EXPECT_FALSE(thread_controller_.IsTaskExecutionAllowed());
EXPECT_FALSE(delegate->DoWork()); EXPECT_EQ(delegate->DoSomeWork().delayed_run_time, TimeTicks::Max());
log.push_back("exiting nested runloop"); log.push_back("exiting nested runloop");
})); }));
...@@ -317,17 +311,15 @@ TEST_F(ThreadControllerWithMessagePumpTest, ...@@ -317,17 +311,15 @@ TEST_F(ThreadControllerWithMessagePumpTest,
.WillOnce(Invoke([&log, this](MessagePump::Delegate* delegate) { .WillOnce(Invoke([&log, this](MessagePump::Delegate* delegate) {
log.push_back("entering top-level runloop"); log.push_back("entering top-level runloop");
EXPECT_EQ(delegate, &thread_controller_); EXPECT_EQ(delegate, &thread_controller_);
EXPECT_TRUE(delegate->DoWork()); EXPECT_EQ(delegate->DoSomeWork().delayed_run_time, TimeTicks::Max());
EXPECT_FALSE(delegate->DoWork());
log.push_back("exiting top-level runloop"); log.push_back("exiting top-level runloop");
})) }))
.WillOnce(Invoke([&log, this](MessagePump::Delegate* delegate) { .WillOnce(Invoke([&log, this](MessagePump::Delegate* delegate) {
log.push_back("entering nested runloop"); log.push_back("entering nested runloop");
EXPECT_EQ(delegate, &thread_controller_); EXPECT_EQ(delegate, &thread_controller_);
EXPECT_TRUE(thread_controller_.IsTaskExecutionAllowed()); EXPECT_TRUE(thread_controller_.IsTaskExecutionAllowed());
EXPECT_TRUE(delegate->DoWork()); EXPECT_TRUE(delegate->DoSomeWork().is_immediate());
EXPECT_TRUE(delegate->DoWork()); EXPECT_EQ(delegate->DoSomeWork().delayed_run_time, TimeTicks::Max());
EXPECT_FALSE(delegate->DoWork());
log.push_back("exiting nested runloop"); log.push_back("exiting nested runloop");
})); }));
...@@ -371,28 +363,6 @@ TEST_F(ThreadControllerWithMessagePumpTest, ...@@ -371,28 +363,6 @@ TEST_F(ThreadControllerWithMessagePumpTest,
testing::Mock::VerifyAndClearExpectations(message_pump_); testing::Mock::VerifyAndClearExpectations(message_pump_);
} }
TEST_F(ThreadControllerWithMessagePumpTest, ScheduleWorkFromDelayedTask) {
ThreadTaskRunnerHandle handle(MakeRefCounted<FakeTaskRunner>());
EXPECT_CALL(*message_pump_, Run(_))
.WillOnce(Invoke([](MessagePump::Delegate* delegate) {
base::TimeTicks run_time;
delegate->DoDelayedWork(&run_time);
}));
EXPECT_CALL(*message_pump_, ScheduleWork());
task_source_.AddTask(FROM_HERE, base::BindLambdaForTesting([&]() {
// Triggers a ScheduleWork call.
task_source_.AddTask(FROM_HERE,
base::BindOnce([]() {}),
base::TimeTicks());
}),
TimeTicks());
RunLoop().Run();
testing::Mock::VerifyAndClearExpectations(message_pump_);
}
TEST_F(ThreadControllerWithMessagePumpTest, SetDefaultTaskRunner) { TEST_F(ThreadControllerWithMessagePumpTest, SetDefaultTaskRunner) {
scoped_refptr<SingleThreadTaskRunner> task_runner1 = scoped_refptr<SingleThreadTaskRunner> task_runner1 =
MakeRefCounted<FakeTaskRunner>(); MakeRefCounted<FakeTaskRunner>();
...@@ -419,16 +389,15 @@ TEST_F(ThreadControllerWithMessagePumpTest, EnsureWorkScheduled) { ...@@ -419,16 +389,15 @@ TEST_F(ThreadControllerWithMessagePumpTest, EnsureWorkScheduled) {
testing::Mock::VerifyAndClearExpectations(message_pump_); testing::Mock::VerifyAndClearExpectations(message_pump_);
// EnsureWorkScheduled() doesn't need to do anything because there's a pending // EnsureWorkScheduled() doesn't need to do anything because there's a pending
// DoWork. // DoSomeWork.
EXPECT_CALL(*message_pump_, ScheduleWork()).Times(0); EXPECT_CALL(*message_pump_, ScheduleWork()).Times(0);
thread_controller_.EnsureWorkScheduled(); thread_controller_.EnsureWorkScheduled();
testing::Mock::VerifyAndClearExpectations(message_pump_); testing::Mock::VerifyAndClearExpectations(message_pump_);
EXPECT_TRUE(thread_controller_.DoWork()); EXPECT_EQ(thread_controller_.DoSomeWork().delayed_run_time, TimeTicks::Max());
// EnsureWorkScheduled() doesn't need to call the pump because there's no // EnsureWorkScheduled() calls the pump because there's no pending DoSomeWork.
// DoWork pending. EXPECT_CALL(*message_pump_, ScheduleWork()).Times(1);
EXPECT_CALL(*message_pump_, ScheduleWork()).Times(0);
thread_controller_.EnsureWorkScheduled(); thread_controller_.EnsureWorkScheduled();
testing::Mock::VerifyAndClearExpectations(message_pump_); testing::Mock::VerifyAndClearExpectations(message_pump_);
} }
...@@ -442,7 +411,7 @@ TEST_F(ThreadControllerWithMessagePumpTest, WorkBatching) { ...@@ -442,7 +411,7 @@ TEST_F(ThreadControllerWithMessagePumpTest, WorkBatching) {
int task_count = 0; int task_count = 0;
EXPECT_CALL(*message_pump_, Run(_)) EXPECT_CALL(*message_pump_, Run(_))
.WillOnce(Invoke([&](MessagePump::Delegate* delegate) { .WillOnce(Invoke([&](MessagePump::Delegate* delegate) {
EXPECT_TRUE(delegate->DoWork()); EXPECT_EQ(delegate->DoSomeWork().delayed_run_time, TimeTicks::Max());
EXPECT_EQ(5, task_count); EXPECT_EQ(5, task_count);
})); }));
...@@ -467,17 +436,16 @@ TEST_F(ThreadControllerWithMessagePumpTest, QuitInterruptsBatch) { ...@@ -467,17 +436,16 @@ TEST_F(ThreadControllerWithMessagePumpTest, QuitInterruptsBatch) {
int task_count = 0; int task_count = 0;
EXPECT_CALL(*message_pump_, Run(_)) EXPECT_CALL(*message_pump_, Run(_))
.WillOnce(Invoke([&](MessagePump::Delegate* delegate) { .WillOnce(Invoke([&](MessagePump::Delegate* delegate) {
TimeTicks next_time; EXPECT_EQ(delegate->DoSomeWork().delayed_run_time, TimeTicks::Max());
EXPECT_TRUE(delegate->DoWork());
EXPECT_EQ(1, task_count); EXPECT_EQ(1, task_count);
// Somewhat counter-intuitive, but if the pump keeps calling us after // Somewhat counter-intuitive, but if the pump keeps calling us after
// Quit(), the delegate should still run tasks as normally. This is // Quit(), the delegate should still run tasks as normally. This is
// needed to support nested OS-level runloops that still pump // needed to support nested OS-level runloops that still pump
// application tasks (e.g., showing a popup menu on Mac). // application tasks (e.g., showing a popup menu on Mac).
EXPECT_TRUE(delegate->DoDelayedWork(&next_time)); EXPECT_EQ(delegate->DoSomeWork().delayed_run_time, TimeTicks::Max());
EXPECT_EQ(2, task_count); EXPECT_EQ(2, task_count);
EXPECT_TRUE(delegate->DoWork()); EXPECT_EQ(delegate->DoSomeWork().delayed_run_time, TimeTicks::Max());
EXPECT_EQ(3, task_count); EXPECT_EQ(3, task_count);
})); }));
EXPECT_CALL(*message_pump_, Quit()); EXPECT_CALL(*message_pump_, Quit());
...@@ -511,9 +479,8 @@ TEST_F(ThreadControllerWithMessagePumpTest, EarlyQuit) { ...@@ -511,9 +479,8 @@ TEST_F(ThreadControllerWithMessagePumpTest, EarlyQuit) {
EXPECT_CALL(*message_pump_, Run(_)) EXPECT_CALL(*message_pump_, Run(_))
.WillOnce(Invoke([this](MessagePump::Delegate* delegate) { .WillOnce(Invoke([this](MessagePump::Delegate* delegate) {
EXPECT_EQ(delegate, &thread_controller_); EXPECT_EQ(delegate, &thread_controller_);
EXPECT_TRUE(delegate->DoWork()); EXPECT_TRUE(delegate->DoSomeWork().is_immediate());
EXPECT_TRUE(delegate->DoWork()); EXPECT_EQ(delegate->DoSomeWork().delayed_run_time, TimeTicks::Max());
EXPECT_FALSE(delegate->DoWork());
})); }));
RunLoop run_loop; RunLoop run_loop;
...@@ -551,7 +518,8 @@ TEST_F(ThreadControllerWithMessagePumpTest, NativeNestedMessageLoop) { ...@@ -551,7 +518,8 @@ TEST_F(ThreadControllerWithMessagePumpTest, NativeNestedMessageLoop) {
// There's no pending work so the native loop should go // There's no pending work so the native loop should go
// idle. // idle.
EXPECT_CALL(*message_pump_, ScheduleWork()).Times(0); EXPECT_CALL(*message_pump_, ScheduleWork()).Times(0);
EXPECT_FALSE(thread_controller_.DoWork()); EXPECT_EQ(thread_controller_.DoSomeWork().delayed_run_time,
TimeTicks::Max());
testing::Mock::VerifyAndClearExpectations(message_pump_); testing::Mock::VerifyAndClearExpectations(message_pump_);
// Simulate a native callback which posts a task, this // Simulate a native callback which posts a task, this
...@@ -578,7 +546,7 @@ TEST_F(ThreadControllerWithMessagePumpTest, NativeNestedMessageLoop) { ...@@ -578,7 +546,7 @@ TEST_F(ThreadControllerWithMessagePumpTest, NativeNestedMessageLoop) {
// Simulate a PostTask that enters a native nested message loop. // Simulate a PostTask that enters a native nested message loop.
EXPECT_CALL(*message_pump_, ScheduleWork()); EXPECT_CALL(*message_pump_, ScheduleWork());
thread_controller_.ScheduleWork(); thread_controller_.ScheduleWork();
EXPECT_TRUE(thread_controller_.DoWork()); EXPECT_TRUE(thread_controller_.DoSomeWork().is_immediate());
EXPECT_TRUE(did_run); EXPECT_TRUE(did_run);
} }
...@@ -592,21 +560,20 @@ TEST_F(ThreadControllerWithMessagePumpTest, RunWithTimeout) { ...@@ -592,21 +560,20 @@ TEST_F(ThreadControllerWithMessagePumpTest, RunWithTimeout) {
EXPECT_CALL(*message_pump_, Run(_)) EXPECT_CALL(*message_pump_, Run(_))
.WillOnce(Invoke([&](MessagePump::Delegate*) { .WillOnce(Invoke([&](MessagePump::Delegate*) {
TimeTicks next_run_time;
clock_.SetNowTicks(Seconds(5)); clock_.SetNowTicks(Seconds(5));
EXPECT_CALL(task1, Run()).Times(1); EXPECT_CALL(task1, Run()).Times(1);
EXPECT_TRUE(thread_controller_.DoDelayedWork(&next_run_time)); EXPECT_EQ(thread_controller_.DoSomeWork().delayed_run_time,
EXPECT_EQ(next_run_time, Seconds(10)); Seconds(10));
clock_.SetNowTicks(Seconds(10)); clock_.SetNowTicks(Seconds(10));
EXPECT_CALL(task2, Run()).Times(1); EXPECT_CALL(task2, Run()).Times(1);
EXPECT_TRUE(thread_controller_.DoDelayedWork(&next_run_time)); EXPECT_EQ(thread_controller_.DoSomeWork().delayed_run_time,
EXPECT_EQ(next_run_time, Seconds(15)); Seconds(15));
clock_.SetNowTicks(Seconds(15)); clock_.SetNowTicks(Seconds(15));
EXPECT_CALL(task3, Run()).Times(0); EXPECT_CALL(task3, Run()).Times(0);
EXPECT_FALSE(thread_controller_.DoDelayedWork(&next_run_time)); EXPECT_EQ(thread_controller_.DoSomeWork().delayed_run_time,
EXPECT_EQ(next_run_time, TimeTicks()); TimeTicks::Max());
EXPECT_CALL(*message_pump_, Quit()); EXPECT_CALL(*message_pump_, Quit());
EXPECT_FALSE(thread_controller_.DoIdleWork()); EXPECT_FALSE(thread_controller_.DoIdleWork());
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment