summaryrefslogtreecommitdiffstats
path: root/chromium/base/message_loop
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2020-10-06 12:48:11 +0200
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2020-10-13 09:33:43 +0000
commit7b5b123ac58f58ffde0f4f6e488bcd09aa4decd3 (patch)
treefa14ba0ca8d2683ba2efdabd246dc9b18a1229c6 /chromium/base/message_loop
parent79b4f909db1049fca459c07cca55af56a9b54fe3 (diff)
BASELINE: Update Chromium to 84.0.4147.141
Change-Id: Ib85eb4cfa1cbe2b2b81e5022c8cad5c493969535 Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
Diffstat (limited to 'chromium/base/message_loop')
-rw-r--r--chromium/base/message_loop/message_loop.cc2
-rw-r--r--chromium/base/message_loop/message_loop_unittest.cc50
-rw-r--r--chromium/base/message_loop/message_pump.cc2
-rw-r--r--chromium/base/message_loop/message_pump_android.cc3
-rw-r--r--chromium/base/message_loop/message_pump_fuchsia.cc11
-rw-r--r--chromium/base/message_loop/message_pump_fuchsia.h5
-rw-r--r--chromium/base/message_loop/message_pump_mac.mm3
-rw-r--r--chromium/base/message_loop/message_pump_win.cc95
-rw-r--r--chromium/base/message_loop/message_pump_win.h17
9 files changed, 160 insertions, 28 deletions
diff --git a/chromium/base/message_loop/message_loop.cc b/chromium/base/message_loop/message_loop.cc
index 7e0b9c5520d..d4b68bed9fb 100644
--- a/chromium/base/message_loop/message_loop.cc
+++ b/chromium/base/message_loop/message_loop.cc
@@ -7,7 +7,7 @@
#include <utility>
#include "base/bind.h"
-#include "base/logging.h"
+#include "base/check_op.h"
#include "base/memory/ptr_util.h"
#include "base/message_loop/message_pump_default.h"
#include "base/message_loop/message_pump_for_io.h"
diff --git a/chromium/base/message_loop/message_loop_unittest.cc b/chromium/base/message_loop/message_loop_unittest.cc
index 129f6b75d4e..1d0ed42b239 100644
--- a/chromium/base/message_loop/message_loop_unittest.cc
+++ b/chromium/base/message_loop/message_loop_unittest.cc
@@ -387,7 +387,7 @@ class TestIOHandler : public MessagePumpForIO::IOHandler {
};
TestIOHandler::TestIOHandler(const wchar_t* name, HANDLE signal, bool wait)
- : signal_(signal), wait_(wait) {
+ : MessagePumpForIO::IOHandler(FROM_HERE), signal_(signal), wait_(wait) {
memset(buffer_, 0, sizeof(buffer_));
file_.Set(CreateFile(name, GENERIC_READ, 0, NULL, OPEN_EXISTING,
@@ -1615,6 +1615,54 @@ TEST_F(MessageLoopTest, PostImmediateTaskFromSystemPump) {
// https://crrev.com/c/1455266/9/base/message_loop/message_pump_win.cc#125 This
// is the delayed task equivalent of the above PostImmediateTaskFromSystemPump
// test.
+//
+// As a reminder of how this works, here's the sequence of events in this test:
+// 1) Test start:
+// work_deduplicator.cc(24): BindToCurrentThread
+// work_deduplicator.cc(34): OnWorkRequested
+// thread_controller_with_message_pump_impl.cc(237) : DoWork
+// work_deduplicator.cc(50): OnWorkStarted
+// 2) SubPumpFunc entered:
+// message_loop_unittest.cc(278): SubPumpFunc
+// 3) ScopedNestableTaskAllower triggers nested ScheduleWork:
+// work_deduplicator.cc(34): OnWorkRequested
+// 4) Nested system loop starts and pumps internal kMsgHaveWork:
+// message_loop_unittest.cc(282): SubPumpFunc : Got Message
+// message_pump_win.cc(302): HandleWorkMessage
+// thread_controller_with_message_pump_impl.cc(237) : DoWork
+// 5) Attempt to DoWork(), there's nothing to do, NextWorkInfo indicates delay.
+// work_deduplicator.cc(50): OnWorkStarted
+// work_deduplicator.cc(58): WillCheckForMoreWork
+// work_deduplicator.cc(67): DidCheckForMoreWork
+// 6) Return control to HandleWorkMessage() which schedules native timer
+// and goes to sleep (no kMsgHaveWork in native queue).
+// message_pump_win.cc(328): HandleWorkMessage ScheduleNativeTimer
+// 7) Native timer fires and posts the delayed application task:
+// message_loop_unittest.cc(282): SubPumpFunc : Got Message
+// message_loop_unittest.cc(1581): DelayedQuitOnSystemTimer
+// !! This is the critical step verified by this test. Since the
+// ThreadController is idle after (6), it won't be invoked again and thus
+// won't get a chance to return a NextWorkInfo that indicates the next
+// delay. A native timer is thus required to have SubPumpFunc handle it.
+// work_deduplicator.cc(42): OnDelayedWorkRequested
+// message_pump_win.cc(129): ScheduleDelayedWork
+// 9) The scheduled native timer fires and runs application task binding
+// ::PostQuitMessage :
+// message_loop_unittest.cc(282) SubPumpFunc : Got Message
+// work_deduplicator.cc(50): OnWorkStarted
+// thread_controller_with_message_pump_impl.cc(237) : DoWork
+// 10) SequenceManager updates delay to none and notifies
+// (TODO(scheduler-dev): Could remove this step but WorkDeduplicator knows
+// to ignore at least):
+// work_deduplicator.cc(42): OnDelayedWorkRequested
+// 11) Nested application task completes and SubPumpFunc unwinds:
+// work_deduplicator.cc(58): WillCheckForMoreWork
+// work_deduplicator.cc(67): DidCheckForMoreWork
+// 12) ~ScopedNestableTaskAllower() makes sure WorkDeduplicator knows we're
+// back in DoWork() (not relevant in this test but important overall).
+// work_deduplicator.cc(50): OnWorkStarted
+// 13) Application task which ran SubPumpFunc completes and test finishes.
+// work_deduplicator.cc(67): DidCheckForMoreWork
TEST_F(MessageLoopTest, PostDelayedTaskFromSystemPump) {
MessageLoop message_loop(MessagePumpType::UI);
diff --git a/chromium/base/message_loop/message_pump.cc b/chromium/base/message_loop/message_pump.cc
index 877ba35cc4c..81ba252ee3e 100644
--- a/chromium/base/message_loop/message_pump.cc
+++ b/chromium/base/message_loop/message_pump.cc
@@ -4,9 +4,11 @@
#include "base/message_loop/message_pump.h"
+#include "base/check.h"
#include "base/message_loop/message_pump_default.h"
#include "base/message_loop/message_pump_for_io.h"
#include "base/message_loop/message_pump_for_ui.h"
+#include "base/notreached.h"
#if defined(OS_MACOSX)
#include "base/message_loop/message_pump_mac.h"
diff --git a/chromium/base/message_loop/message_pump_android.cc b/chromium/base/message_loop/message_pump_android.cc
index 9b514918228..85a25deab2f 100644
--- a/chromium/base/message_loop/message_pump_android.cc
+++ b/chromium/base/message_loop/message_pump_android.cc
@@ -17,8 +17,9 @@
#include "base/android/jni_android.h"
#include "base/android/scoped_java_ref.h"
#include "base/callback_helpers.h"
+#include "base/check_op.h"
#include "base/lazy_instance.h"
-#include "base/logging.h"
+#include "base/notreached.h"
#include "base/run_loop.h"
#include "build/build_config.h"
diff --git a/chromium/base/message_loop/message_pump_fuchsia.cc b/chromium/base/message_loop/message_pump_fuchsia.cc
index c4a15598e14..1c575681064 100644
--- a/chromium/base/message_loop/message_pump_fuchsia.cc
+++ b/chromium/base/message_loop/message_pump_fuchsia.cc
@@ -60,8 +60,7 @@ bool MessagePumpFuchsia::ZxHandleWatchController::StopWatchingZxHandle() {
if (!weak_pump_)
return true;
- // |handler| is set when waiting for a signal.
- if (!handler)
+ if (!is_active())
return true;
async_wait_t::handler = nullptr;
@@ -150,7 +149,7 @@ MessagePumpFuchsia::FdWatchController::~FdWatchController() {
}
bool MessagePumpFuchsia::FdWatchController::WaitBegin() {
- // Refresh the |handle_| and |desired_signals_| from the mxio for the fd.
+ // Refresh the |handle_| and |desired_signals_| from the fdio for the fd.
// Some types of fdio map read/write events to different signals depending on
// their current state, so we must do this every time we begin to wait.
fdio_unsafe_wait_begin(io_, desired_events_, &object, &trigger);
@@ -229,8 +228,10 @@ bool MessagePumpFuchsia::WatchZxHandle(zx_handle_t handle,
DCHECK_NE(0u, signals);
DCHECK(controller);
DCHECK(delegate);
- DCHECK(handle == ZX_HANDLE_INVALID ||
- controller->async_wait_t::object == ZX_HANDLE_INVALID ||
+
+ // If the watch controller is active then WatchZxHandle() can be called only
+ // for the same handle.
+ DCHECK(handle == ZX_HANDLE_INVALID || !controller->is_active() ||
handle == controller->async_wait_t::object);
if (!controller->StopWatchingZxHandle())
diff --git a/chromium/base/message_loop/message_pump_fuchsia.h b/chromium/base/message_loop/message_pump_fuchsia.h
index 2b21b53205f..d494a4f0d7e 100644
--- a/chromium/base/message_loop/message_pump_fuchsia.h
+++ b/chromium/base/message_loop/message_pump_fuchsia.h
@@ -53,6 +53,8 @@ class BASE_EXPORT MessagePumpFuchsia : public MessagePump,
virtual bool WaitBegin();
+ bool is_active() const { return async_wait_t::handler != nullptr; }
+
static void HandleSignal(async_dispatcher_t* async,
async_wait_t* wait,
zx_status_t status,
@@ -105,7 +107,8 @@ class BASE_EXPORT MessagePumpFuchsia : public MessagePump,
int fd_ = -1;
uint32_t desired_events_ = 0;
- // Set by WatchFileDescriptor to hold a reference to the descriptor's mxio.
+ // Set by WatchFileDescriptor() to hold a reference to the descriptor's
+ // fdio.
fdio_t* io_ = nullptr;
DISALLOW_COPY_AND_ASSIGN(FdWatchController);
diff --git a/chromium/base/message_loop/message_pump_mac.mm b/chromium/base/message_loop/message_pump_mac.mm
index bb9e6d30bed..cbda789a0d2 100644
--- a/chromium/base/message_loop/message_pump_mac.mm
+++ b/chromium/base/message_loop/message_pump_mac.mm
@@ -10,11 +10,12 @@
#include <memory>
#include "base/auto_reset.h"
+#include "base/check_op.h"
#include "base/feature_list.h"
-#include "base/logging.h"
#include "base/mac/call_with_eh_frame.h"
#include "base/mac/scoped_cftyperef.h"
#include "base/message_loop/timer_slack.h"
+#include "base/notreached.h"
#include "base/run_loop.h"
#include "base/stl_util.h"
#include "base/time/time.h"
diff --git a/chromium/base/message_loop/message_pump_win.cc b/chromium/base/message_loop/message_pump_win.cc
index c50e34f6da1..83cbec19c29 100644
--- a/chromium/base/message_loop/message_pump_win.cc
+++ b/chromium/base/message_loop/message_pump_win.cc
@@ -10,6 +10,7 @@
#include "base/bind.h"
#include "base/debug/alias.h"
+#include "base/feature_list.h"
#include "base/metrics/histogram_macros.h"
#include "base/numerics/ranges.h"
#include "base/numerics/safe_conversions.h"
@@ -19,6 +20,16 @@ namespace base {
namespace {
+// Jank analysis uncovered that Windows uses native ::PeekMessage calls as an
+// opportunity to yield to other threads according to some heuristics (e.g.
+// presumably when there's no input but perhaps a single WM_USER message posted
+// later than another thread was readied). MessagePumpForUI doesn't intend to
+// give this opportunity to the kernel when invoking ::PeekMessage however as it
+// runs most tasks out-of-band. Hence, PM_NOYIELD should be used to tell
+// ::PeekMessage it's not the only source of work for this thread.
+const Feature kNoYieldFromNativePeek{"NoYieldFromNativePeek",
+ FEATURE_DISABLED_BY_DEFAULT};
+
enum MessageLoopProblems {
MESSAGE_POST_ERROR,
COMPLETION_POST_ERROR,
@@ -138,6 +149,7 @@ void MessagePumpForUI::ScheduleDelayedWork(const TimeTicks& delayed_work_time) {
// from it. This is the only case where we must install/adjust the native
// timer from ScheduleDelayedWork() because if we don't, the native loop will
// go back to sleep, unaware of the new |delayed_work_time|.
+ // See MessageLoopTest.PostDelayedTaskFromSystemPump for an example.
// TODO(gab): This could potentially be replaced by a ForegroundIdleProc hook
// if Windows ends up being the only platform requiring ScheduleDelayedWork().
if (in_native_loop_ && !work_scheduled_) {
@@ -206,8 +218,6 @@ void MessagePumpForUI::DoRunLoop() {
// work.
in_native_loop_ = false;
- state_->delegate->BeforeDoInternalWork();
- DCHECK(!in_native_loop_);
bool more_work_is_plausible = ProcessNextWindowsMessage();
in_native_loop_ = false;
@@ -277,12 +287,23 @@ void MessagePumpForUI::WaitForWork(Delegate::NextWorkInfo next_work_info) {
// some time to process its input messages by looping back to
// MsgWaitForMultipleObjectsEx above when there are no messages for the
// current thread.
- MSG msg = {0};
- bool has_pending_sent_message =
- (HIWORD(::GetQueueStatus(QS_SENDMESSAGE)) & QS_SENDMESSAGE) != 0;
- if (has_pending_sent_message ||
- ::PeekMessage(&msg, nullptr, 0, 0, PM_NOREMOVE)) {
- return;
+
+ {
+ // Trace as in ProcessNextWindowsMessage().
+ TRACE_EVENT0("base", "MessagePumpForUI::WaitForWork GetQueueStatus");
+ if (HIWORD(::GetQueueStatus(QS_SENDMESSAGE)) & QS_SENDMESSAGE)
+ return;
+ }
+
+ {
+ static const auto kAdditionalFlags =
+ FeatureList::IsEnabled(kNoYieldFromNativePeek) ? PM_NOYIELD : 0x0;
+
+ MSG msg;
+ // Trace as in ProcessNextWindowsMessage().
+ TRACE_EVENT0("base", "MessagePumpForUI::WaitForWork PeekMessage");
+ if (::PeekMessage(&msg, nullptr, 0, 0, kAdditionalFlags | PM_NOREMOVE))
+ return;
}
// We know there are no more messages for this thread because PeekMessage
@@ -435,16 +456,46 @@ bool MessagePumpForUI::ProcessNextWindowsMessage() {
// dispatches the message and returns false. We return true in this
// case to ensure that the message loop peeks again instead of calling
// MsgWaitForMultipleObjectsEx.
- bool sent_messages_in_queue = false;
- DWORD queue_status = ::GetQueueStatus(QS_SENDMESSAGE);
- if (HIWORD(queue_status) & QS_SENDMESSAGE)
- sent_messages_in_queue = true;
+ bool more_work_is_plausible = false;
+ {
+ // Individually trace ::GetQueueStatus and ::PeekMessage because sampling
+ // profiler is hinting that we're spending a surprising amount of time with
+ // these on top of the stack. Tracing will be able to tell us whether this
+ // is a bias of sampling profiler (e.g. kernel takes ::GetQueueStatus as an
+ // opportunity to swap threads and is more likely to schedule the sampling
+ // profiler's thread while the sampled thread is swapped out on this frame).
+ TRACE_EVENT0("base",
+ "MessagePumpForUI::ProcessNextWindowsMessage GetQueueStatus");
+ DWORD queue_status = ::GetQueueStatus(QS_SENDMESSAGE);
+ if (HIWORD(queue_status) & QS_SENDMESSAGE)
+ more_work_is_plausible = true;
+ }
MSG msg;
- if (::PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE) != FALSE)
- return ProcessMessageHelper(msg);
+ bool has_msg = false;
+ {
+ // ::PeekMessage() may process sent messages (regardless of |had_messages|
+ // as ::GetQueueStatus() is an optimistic check that may racily have missed
+ // an incoming event -- it doesn't hurt to have empty internal units of work
+ // when ::PeekMessage turns out to be a no-op).
+ state_->delegate->BeforeDoInternalWork();
+
+ static const auto kAdditionalFlags =
+ FeatureList::IsEnabled(kNoYieldFromNativePeek) ? PM_NOYIELD : 0x0;
+
+ // PeekMessage can run a message if there are sent messages, trace that and
+ // emit the boolean param to see if it ever janks independently (ref.
+ // comment on GetQueueStatus).
+ TRACE_EVENT1("base",
+ "MessagePumpForUI::ProcessNextWindowsMessage PeekMessage",
+ "sent_messages_in_queue", more_work_is_plausible);
+ has_msg = ::PeekMessage(&msg, nullptr, 0, 0,
+ kAdditionalFlags | PM_REMOVE) != FALSE;
+ }
+ if (has_msg)
+ more_work_is_plausible |= ProcessMessageHelper(msg);
- return sent_messages_in_queue;
+ return more_work_is_plausible;
}
bool MessagePumpForUI::ProcessMessageHelper(const MSG& msg) {
@@ -470,6 +521,8 @@ bool MessagePumpForUI::ProcessMessageHelper(const MSG& msg) {
if (msg.message == kMsgHaveWork && msg.hwnd == message_window_.hwnd())
return ProcessPumpReplacementMessage();
+ state_->delegate->BeforeDoInternalWork();
+
for (Observer& observer : observers_)
observer.WillDispatchMSG(msg);
::TranslateMessage(&msg);
@@ -492,6 +545,10 @@ bool MessagePumpForUI::ProcessPumpReplacementMessage() {
// that peeked replacement. Note that the re-post of kMsgHaveWork may be
// asynchronous to this thread!!
+ // As in ProcessNextWindowsMessage() since ::PeekMessage() may process
+ // sent-messages.
+ state_->delegate->BeforeDoInternalWork();
+
MSG msg;
const bool have_message =
::PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE) != FALSE;
@@ -544,6 +601,11 @@ MessagePumpForIO::IOContext::IOContext() {
memset(&overlapped, 0, sizeof(overlapped));
}
+MessagePumpForIO::IOHandler::IOHandler(const Location& from_here)
+ : io_handler_location_(from_here) {}
+
+MessagePumpForIO::IOHandler::~IOHandler() = default;
+
MessagePumpForIO::MessagePumpForIO() {
port_.Set(::CreateIoCompletionPort(INVALID_HANDLE_VALUE, nullptr,
reinterpret_cast<ULONG_PTR>(nullptr), 1));
@@ -678,6 +740,9 @@ bool MessagePumpForIO::WaitForIOCompletion(DWORD timeout, IOHandler* filter) {
// Save this item for later
completed_io_.push_back(item);
} else {
+ TRACE_EVENT2("base,toplevel", "IOHandler::OnIOCompleted", "dest_file",
+ item.handler->io_handler_location().file_name(), "dest_func",
+ item.handler->io_handler_location().function_name());
item.handler->OnIOCompleted(item.context, item.bytes_transfered,
item.error);
}
diff --git a/chromium/base/message_loop/message_pump_win.h b/chromium/base/message_loop/message_pump_win.h
index a55947fd731..786ae8054f3 100644
--- a/chromium/base/message_loop/message_pump_win.h
+++ b/chromium/base/message_loop/message_pump_win.h
@@ -12,6 +12,7 @@
#include <memory>
#include "base/base_export.h"
+#include "base/location.h"
#include "base/message_loop/message_pump.h"
#include "base/observer_list.h"
#include "base/optional.h"
@@ -198,7 +199,7 @@ class BASE_EXPORT MessagePumpForIO : public MessagePumpWin {
//
// Typical use #1:
// class MyFile : public IOHandler {
- // MyFile() {
+ // MyFile() : IOHandler(FROM_HERE) {
// ...
// message_pump->RegisterIOHandler(file_, this);
// }
@@ -228,9 +229,14 @@ class BASE_EXPORT MessagePumpForIO : public MessagePumpWin {
// message_pump->WaitForIOCompletion(INFINITE, this);
// }
//
- class IOHandler {
+ class BASE_EXPORT IOHandler {
public:
- virtual ~IOHandler() {}
+ explicit IOHandler(const Location& from_here);
+ virtual ~IOHandler();
+
+ IOHandler(const IOHandler&) = delete;
+ IOHandler& operator=(const IOHandler&) = delete;
+
// This will be called once the pending IO operation associated with
// |context| completes. |error| is the Win32 error code of the IO operation
// (ERROR_SUCCESS if there was no error). |bytes_transfered| will be zero
@@ -238,6 +244,11 @@ class BASE_EXPORT MessagePumpForIO : public MessagePumpWin {
virtual void OnIOCompleted(IOContext* context,
DWORD bytes_transfered,
DWORD error) = 0;
+
+ const Location& io_handler_location() { return io_handler_location_; }
+
+ private:
+ const Location io_handler_location_;
};
MessagePumpForIO();