Repository: microsoft/terminal
File: src/host/ft_host/API_MultipleInflightMessageTests.cpp (C++)

Code before:
        DWORD originalConsoleMode{};
        VERIFY_WIN32_BOOL_SUCCEEDED(GetConsoleMode(inputHandle, &originalConsoleMode));
        auto restoreMode{ wil::scope_exit([=]() {
            SetConsoleMode(inputHandle, originalConsoleMode);
        }) };
        VERIFY_WIN32_BOOL_SUCCEEDED(SetConsoleMode(inputHandle, ENABLE_ECHO_INPUT | ENABLE_LINE_INPUT));

        // Prime the console with some fake input records.
        const std::array<INPUT_RECORD, 4> inputRecords{
            INPUT_RECORD{ KEY_EVENT, KEY_EVENT_RECORD{ TRUE, 1, 'h', 0, L'h', 0 } },
            INPUT_RECORD{ KEY_EVENT, KEY_EVENT_RECORD{ FALSE, 1, 'h', 0, L'h', 0 } },
            INPUT_RECORD{ KEY_EVENT, KEY_EVENT_RECORD{ TRUE, 1, 'i', 0, L'i', 0 } },
            INPUT_RECORD{ KEY_EVENT, KEY_EVENT_RECORD{ FALSE, 1, 'i', 0, L'i', 0 } },
        };
        DWORD written{};
        VERIFY_WIN32_BOOL_SUCCEEDED(WriteConsoleInput(inputHandle, inputRecords.data(), static_cast<DWORD>(inputRecords.size()), &written));
        VERIFY_ARE_EQUAL(inputRecords.size(), written);

        // !!! LOAD BEARING !!!
        // This buffer needs to be large enough to force API_MSG to heap allocate (!)
        std::array<wchar_t, 129> buffer;
        DWORD read{};

        bool readerThreadLaunched{ false };
        std::condition_variable readerThreadLaunchCV;
        std::mutex readerThreadLaunchMutex;
        std::thread readerThread{ [&]() {
            WEX::TestExecution::DisableVerifyExceptions disableVerifyExceptions{};
            {
                std::scoped_lock lock{ readerThreadLaunchMutex };
                readerThreadLaunched = true;
            }
            readerThreadLaunchCV.notify_all();
            VERIFY_WIN32_BOOL_SUCCEEDED(ReadConsoleW(inputHandle, buffer.data(), static_cast<DWORD>(buffer.size()), &read, nullptr));
        } };

        {
            std::unique_lock lock{ readerThreadLaunchMutex };
            readerThreadLaunchCV.wait(lock, [&]() { return readerThreadLaunched; });
            // should not progress until readerThreadLaunched is set.
        }
        Sleep(50); // Yeah, it's not science.

        std::thread writerThread{ [&]() {
            WEX::TestExecution::DisableVerifyExceptions disableVerifyExceptions{};
            DWORD temp{};
            // !!! LOAD BEARING !!!
            // This buffer must be large enough to trigger a *re-allocation* in the API message handler.
            std::array<wchar_t, 4096> anEvenLargerBuffer;
            VERIFY_WIN32_BOOL_SUCCEEDED(ReadConsoleOutputCharacterW(outputHandle, anEvenLargerBuffer.data(), static_cast<DWORD>(anEvenLargerBuffer.size()), COORD{ 1, 1 }, &temp)); // has payload (output buffer)
            VERIFY_ARE_EQUAL(4096u, temp);

Review comment (suggestion):
FYI: You can build yourself a super simple barrier:
```cpp
struct latch
{
    explicit latch(int slots)
    {
        InitializeSynchronizationBarrier(&_barrier, slots, -1);
    }

    ~latch()
    {
        DeleteSynchronizationBarrier(&_barrier);
    }

    void arrive_and_wait()
    {
        EnterSynchronizationBarrier(&_barrier, 0);
    }

private:
    SYNCHRONIZATION_BARRIER _barrier{};
};
```

I also uploaded a full std::latch, that I built a while ago: https://gist.github.com/lhecker/f12f9e9fa3a60ab71f44314c7df74da6

Code after:

        DWORD originalConsoleMode{};
        VERIFY_WIN32_BOOL_SUCCEEDED(GetConsoleMode(inputHandle, &originalConsoleMode));
        auto restoreMode{ wil::scope_exit([=]() {
            SetConsoleMode(inputHandle, originalConsoleMode);
        }) };
        VERIFY_WIN32_BOOL_SUCCEEDED(SetConsoleMode(inputHandle, ENABLE_ECHO_INPUT | ENABLE_LINE_INPUT));

        // Prime the console with some fake input records.
        const std::array<INPUT_RECORD, 4> inputRecords{
            INPUT_RECORD{ KEY_EVENT, KEY_EVENT_RECORD{ TRUE, 1, 'h', 0, L'h', 0 } },
            INPUT_RECORD{ KEY_EVENT, KEY_EVENT_RECORD{ FALSE, 1, 'h', 0, L'h', 0 } },
            INPUT_RECORD{ KEY_EVENT, KEY_EVENT_RECORD{ TRUE, 1, 'i', 0, L'i', 0 } },
            INPUT_RECORD{ KEY_EVENT, KEY_EVENT_RECORD{ FALSE, 1, 'i', 0, L'i', 0 } },
        };
        DWORD written{};
        VERIFY_WIN32_BOOL_SUCCEEDED(WriteConsoleInput(inputHandle, inputRecords.data(), static_cast<DWORD>(inputRecords.size()), &written));
        VERIFY_ARE_EQUAL(inputRecords.size(), written);

        // !!! LOAD BEARING !!!
        // This buffer needs to be large enough to force API_MSG to heap allocate (!)
        std::array<wchar_t, 129> buffer;
        DWORD read{};

        bool readerThreadLaunched{ false };
        std::condition_variable readerThreadLaunchCV;
        std::mutex readerThreadLaunchMutex;

        std::unique_lock lock{ readerThreadLaunchMutex };

        std::thread readerThread{ [&]() {
            WEX::TestExecution::DisableVerifyExceptions disableVerifyExceptions{};
            {
                std::scoped_lock lock{ readerThreadLaunchMutex };
                readerThreadLaunched = true;
            }
            readerThreadLaunchCV.notify_all();
            VERIFY_WIN32_BOOL_SUCCEEDED(ReadConsoleW(inputHandle, buffer.data(), static_cast<DWORD>(buffer.size()), &read, nullptr));
        } };

        // CV wait should allow readerThread to progress
        readerThreadLaunchCV.wait(lock, [&]() { return readerThreadLaunched; });
        // should not progress until readerThreadLaunched is set.
        Sleep(50); // Yeah, it's not science.

        std::thread writerThread{ [&]() {
            WEX::TestExecution::DisableVerifyExceptions disableVerifyExceptions{};
            DWORD temp{};
            // !!! LOAD BEARING !!!
            // This buffer must be large enough to trigger a *re-allocation* in the API message handler.
            std::array<wchar_t, 4096> anEvenLargerBuffer;