This works to kill the content and have the app live
This commit is contained in:
parent
56f1223dc5
commit
b541179333
|
@ -199,6 +199,16 @@ namespace winrt::SampleApp::implementation
|
|||
// Create the XAML control that will be attached to the content process.
|
||||
// We're not passing in a connection, because the contentGuid will be used instead.
|
||||
Control::TermControl control{ contentGuid, settings, nullptr };
|
||||
control.RaiseNotice([this](auto&&, auto& args) {
|
||||
_writeToLog(L"Content process died, probably.");
|
||||
_writeToLog(args.Message());
|
||||
OutOfProcContent().Children().Clear();
|
||||
GuidInput().Text(L"");
|
||||
if (piContentProcess.hProcess)
|
||||
{
|
||||
piContentProcess.reset();
|
||||
}
|
||||
});
|
||||
|
||||
Log().Children().Clear();
|
||||
OutOfProcContent().Children().Append(control);
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
namespace SampleApp
|
||||
{
|
||||
[default_interface] runtimeclass MyPage : Windows.UI.Xaml.Controls.Page, Windows.UI.Xaml.Data.INotifyPropertyChanged
|
||||
[default_interface] runtimeclass MyPage : Windows.UI.Xaml.Controls.Page
|
||||
{
|
||||
MyPage();
|
||||
}
|
||||
|
|
|
@ -7,7 +7,8 @@
|
|||
|
||||
namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
{
|
||||
ContentProcess::ContentProcess() {}
|
||||
ContentProcess::ContentProcess() :
|
||||
_ourPID{ GetCurrentProcessId() } {}
|
||||
|
||||
bool ContentProcess::Initialize(Control::IControlSettings settings,
|
||||
TerminalConnection::ConnectionInformation connectionInfo)
|
||||
|
@ -31,6 +32,11 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||
return _interactivity;
|
||||
}
|
||||
|
||||
uint64_t ContentProcess::GetPID()
|
||||
{
|
||||
return _ourPID;
|
||||
}
|
||||
|
||||
uint64_t ContentProcess::RequestSwapChainHandle(const uint64_t pid)
|
||||
{
|
||||
auto ourPid = GetCurrentProcessId();
|
||||
|
|
|
@ -17,12 +17,14 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||
TerminalConnection::ConnectionInformation connectionInfo);
|
||||
Control::ControlInteractivity GetInteractivity();
|
||||
|
||||
uint64_t GetPID();
|
||||
uint64_t RequestSwapChainHandle(const uint64_t pid);
|
||||
|
||||
WINRT_CALLBACK(Destructed, Control::DestructedArgs);
|
||||
|
||||
private:
|
||||
Control::ControlInteractivity _interactivity{ nullptr };
|
||||
uint64_t _ourPID;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -16,6 +16,8 @@ namespace Microsoft.Terminal.Control
|
|||
|
||||
ControlInteractivity GetInteractivity();
|
||||
|
||||
UInt64 GetPID();
|
||||
|
||||
UInt64 RequestSwapChainHandle(UInt64 pid);
|
||||
|
||||
event DestructedArgs Destructed;
|
||||
|
|
|
@ -75,6 +75,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||
if (_contentProc != nullptr)
|
||||
{
|
||||
_interactivity = _contentProc.GetInteractivity();
|
||||
_contentWaitInterrupt.create();
|
||||
_createContentWaitThread();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -167,6 +169,148 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||
_ApplyUISettings(_settings);
|
||||
}
|
||||
|
||||
bool s_waitOnContentProcess(uint64_t contentPid, HANDLE contentWaitInterrupt)
|
||||
{
|
||||
// This is the array of HANDLEs that we're going to wait on in
|
||||
// WaitForMultipleObjects below.
|
||||
// * waits[0] will be the handle to the monarch process. It gets
|
||||
// signalled when the process exits / dies.
|
||||
// * waits[1] is the handle to our _contentWaitInterrupt event. Another
|
||||
// thread can use that to manually break this loop. We'll do that when
|
||||
// we're getting torn down.
|
||||
HANDLE waits[2];
|
||||
waits[1] = contentWaitInterrupt;
|
||||
bool displayError = true;
|
||||
// bool exitThreadRequested = false;
|
||||
// while (!exitThreadRequested)
|
||||
// {
|
||||
// At any point in all this, the current monarch might die. If it
|
||||
// does, we'll go straight to a new election, in the "jail"
|
||||
// try/catch below. Worst case, eventually, we'll become the new
|
||||
// monarch.
|
||||
try
|
||||
{
|
||||
// This might fail to even ask the monarch for it's PID.
|
||||
wil::unique_handle hContent{ OpenProcess(PROCESS_ALL_ACCESS,
|
||||
FALSE,
|
||||
static_cast<DWORD>(contentPid)) };
|
||||
|
||||
// If we fail to open the content, then they don't exist
|
||||
// anymore! Go straight to an election.
|
||||
if (hContent.get() == nullptr)
|
||||
{
|
||||
const auto gle = GetLastError();
|
||||
TraceLoggingWrite(g_hTerminalControlProvider,
|
||||
"TermControl_FailedToOpenContent",
|
||||
// TraceLoggingUInt64(peasantID, "peasantID", "Our peasant ID"),
|
||||
TraceLoggingUInt64(gle, "lastError", "The result of GetLastError"),
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
|
||||
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
|
||||
|
||||
// exitThreadRequested = true;
|
||||
// continue;
|
||||
}
|
||||
|
||||
waits[0] = hContent.get();
|
||||
|
||||
switch (WaitForMultipleObjects(2, waits, FALSE, INFINITE))
|
||||
{
|
||||
case WAIT_OBJECT_0 + 0: // waits[0] was signaled, the handle to the monarch process
|
||||
|
||||
TraceLoggingWrite(g_hTerminalControlProvider,
|
||||
"TermControl_ContentDied",
|
||||
// TraceLoggingUInt64(peasantID, "peasantID", "Our peasant ID"),
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
|
||||
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
|
||||
// Connect to the new monarch, which might be us!
|
||||
// If we become the monarch, then we'll return true and exit this thread.
|
||||
// exitThreadRequested = true;
|
||||
break;
|
||||
|
||||
case WAIT_OBJECT_0 + 1: // waits[1] was signaled, our manual interrupt
|
||||
|
||||
TraceLoggingWrite(g_hTerminalControlProvider,
|
||||
"TermControl_ContentWaitInterrupted",
|
||||
// TraceLoggingUInt64(peasantID, "peasantID", "Our peasant ID"),
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
|
||||
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
|
||||
// exitThreadRequested = true;
|
||||
displayError = false;
|
||||
break;
|
||||
|
||||
case WAIT_TIMEOUT:
|
||||
// This should be impossible.
|
||||
TraceLoggingWrite(g_hTerminalControlProvider,
|
||||
"TermControl_ContentWaitTimeout",
|
||||
// TraceLoggingUInt64(peasantID, "peasantID", "Our peasant ID"),
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
|
||||
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
|
||||
// exitThreadRequested = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
{
|
||||
// TODO!
|
||||
// Returning any other value is invalid. Just die.
|
||||
const auto gle = GetLastError();
|
||||
TraceLoggingWrite(g_hTerminalControlProvider,
|
||||
"TermControl_WaitFailed",
|
||||
// TraceLoggingUInt64(peasantID, "peasantID", "Our peasant ID"),
|
||||
TraceLoggingUInt64(gle, "lastError", "The result of GetLastError"),
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
|
||||
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
|
||||
// exitThreadRequested = true;
|
||||
// ExitProcess(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
// Theoretically, if window[1] dies when we're trying to get
|
||||
// it's PID we'll get here. We can probably just exit here.
|
||||
|
||||
TraceLoggingWrite(g_hTerminalControlProvider,
|
||||
"TermControl_ExceptionInWaitThread",
|
||||
// TraceLoggingUInt64(peasantID, "peasantID", "Our peasant ID"),
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
|
||||
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
|
||||
// exitThreadRequested = true;
|
||||
}
|
||||
// }
|
||||
|
||||
// if (displayError)
|
||||
// {
|
||||
// }
|
||||
return displayError;
|
||||
}
|
||||
|
||||
void TermControl::_createContentWaitThread()
|
||||
{
|
||||
_contentWaitThread = std::thread([weakThis = get_weak(), contentPid = _contentProc.GetPID(), contentWaitInterrupt=_contentWaitInterrupt.get()] {
|
||||
if (s_waitOnContentProcess(contentPid, contentWaitInterrupt))
|
||||
{
|
||||
if (auto control{ weakThis.get() })
|
||||
{
|
||||
control->_contentWaitThread.detach();
|
||||
control->_raiseContentDied();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
winrt::fire_and_forget TermControl::_raiseContentDied()
|
||||
{
|
||||
auto weakThis{ get_weak() };
|
||||
co_await winrt::resume_foreground(Dispatcher());
|
||||
|
||||
if (auto control{ weakThis.get() })
|
||||
{
|
||||
// dialog the thing
|
||||
auto noticeArgs = winrt::make<NoticeEventArgs>(NoticeLevel::Error, L"The content of this terminal died unexpectedly.");
|
||||
control->_RaiseNoticeHandlers(*control, noticeArgs);
|
||||
}
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Loads the search box from the xaml UI and focuses it.
|
||||
void TermControl::CreateSearchBoxControl()
|
||||
|
|
|
@ -185,6 +185,11 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||
|
||||
winrt::Windows::UI::Xaml::Controls::SwapChainPanel::LayoutUpdated_revoker _layoutUpdatedRevoker;
|
||||
|
||||
wil::unique_event _contentWaitInterrupt;
|
||||
std::thread _contentWaitThread;
|
||||
void _createContentWaitThread();
|
||||
// void _waitOnContentProcess();
|
||||
|
||||
inline bool _IsClosing() const noexcept
|
||||
{
|
||||
// _closing isn't atomic and may only be accessed from the main thread.
|
||||
|
@ -267,6 +272,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||
winrt::fire_and_forget _coreTransparencyChanged(IInspectable sender, Control::TransparencyChangedEventArgs args);
|
||||
void _coreRaisedNotice(const IInspectable& s, const Control::NoticeEventArgs& args);
|
||||
void _coreWarningBell(const IInspectable& sender, const IInspectable& args);
|
||||
winrt::fire_and_forget _raiseContentDied();
|
||||
};
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue