diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2020-10-06 12:48:11 +0200 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2020-10-13 09:33:43 +0000 |
commit | 7b5b123ac58f58ffde0f4f6e488bcd09aa4decd3 (patch) | |
tree | fa14ba0ca8d2683ba2efdabd246dc9b18a1229c6 /chromium/base/message_loop | |
parent | 79b4f909db1049fca459c07cca55af56a9b54fe3 (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.cc | 2 | ||||
-rw-r--r-- | chromium/base/message_loop/message_loop_unittest.cc | 50 | ||||
-rw-r--r-- | chromium/base/message_loop/message_pump.cc | 2 | ||||
-rw-r--r-- | chromium/base/message_loop/message_pump_android.cc | 3 | ||||
-rw-r--r-- | chromium/base/message_loop/message_pump_fuchsia.cc | 11 | ||||
-rw-r--r-- | chromium/base/message_loop/message_pump_fuchsia.h | 5 | ||||
-rw-r--r-- | chromium/base/message_loop/message_pump_mac.mm | 3 | ||||
-rw-r--r-- | chromium/base/message_loop/message_pump_win.cc | 95 | ||||
-rw-r--r-- | chromium/base/message_loop/message_pump_win.h | 17 |
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(); |