Repository: microsoft/terminal
File: src/interactivity/base/ServiceLocator.cpp (C++)

Code before:
#pragma region Public Methods

void ServiceLocator::SetOneCoreTeardownFunction(void (*pfn)()) noexcept
{
    FAIL_FAST_IF(nullptr != s_oneCoreTeardownFunction);
    s_oneCoreTeardownFunction = pfn;
}

void ServiceLocator::RundownAndExit(const HRESULT hr)
{
    static std::atomic<bool> locked;

    // MSFT:40146639
    //   The premise of this function is that 1 thread enters and 0 threads leave alive.
    //   We need to prevent anyone from calling us until we actually ExitProcess(),
    //   so that we don't TriggerTeardown() twice. LockConsole() can't be used here,
    //   because doing so would prevent the render thread from progressing.
    if (locked.exchange(true, std::memory_order_relaxed))
    {
        // Don't sleep forever with the console lock being held or otherwise
        // no one can acquire it while we shut down.
        const auto& gci = s_globals.getConsoleInformation();
        while (gci.IsConsoleLocked())
        {
            gci.UnlockConsole();
        }

        // If we reach this point, another thread is already in the process of exiting.
        // There's a lot of ways to suspend ourselves until we exit, one of which is "sleep forever".
        Sleep(INFINITE);
    }

    // MSFT:15506250
    // In VT I/O Mode, a client application might die before we've rendered
    //      the last bit of text they've emitted. So give the VtRenderer one
    //      last chance to paint before it is killed.
    if (s_globals.pRender)
    {
        s_globals.pRender->TriggerTeardown();
    }

    // MSFT:40226902 - HOTFIX shutdown on OneCore, by leaking the renderer, thereby
    // reducing the change for existing race conditions to turn into deadlocks.
#ifndef NDEBUG
    // By locking the console, we ensure no background tasks are accessing the
    // classes we're going to destruct down below (for instance: CursorBlinker).
    s_globals.getConsoleInformation().LockConsole();
#endif

    // A History Lesson from MSFT: 13576341:
    // We introduced RundownAndExit to give services that hold onto important handles

Review comment (suggestion):
I put this in as a safety measure so that `CloseConsoleProcessState()` works correctly even if the console lock was acquired. Do you think I should call the global `UnlockConsole()` instead so that this optionally calls `ProcessCtrlEvents`? I was hoping that this wouldn't be important given that this would be at least the second thread to enter `RundownAndExit`...

Code after:
wil::unique_hwnd ServiceLocator::s_pseudoWindow = nullptr;

#pragma endregion

#pragma region Public Methods

void ServiceLocator::SetOneCoreTeardownFunction(void (*pfn)()) noexcept
{
    FAIL_FAST_IF(nullptr != s_oneCoreTeardownFunction);
    s_oneCoreTeardownFunction = pfn;
}

void ServiceLocator::RundownAndExit(const HRESULT hr)
{
    // The TriggerTeardown() call below depends on the render thread being able to acquire the
    // console lock, so that it can safely progress with flushing the last frame. Since there's no
    // coming back from this function (it's [[noreturn]]), it's safe to unlock the console here.
    auto& gci = s_globals.getConsoleInformation();
    while (gci.IsConsoleLocked())
    {
        gci.UnlockConsole();
    }

    // MSFT:40146639
    //   The premise of this function is that 1 thread enters and 0 threads leave alive.
    //   We need to prevent anyone from calling us until we actually ExitProcess(),
    //   so that we don't TriggerTeardown() twice. LockConsole() can't be used here,
    //   because doing so would prevent the render thread from progressing.
    static std::atomic<bool> locked;
    if (locked.exchange(true, std::memory_order_relaxed))
    {
        // If we reach this point, another thread is already in the process of exiting.
        // There's a lot of ways to suspend ourselves until we exit, one of which is "sleep forever".
        Sleep(INFINITE);
    }

    // MSFT:15506250
    // In VT I/O Mode, a client application might die before we've rendered
    //      the last bit of text they've emitted. So give the VtRenderer one
    //      last chance to paint before it is killed.
    if (s_globals.pRender)
    {
        s_globals.pRender->TriggerTeardown();
    }

    // MSFT:40226902 - HOTFIX shutdown on OneCore, by leaking the renderer, thereby
    // reducing the change for existing race conditions to turn into deadlocks.
#ifndef NDEBUG
    // By locking the console, we ensure no background tasks are accessing the
    // classes we're going to destruct down below (for instance: CursorBlinker).
    s_globals.getConsoleInformation().LockConsole();