it's hard to believe he's gone / were it so easy
This commit is contained in:
parent
e1402d834f
commit
f978a9c52c
|
@ -66,6 +66,9 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
|||
// TODO:projects/5 Wait on the peasant's PID, and remove them from the
|
||||
// map if they die. This won't work great in tests though, with fake
|
||||
// PIDs.
|
||||
//
|
||||
// We should trigger a callback. The manager will use this callback as
|
||||
// an opportunity to start waiting on the new peasant.
|
||||
|
||||
return newPeasantsId;
|
||||
}
|
||||
|
@ -99,8 +102,20 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
|||
// - the peasant if it exists in our map, otherwise null
|
||||
Remoting::IPeasant Monarch::_getPeasant(uint64_t peasantID)
|
||||
{
|
||||
auto peasantSearch = _peasants.find(peasantID);
|
||||
return peasantSearch == _peasants.end() ? nullptr : peasantSearch->second;
|
||||
try
|
||||
{
|
||||
auto peasantSearch = _peasants.find(peasantID);
|
||||
auto maybeThePeasant = peasantSearch == _peasants.end() ? nullptr : peasantSearch->second;
|
||||
maybeThePeasant.GetPID();
|
||||
return maybeThePeasant;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
LOG_CAUGHT_EXCEPTION();
|
||||
// TODO: Remove the peasant from the list of peasants
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void Monarch::_setMostRecentPeasant(const uint64_t peasantID)
|
||||
|
|
|
@ -16,11 +16,16 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
|||
WindowManager::WindowManager()
|
||||
{
|
||||
_monarchWaitInterrupt.create();
|
||||
// _peasantListenerInterrupt.create();
|
||||
|
||||
// wil::unique_event peasantListenerInterrupt;
|
||||
// peasantListenerInterrupt.create();
|
||||
// _peasantHandles.emplace_back(std::move(peasantListenerInterrupt));
|
||||
|
||||
// Register with COM as a server for the Monarch class
|
||||
_registerAsMonarch();
|
||||
// Instantiate an instance of the Monarch. This may or may not be in-proc!
|
||||
_createMonarch();
|
||||
_createMonarchAndCallbacks();
|
||||
}
|
||||
|
||||
WindowManager::~WindowManager()
|
||||
|
@ -32,10 +37,15 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
|||
CoRevokeClassObject(_registrationHostClass);
|
||||
_registrationHostClass = 0;
|
||||
_monarchWaitInterrupt.SetEvent();
|
||||
// _peasantListenerInterrupt.SetEvent();
|
||||
if (_electionThread.joinable())
|
||||
{
|
||||
_electionThread.join();
|
||||
}
|
||||
// if (_peasantListenerThread.joinable())
|
||||
// {
|
||||
// _peasantListenerThread.join();
|
||||
// }
|
||||
}
|
||||
|
||||
void WindowManager::ProposeCommandline(const Remoting::CommandlineArgs& args)
|
||||
|
@ -93,6 +103,35 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
|||
CLSCTX_LOCAL_SERVER);
|
||||
}
|
||||
|
||||
void WindowManager::_createMonarchAndCallbacks()
|
||||
{
|
||||
_createMonarch();
|
||||
const auto isKing = _areWeTheKing();
|
||||
if (!isKing)
|
||||
{
|
||||
return;
|
||||
}
|
||||
// Here, we're the king!
|
||||
|
||||
// TODO:MG Add an even handler to the monarch's PeasantAdded event.
|
||||
// We'll use that callback as a chance to start waiting on the peasant's
|
||||
// PID. If they die, we'll tell the monarch to remove them from the
|
||||
// list.
|
||||
// _peasantHandles.emplace_back(_peasantListenerInterrupt.get());
|
||||
|
||||
// _peasantListenerThread = std::thread([this]() {
|
||||
|
||||
// bool exitRequested = false;
|
||||
// while (!exitRequested)
|
||||
// {
|
||||
// }
|
||||
// });
|
||||
|
||||
// Wait, don't. Let's just have the monarch try/catch any accesses to
|
||||
// peasants. If the peasant dies, then it can't get the peasant's
|
||||
// anything. In that case, _remove it_.
|
||||
}
|
||||
|
||||
bool WindowManager::_areWeTheKing()
|
||||
{
|
||||
auto kingPID = _monarch.GetPID();
|
||||
|
@ -111,7 +150,7 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
|||
|
||||
bool WindowManager::_electionNight2020()
|
||||
{
|
||||
_createMonarch();
|
||||
_createMonarchAndCallbacks();
|
||||
if (_areWeTheKing())
|
||||
{
|
||||
return true;
|
||||
|
@ -134,7 +173,9 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
|||
while (!exitRequested)
|
||||
{
|
||||
wil::unique_handle hMonarch{ OpenProcess(PROCESS_ALL_ACCESS, FALSE, static_cast<DWORD>(_monarch.GetPID())) };
|
||||
// TODO:MG
|
||||
// TODO:MG If we fail to open the monarch, then they don't exist
|
||||
// anymore! Go straight to an election.
|
||||
//
|
||||
// if (hMonarch.get() == nullptr)
|
||||
// {
|
||||
// const auto gle = GetLastError();
|
||||
|
@ -146,11 +187,8 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
|||
switch (waitResult)
|
||||
{
|
||||
case WAIT_OBJECT_0 + 0: // waits[0] was signaled
|
||||
// printf("THE KING IS \x1b[31mDEAD\x1b[m\n");
|
||||
// // Return false here - this will trigger us to find the new monarch
|
||||
// return false;
|
||||
//
|
||||
// TODO:MG Connect to the new monarch, which might be us!
|
||||
// Connect to the new monarch, which might be us!
|
||||
// If we become the monarch, then we'll return true and exit this thread.
|
||||
exitRequested = _electionNight2020();
|
||||
break;
|
||||
case WAIT_OBJECT_0 + 1: // waits[1] was signaled
|
||||
|
|
|
@ -24,10 +24,17 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
|||
winrt::Microsoft::Terminal::Remoting::Peasant _peasant{ nullptr };
|
||||
|
||||
wil::unique_event _monarchWaitInterrupt;
|
||||
// wil::unique_event _peasantListenerInterrupt;
|
||||
|
||||
std::thread _electionThread;
|
||||
// std::thread _peasantListenerThread;
|
||||
|
||||
// // NON-OWNING HANDLES
|
||||
// std::vector<HANDLE> _peasantHandles{};
|
||||
|
||||
void _registerAsMonarch();
|
||||
void _createMonarch();
|
||||
void _createMonarchAndCallbacks();
|
||||
bool _areWeTheKing();
|
||||
winrt::Microsoft::Terminal::Remoting::IPeasant _createOurPeasant();
|
||||
|
||||
|
|
|
@ -32,6 +32,22 @@ using namespace winrt::Microsoft::Terminal;
|
|||
|
||||
namespace RemotingUnitTests
|
||||
{
|
||||
// This is a silly helper struct.
|
||||
// It will always throw an hresult_error on any of it's methods.
|
||||
// In the tests, it's hard to emulate a peasant process being totally dead once the Monarch has captured a reference to it. Since everything's in-proc in the tests, we can't decrement the refcount in such a way that the monarch's reference will throw a catchable exception.
|
||||
// Instead, this class can be used to replace a peasant inside a Monarch, to emulate that peasant process dying. Any time the monarch tries to do something to this peasant, it'll throw an exception.
|
||||
struct DeadPeasant : implements<DeadPeasant, winrt::Microsoft::Terminal::Remoting::IPeasant>
|
||||
{
|
||||
DeadPeasant() = default;
|
||||
void AssignID(uint64_t /*id*/) { throw winrt::hresult_error{}; };
|
||||
uint64_t GetID() { throw winrt::hresult_error{}; };
|
||||
uint64_t GetPID() { throw winrt::hresult_error{}; };
|
||||
bool ExecuteCommandline(const winrt::Microsoft::Terminal::Remoting::CommandlineArgs& /*args*/) { throw winrt::hresult_error{}; }
|
||||
winrt::Microsoft::Terminal::Remoting::CommandlineArgs InitialArgs() { throw winrt::hresult_error{}; }
|
||||
TYPED_EVENT(WindowActivated, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
|
||||
TYPED_EVENT(ExecuteCommandlineRequested, winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Remoting::CommandlineArgs);
|
||||
};
|
||||
|
||||
class RemotingTests
|
||||
{
|
||||
BEGIN_TEST_CLASS(RemotingTests)
|
||||
|
@ -39,13 +55,34 @@ namespace RemotingUnitTests
|
|||
|
||||
TEST_METHOD(CreateMonarch);
|
||||
TEST_METHOD(CreatePeasant);
|
||||
TEST_METHOD(CreatePeasantWithNew);
|
||||
TEST_METHOD(AddPeasants);
|
||||
TEST_METHOD(GetPeasantsByID);
|
||||
TEST_METHOD(AddPeasantsToNewMonarch);
|
||||
TEST_METHOD(RemovePeasantFromMonarchWhenFreed);
|
||||
|
||||
TEST_CLASS_SETUP(ClassSetup)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
static void _killPeasant(const com_ptr<Remoting::implementation::Monarch>& m,
|
||||
const uint64_t peasantID);
|
||||
};
|
||||
|
||||
void RemotingTests::_killPeasant(const com_ptr<Remoting::implementation::Monarch>& m,
|
||||
const uint64_t peasantID)
|
||||
{
|
||||
if (peasantID <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
com_ptr<DeadPeasant> tombstone;
|
||||
tombstone.attach(new DeadPeasant());
|
||||
m->_peasants[peasantID] = *tombstone;
|
||||
}
|
||||
|
||||
void RemotingTests::CreateMonarch()
|
||||
{
|
||||
auto m1 = winrt::make_self<Remoting::implementation::Monarch>();
|
||||
|
@ -84,4 +121,175 @@ namespace RemotingUnitTests
|
|||
L"A Peasant with an explicit PID should use the one we provided");
|
||||
}
|
||||
|
||||
void RemotingTests::CreatePeasantWithNew()
|
||||
{
|
||||
Log::Comment(L"The same thing as the above test, but with `new` instead of insanity on the stack");
|
||||
|
||||
auto p1 = winrt::make_self<Remoting::implementation::Peasant>();
|
||||
VERIFY_IS_NOT_NULL(p1);
|
||||
VERIFY_ARE_EQUAL(GetCurrentProcessId(),
|
||||
p1->GetPID(),
|
||||
L"A Peasant without an explicit PID should use the current PID");
|
||||
|
||||
auto expectedFakePID = 2345u;
|
||||
|
||||
com_ptr<Remoting::implementation::Peasant> p2;
|
||||
VERIFY_IS_NULL(p2);
|
||||
p2.attach(new Remoting::implementation::Peasant(expectedFakePID));
|
||||
|
||||
VERIFY_IS_NOT_NULL(p2);
|
||||
VERIFY_ARE_EQUAL(expectedFakePID,
|
||||
p2->GetPID(),
|
||||
L"A Peasant with an explicit PID should use the one we provided");
|
||||
}
|
||||
|
||||
void RemotingTests::AddPeasants()
|
||||
{
|
||||
const auto monarch0PID = 12345u;
|
||||
const auto peasant1PID = 23456u;
|
||||
const auto peasant2PID = 34567u;
|
||||
|
||||
com_ptr<Remoting::implementation::Monarch> m0;
|
||||
m0.attach(new Remoting::implementation::Monarch(monarch0PID));
|
||||
|
||||
com_ptr<Remoting::implementation::Peasant> p1;
|
||||
p1.attach(new Remoting::implementation::Peasant(peasant1PID));
|
||||
|
||||
com_ptr<Remoting::implementation::Peasant> p2;
|
||||
p2.attach(new Remoting::implementation::Peasant(peasant2PID));
|
||||
|
||||
VERIFY_IS_NOT_NULL(m0);
|
||||
VERIFY_IS_NOT_NULL(p1);
|
||||
VERIFY_IS_NOT_NULL(p2);
|
||||
|
||||
VERIFY_ARE_EQUAL(0, p1->GetID());
|
||||
VERIFY_ARE_EQUAL(0, p2->GetID());
|
||||
|
||||
m0->AddPeasant(*p1);
|
||||
m0->AddPeasant(*p2);
|
||||
|
||||
VERIFY_ARE_EQUAL(1, p1->GetID());
|
||||
VERIFY_ARE_EQUAL(2, p2->GetID());
|
||||
}
|
||||
|
||||
void RemotingTests::GetPeasantsByID()
|
||||
{
|
||||
const auto monarch0PID = 12345u;
|
||||
const auto peasant1PID = 23456u;
|
||||
const auto peasant2PID = 34567u;
|
||||
|
||||
com_ptr<Remoting::implementation::Monarch> m0;
|
||||
m0.attach(new Remoting::implementation::Monarch(monarch0PID));
|
||||
|
||||
com_ptr<Remoting::implementation::Peasant> p1;
|
||||
p1.attach(new Remoting::implementation::Peasant(peasant1PID));
|
||||
|
||||
com_ptr<Remoting::implementation::Peasant> p2;
|
||||
p2.attach(new Remoting::implementation::Peasant(peasant2PID));
|
||||
|
||||
VERIFY_IS_NOT_NULL(m0);
|
||||
VERIFY_IS_NOT_NULL(p1);
|
||||
VERIFY_IS_NOT_NULL(p2);
|
||||
|
||||
VERIFY_ARE_EQUAL(0, p1->GetID());
|
||||
VERIFY_ARE_EQUAL(0, p2->GetID());
|
||||
|
||||
m0->AddPeasant(*p1);
|
||||
m0->AddPeasant(*p2);
|
||||
|
||||
VERIFY_ARE_EQUAL(1, p1->GetID());
|
||||
VERIFY_ARE_EQUAL(2, p2->GetID());
|
||||
|
||||
auto maybeP1 = m0->_getPeasant(1);
|
||||
VERIFY_IS_NOT_NULL(maybeP1);
|
||||
VERIFY_ARE_EQUAL(peasant1PID, maybeP1.GetPID());
|
||||
|
||||
auto maybeP2 = m0->_getPeasant(2);
|
||||
VERIFY_IS_NOT_NULL(maybeP2);
|
||||
VERIFY_ARE_EQUAL(peasant2PID, maybeP2.GetPID());
|
||||
}
|
||||
|
||||
void RemotingTests::AddPeasantsToNewMonarch()
|
||||
{
|
||||
const auto monarch0PID = 12345u;
|
||||
const auto peasant1PID = 23456u;
|
||||
const auto peasant2PID = 34567u;
|
||||
const auto monarch3PID = 45678u;
|
||||
|
||||
com_ptr<Remoting::implementation::Monarch> m0;
|
||||
m0.attach(new Remoting::implementation::Monarch(monarch0PID));
|
||||
|
||||
com_ptr<Remoting::implementation::Peasant> p1;
|
||||
p1.attach(new Remoting::implementation::Peasant(peasant1PID));
|
||||
|
||||
com_ptr<Remoting::implementation::Peasant> p2;
|
||||
p2.attach(new Remoting::implementation::Peasant(peasant2PID));
|
||||
|
||||
com_ptr<Remoting::implementation::Monarch> m3;
|
||||
m3.attach(new Remoting::implementation::Monarch(monarch3PID));
|
||||
|
||||
VERIFY_IS_NOT_NULL(m0);
|
||||
VERIFY_IS_NOT_NULL(p1);
|
||||
VERIFY_IS_NOT_NULL(p2);
|
||||
VERIFY_IS_NOT_NULL(m3);
|
||||
|
||||
VERIFY_ARE_EQUAL(0, p1->GetID());
|
||||
VERIFY_ARE_EQUAL(0, p2->GetID());
|
||||
|
||||
m0->AddPeasant(*p1);
|
||||
m0->AddPeasant(*p2);
|
||||
|
||||
VERIFY_ARE_EQUAL(1, p1->GetID());
|
||||
VERIFY_ARE_EQUAL(2, p2->GetID());
|
||||
|
||||
m3->AddPeasant(*p1);
|
||||
m3->AddPeasant(*p2);
|
||||
|
||||
VERIFY_ARE_EQUAL(1, p1->GetID());
|
||||
VERIFY_ARE_EQUAL(2, p2->GetID());
|
||||
}
|
||||
|
||||
void RemotingTests::RemovePeasantFromMonarchWhenFreed()
|
||||
{
|
||||
const auto monarch0PID = 12345u;
|
||||
const auto peasant1PID = 23456u;
|
||||
const auto peasant2PID = 34567u;
|
||||
|
||||
com_ptr<Remoting::implementation::Monarch> m0;
|
||||
m0.attach(new Remoting::implementation::Monarch(monarch0PID));
|
||||
|
||||
com_ptr<Remoting::implementation::Peasant> p1;
|
||||
p1.attach(new Remoting::implementation::Peasant(peasant1PID));
|
||||
|
||||
com_ptr<Remoting::implementation::Peasant> p2;
|
||||
p2.attach(new Remoting::implementation::Peasant(peasant2PID));
|
||||
|
||||
VERIFY_IS_NOT_NULL(m0);
|
||||
VERIFY_IS_NOT_NULL(p1);
|
||||
VERIFY_IS_NOT_NULL(p2);
|
||||
|
||||
VERIFY_ARE_EQUAL(0, p1->GetID());
|
||||
VERIFY_ARE_EQUAL(0, p2->GetID());
|
||||
|
||||
m0->AddPeasant(*p1);
|
||||
m0->AddPeasant(*p2);
|
||||
|
||||
VERIFY_ARE_EQUAL(1, p1->GetID());
|
||||
VERIFY_ARE_EQUAL(2, p2->GetID());
|
||||
|
||||
VERIFY_ARE_EQUAL(2u, m0->_peasants.size());
|
||||
|
||||
RemotingTests::_killPeasant(m0, p1->GetID());
|
||||
|
||||
auto maybeP2 = m0->_getPeasant(2);
|
||||
VERIFY_IS_NOT_NULL(maybeP2);
|
||||
VERIFY_ARE_EQUAL(peasant2PID, maybeP2.GetPID());
|
||||
|
||||
auto maybeP1 = m0->_getPeasant(1);
|
||||
// VERIFY_ARE_EQUAL(peasant1PID, maybeP1.GetPID());
|
||||
VERIFY_IS_NULL(maybeP1);
|
||||
|
||||
VERIFY_ARE_EQUAL(1u, m0->_peasants.size());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue