From 1299a839bd61d291cbb90d723479f058a612b626 Mon Sep 17 00:00:00 2001 From: "Dustin L. Howett (MSFT)" Date: Wed, 8 Apr 2020 17:20:51 -0700 Subject: [PATCH] Muffle updates to the cursor position to 1/~100ms (#5289) This stops us from dispatching back-to-back terminal cursor position updates to the TSF control before it has a chance to get back to us. Fixes #5288. --- src/cascadia/TerminalControl/TermControl.cpp | 17 +++++++++++++++++ src/cascadia/TerminalControl/TermControl.h | 6 ++++++ 2 files changed, 23 insertions(+) diff --git a/src/cascadia/TerminalControl/TermControl.cpp b/src/cascadia/TerminalControl/TermControl.cpp index bfa107318d..f3c2e1d835 100644 --- a/src/cascadia/TerminalControl/TermControl.cpp +++ b/src/cascadia/TerminalControl/TermControl.cpp @@ -1851,6 +1851,13 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation // - N/A winrt::fire_and_forget TermControl::_TerminalCursorPositionChanged() { + bool expectedFalse{ false }; + if (!_coroutineDispatchStateUpdateInProgress.compare_exchange_weak(expectedFalse, true)) + { + // somebody's already in here. + return; + } + if (_closing.load()) { return; @@ -1858,6 +1865,15 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation auto weakThis{ get_weak() }; + // Muffle 2: Muffle Harder + // If we're the lucky coroutine who gets through, we'll still wait 100ms to clog + // the atomic above so we don't service the cursor update too fast. If we get through + // and finish processing the update quickly but similar requests are still beating + // down the door above in the atomic, we may still update the cursor way more than + // is visible to anyone's eye, which is a waste of effort. + static constexpr auto CursorUpdateQuiesceTime{ std::chrono::milliseconds(100) }; + co_await winrt::resume_after(CursorUpdateQuiesceTime); + co_await winrt::resume_foreground(Dispatcher()); if (auto control{ weakThis.get() }) @@ -1866,6 +1882,7 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation { TSFInputControl().TryRedrawCanvas(); } + _coroutineDispatchStateUpdateInProgress.store(false); } } diff --git a/src/cascadia/TerminalControl/TermControl.h b/src/cascadia/TerminalControl/TermControl.h index cb28cd78ab..d308296555 100644 --- a/src/cascadia/TerminalControl/TermControl.h +++ b/src/cascadia/TerminalControl/TermControl.h @@ -231,6 +231,12 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation void _CompositionCompleted(winrt::hstring text); void _CurrentCursorPositionHandler(const IInspectable& sender, const CursorPositionEventArgs& eventArgs); void _FontInfoHandler(const IInspectable& sender, const FontInfoEventArgs& eventArgs); + + // this atomic is to be used as a guard against dispatching billions of coroutines for + // routine state changes that might happen millions of times a second. + // Unbounded main dispatcher use leads to massive memory leaks and intense slowdowns + // on the UI thread. + std::atomic _coroutineDispatchStateUpdateInProgress{ false }; }; }