mirror of
https://github.com/microsoft/terminal.git
synced 2025-12-10 00:48:23 -06:00
The conhost v2 rewrite from a decade ago introduced a race condition: Previously, we would acquire and hold the global console lock while servicing a console API call. If the call cannot be completed a wait task is enqueued, while the lock is held. The v2 rewrite then split the project up into a "server" and "host" component (which remain to this day). The "host" would hold the console lock, while the "server" was responsible for enqueueing wait tasks _outside of the console lock_. Without any form of synchronization, any operations on the waiter list would then of course introduce a race condition. In conhost this primarily meant keyboard/mouse input, because that runs on the separate Win32 window thread. For Windows Terminal it primarily meant the VT input thread. I do not know why this issue is so extremely noticeable specifically when we respond to DSC CPR requests, but I'm also not surprised: I suspect that the overall performance issues that conhost had for a long time, meant that most things it did were slower than allocating the wait task. Now that both conhost and Windows Terminal became orders of magnitudes faster over the last few years, it probably just so happens that the DSC CPR request takes almost exactly as many cycles to complete as allocating the wait task does, hence perfectly reproducing the race condition. There's also a slight chance that this is actually a regression from my ConPTY rewrite #17510, but I fail to see what that would be. Regardless of that, I'm 100% certain though, that this is a bug that has existed in v0.1. Closes #18117 Closes #18800 ## Validation Steps Performed * See repro in #18800. In other words: * Continuously emit DSC CPR sequences * ...read the response from stdin * ...and print the response to stdout * Doesn't deadlock randomly anymore ✅ * Feature & Unit tests ✅ (cherry picked from commit 29924217615d58940d8309bec49476fa9dd2fb6b) Service-Card-Id: PVTI_lADOAF3p4s4AxadtzgZiUlo Service-Version: 1.23
176 lines
6.3 KiB
C++
176 lines
6.3 KiB
C++
/*++
|
|
Copyright (c) Microsoft Corporation
|
|
Licensed under the MIT license.
|
|
|
|
Module Name:
|
|
- server.h
|
|
|
|
Abstract:
|
|
- This module contains the internal structures and definitions used by the console server.
|
|
|
|
Author:
|
|
- Therese Stowell (ThereseS) 12-Nov-1990
|
|
|
|
Revision History:
|
|
--*/
|
|
|
|
#pragma once
|
|
|
|
#include "CursorBlinker.hpp"
|
|
#include "IIoProvider.hpp"
|
|
#include "readDataCooked.hpp"
|
|
#include "settings.hpp"
|
|
#include "VtIo.hpp"
|
|
#include "../audio/midi/MidiAudio.hpp"
|
|
#include "../host/RenderData.hpp"
|
|
#include "../server/ProcessList.h"
|
|
#include "../server/WaitQueue.h"
|
|
|
|
#include <til/ticket_lock.h>
|
|
|
|
// clang-format off
|
|
// Flags flags
|
|
#define CONSOLE_IS_ICONIC 0x00000001
|
|
#define CONSOLE_OUTPUT_SUSPENDED 0x00000002
|
|
#define CONSOLE_HAS_FOCUS 0x00000004
|
|
#define CONSOLE_IGNORE_NEXT_MOUSE_INPUT 0x00000008
|
|
#define CONSOLE_SELECTING 0x00000010
|
|
#define CONSOLE_SCROLLING 0x00000020
|
|
// unused (CONSOLE_DISABLE_CLOSE) 0x00000040
|
|
// unused (CONSOLE_USE_POLY_TEXT) 0x00000080
|
|
|
|
// Removed Oct 2017 - added a headless mode, which revealed that the consumption
|
|
// of this flag was redundant.
|
|
// unused (CONSOLE_NO_WINDOW) 0x00000100
|
|
|
|
// unused (CONSOLE_VDM_REGISTERED) 0x00000200
|
|
#define CONSOLE_UPDATING_SCROLL_BARS 0x00000400
|
|
#define CONSOLE_QUICK_EDIT_MODE 0x00000800
|
|
#define CONSOLE_CONNECTED_TO_EMULATOR 0x00002000
|
|
// unused (CONSOLE_FULLSCREEN_NOPAINT) 0x00004000
|
|
#define CONSOLE_QUIT_POSTED 0x00008000
|
|
#define CONSOLE_AUTO_POSITION 0x00010000
|
|
#define CONSOLE_IGNORE_NEXT_KEYUP 0x00020000
|
|
// unused (CONSOLE_WOW_REGISTERED) 0x00040000
|
|
#define CONSOLE_HISTORY_NODUP 0x00100000
|
|
#define CONSOLE_SCROLLBAR_TRACKING 0x00200000
|
|
#define CONSOLE_SETTING_WINDOW_SIZE 0x00800000
|
|
// unused (CONSOLE_VDM_HIDDEN_WINDOW) 0x01000000
|
|
// unused (CONSOLE_OS2_REGISTERED) 0x02000000
|
|
// unused (CONSOLE_OS2_OEM_FORMAT) 0x04000000
|
|
// unused (CONSOLE_JUST_VDM_UNREGISTERED) 0x08000000
|
|
// unused (CONSOLE_FULLSCREEN_INITIALIZED) 0x10000000
|
|
#define CONSOLE_USE_PRIVATE_FLAGS 0x20000000
|
|
// unused (CONSOLE_TSF_ACTIVATED) 0x40000000
|
|
#define CONSOLE_INITIALIZED 0x80000000
|
|
|
|
#define CONSOLE_SUSPENDED (CONSOLE_OUTPUT_SUSPENDED)
|
|
// clang-format on
|
|
|
|
class COOKED_READ_DATA;
|
|
class CommandHistory;
|
|
|
|
class CONSOLE_INFORMATION :
|
|
public Settings,
|
|
public Microsoft::Console::IIoProvider
|
|
{
|
|
public:
|
|
CONSOLE_INFORMATION() = default;
|
|
CONSOLE_INFORMATION(const CONSOLE_INFORMATION& c) = delete;
|
|
CONSOLE_INFORMATION& operator=(const CONSOLE_INFORMATION& c) = delete;
|
|
|
|
ConsoleProcessList ProcessHandleList;
|
|
InputBuffer* pInputBuffer = nullptr;
|
|
|
|
SCREEN_INFORMATION* ScreenBuffers = nullptr; // singly linked list
|
|
ConsoleWaitQueue OutputQueue;
|
|
|
|
DWORD Flags = 0;
|
|
|
|
// the following fields are used for ansi-unicode translation
|
|
UINT CP = 0;
|
|
UINT OutputCP = 0;
|
|
// the VT RIS sequence uses these default values to reset the code pages
|
|
UINT DefaultCP = 0;
|
|
UINT DefaultOutputCP = 0;
|
|
|
|
ULONG CtrlFlags = 0; // indicates outstanding ctrl requests
|
|
ULONG LimitingProcessId = 0;
|
|
|
|
CPINFO CPInfo = {};
|
|
CPINFO OutputCPInfo = {};
|
|
|
|
void LockConsole() noexcept;
|
|
void UnlockConsole() noexcept;
|
|
til::recursive_ticket_lock_suspension SuspendLock() noexcept;
|
|
bool IsConsoleLocked() const noexcept;
|
|
ULONG GetCSRecursionCount() const noexcept;
|
|
|
|
Microsoft::Console::VirtualTerminal::VtIo* GetVtIo() noexcept;
|
|
Microsoft::Console::VirtualTerminal::VtIo::Writer GetVtWriter() noexcept;
|
|
Microsoft::Console::VirtualTerminal::VtIo::Writer GetVtWriterForBuffer(const SCREEN_INFORMATION* context) noexcept;
|
|
bool IsInVtIoMode() const noexcept;
|
|
|
|
SCREEN_INFORMATION& GetActiveOutputBuffer() override;
|
|
const SCREEN_INFORMATION& GetActiveOutputBuffer() const override;
|
|
void SetActiveOutputBuffer(SCREEN_INFORMATION& screenBuffer);
|
|
bool HasActiveOutputBuffer() const;
|
|
|
|
InputBuffer* const GetActiveInputBuffer() const override;
|
|
|
|
bool HasPendingCookedRead() const noexcept;
|
|
bool HasPendingPopup() const noexcept;
|
|
const COOKED_READ_DATA& CookedReadData() const noexcept;
|
|
COOKED_READ_DATA& CookedReadData() noexcept;
|
|
void SetCookedReadData(COOKED_READ_DATA* readData) noexcept;
|
|
|
|
bool GetBracketedPasteMode() const noexcept;
|
|
void SetBracketedPasteMode(const bool enabled) noexcept;
|
|
|
|
void SetTitle(const std::wstring_view newTitle);
|
|
void SetTitlePrefix(const std::wstring_view newTitlePrefix);
|
|
void SetOriginalTitle(const std::wstring_view originalTitle);
|
|
void SetLinkTitle(const std::wstring_view linkTitle);
|
|
const std::wstring_view GetTitle() const noexcept;
|
|
const std::wstring_view GetOriginalTitle() const noexcept;
|
|
const std::wstring_view GetLinkTitle() const noexcept;
|
|
const std::wstring_view GetTitleAndPrefix() const;
|
|
|
|
[[nodiscard]] static NTSTATUS AllocateConsole(const std::wstring_view title);
|
|
// MSFT:16886775 : get rid of friends
|
|
friend void SetActiveScreenBuffer(_Inout_ SCREEN_INFORMATION& screenInfo);
|
|
friend class SCREEN_INFORMATION;
|
|
friend class CommonState;
|
|
Microsoft::Console::CursorBlinker& GetCursorBlinker() noexcept;
|
|
|
|
MidiAudio& GetMidiAudio();
|
|
|
|
CHAR_INFO AsCharInfo(const OutputCellView& cell) const noexcept;
|
|
|
|
RenderData renderData;
|
|
|
|
private:
|
|
til::recursive_ticket_lock _lock;
|
|
|
|
std::wstring _Title;
|
|
std::wstring _Prefix; // Eg Select, Mark - things that we manually prepend to the title.
|
|
std::wstring _TitleAndPrefix;
|
|
std::wstring _OriginalTitle;
|
|
std::wstring _LinkTitle; // Path to .lnk file
|
|
SCREEN_INFORMATION* pCurrentScreenBuffer = nullptr;
|
|
COOKED_READ_DATA* _cookedReadData = nullptr; // non-ownership pointer
|
|
bool _bracketedPasteMode = false;
|
|
|
|
Microsoft::Console::VirtualTerminal::VtIo _vtIo;
|
|
Microsoft::Console::CursorBlinker _blinker;
|
|
MidiAudio _midiAudio;
|
|
};
|
|
|
|
#define CONSOLE_STATUS_WAIT ((HRESULT)0xC0030001)
|
|
#define CONSOLE_STATUS_READ_COMPLETE ((HRESULT)0xC0030002)
|
|
#define CONSOLE_STATUS_WAIT_NO_BLOCK ((HRESULT)0xC0030003)
|
|
|
|
#include "../server/ObjectHandle.h"
|
|
|
|
void SetActiveScreenBuffer(SCREEN_INFORMATION& screenInfo);
|