From bd8bfa13bb6ab6883536b0672abcf254aa666875 Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Wed, 6 Oct 2021 16:11:09 -0500 Subject: [PATCH] Fix opening the debug tap (#11445) It's possible that we're about to be started, _before_ our paired connection is started. Both will get Start()'ed when their owning TermControl is finally laid out. However, if we're started first, then we'll immediately start printing to the other control as well, which might not have initialized yet. If we do that, we'll explode. Instead, wait here until the other connection is started too, before actually starting the connection to the client app. This will ensure both controls are initialized before the client app is. Fixes #11282 Tested: Opened about 100 debug taps. They all worked. :shipit: --- .../TerminalApp/DebugTapConnection.cpp | 19 ++++++++++++++++++- src/cascadia/TerminalApp/DebugTapConnection.h | 3 +++ src/cascadia/TerminalControl/ControlCore.cpp | 2 +- 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/src/cascadia/TerminalApp/DebugTapConnection.cpp b/src/cascadia/TerminalApp/DebugTapConnection.cpp index 54f327b3e..0d84d8f05 100644 --- a/src/cascadia/TerminalApp/DebugTapConnection.cpp +++ b/src/cascadia/TerminalApp/DebugTapConnection.cpp @@ -21,8 +21,22 @@ namespace winrt::Microsoft::TerminalApp::implementation } void Initialize(const Windows::Foundation::Collections::ValueSet& /*settings*/) {} ~DebugInputTapConnection() = default; - void Start() + winrt::fire_and_forget Start() { + // GH#11282: It's possible that we're about to be started, _before_ + // our paired connection is started. Both will get Start()'ed when + // their owning TermControl is finally laid out. However, if we're + // started first, then we'll immediately start printing to the other + // control as well, which might not have initialized yet. If we do + // that, we'll explode. + // + // Instead, wait here until the other connection is started too, + // before actually starting the connection to the client app. This + // will ensure both controls are initialized before the client app + // is. + co_await winrt::resume_background(); + _pairedTap->_start.wait(); + _wrappedConnection.Start(); } void WriteInput(hstring const& data) @@ -59,6 +73,9 @@ namespace winrt::Microsoft::TerminalApp::implementation void DebugTapConnection::Start() { // presume the wrapped connection is started. + + // This is explained in the comment for GH#11282 above. + _start.count_down(); } void DebugTapConnection::WriteInput(hstring const& data) diff --git a/src/cascadia/TerminalApp/DebugTapConnection.h b/src/cascadia/TerminalApp/DebugTapConnection.h index c5156afc4..56d509fbf 100644 --- a/src/cascadia/TerminalApp/DebugTapConnection.h +++ b/src/cascadia/TerminalApp/DebugTapConnection.h @@ -5,6 +5,7 @@ #include #include "../../inc/cppwinrt_utils.h" +#include namespace winrt::Microsoft::TerminalApp::implementation { @@ -36,6 +37,8 @@ namespace winrt::Microsoft::TerminalApp::implementation winrt::weak_ref _wrappedConnection; winrt::weak_ref _inputSide; + til::latch _start{ 1 }; + friend class DebugInputTapConnection; }; } diff --git a/src/cascadia/TerminalControl/ControlCore.cpp b/src/cascadia/TerminalControl/ControlCore.cpp index efcce89c8..9c3af6bc3 100644 --- a/src/cascadia/TerminalControl/ControlCore.cpp +++ b/src/cascadia/TerminalControl/ControlCore.cpp @@ -1025,7 +1025,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation TerminalConnection::ConnectionState ControlCore::ConnectionState() const { - return _connection.State(); + return _connection ? _connection.State() : TerminalConnection::ConnectionState::Closed; } hstring ControlCore::Title()