terminal/src/server/WaitQueue.cpp
N d09fdd61cb
Change backslashes in include statements to forward slashes (#8205)
Many include statements use forward slashes, while others use backwards
slashes. This is inconsistent formatting. For this reason, I changed the
backward slashes to forward slashes since that is the standard.
2020-11-25 21:02:10 +00:00

127 lines
4.6 KiB
C++

// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#include "precomp.h"
#include "WaitQueue.h"
#include "WaitBlock.h"
#include "../host/globals.h"
#include "../host/utils.hpp"
// Routine Description:
// - Instantiates a new ConsoleWaitQueue
ConsoleWaitQueue::ConsoleWaitQueue() :
_blocks()
{
}
// Routine Description:
// - Destructs a ConsoleWaitQueue
// - This will notify any remaining waiting items that the associated process/object is dying.
ConsoleWaitQueue::~ConsoleWaitQueue()
{
// Notify all blocks that the thread or object is dying when destroyed.
NotifyWaiters(TRUE, WaitTerminationReason::ThreadDying);
}
// Routine Description:
// - Establishes a wait (call me back later) for a particular message with a given callback routine and its parameter
// Arguments:
// - pWaitReplyMessage - The API message that we're deferring until data is available later.
// - pWaiter - The context/callback information to restore and dispatch the call later.
// Return Value:
// - S_OK if enqueued appropriately and everything is alright. Or suitable HRESULT failure otherwise.
[[nodiscard]] HRESULT ConsoleWaitQueue::s_CreateWait(_Inout_ CONSOLE_API_MSG* const pWaitReplyMessage,
_In_ IWaitRoutine* const pWaiter)
{
// Normally we'd have the Wait Queue handle the insertion of the block into the queue, but
// the console does queues in a somewhat special way.
//
// Each block belongs in two queues:
// 1. The process queue of the client that dispatched the request
// 2. The object queue that the request will be serviced by
// As such, when a wait occurs, it gets added to both queues.
//
// It will end up being serviced by one or the other queue, but when it is serviced, it must be
// removed from both so it is not double processed.
//
// Therefore, I've inverted the queue management responsibility into the WaitBlock itself
// and made it a friend to this WaitQueue class.
return ConsoleWaitBlock::s_CreateWait(pWaitReplyMessage,
pWaiter);
}
// Routine Description:
// - Instructs this queue to attempt to callback waiting requests
// Arguments:
// - fNotifyAll - If true, we will notify all items in the queue. If false, we will only notify the first item.
// Return Value:
// - True if any block was successfully notified. False if no blocks were successful.
bool ConsoleWaitQueue::NotifyWaiters(const bool fNotifyAll)
{
return NotifyWaiters(fNotifyAll, WaitTerminationReason::NoReason);
}
// Routine Description:
// - Instructs this queue to attempt to callback waiting requests and request termination with the given reason
// Arguments:
// - fNotifyAll - If true, we will notify all items in the queue. If false, we will only notify the first item.
// - TerminationReason - A reason/message to pass to each waiter signaling it should terminate appropriately.
// Return Value:
// - True if any block was successfully notified. False if no blocks were successful.
bool ConsoleWaitQueue::NotifyWaiters(const bool fNotifyAll,
const WaitTerminationReason TerminationReason)
{
bool fResult = false;
auto it = _blocks.cbegin();
while (!_blocks.empty() && it != _blocks.cend())
{
ConsoleWaitBlock* const WaitBlock = (*it);
if (nullptr == WaitBlock)
{
break;
}
auto const nextIt = std::next(it); // we have to capture next before it is potentially erased
if (_NotifyBlock(WaitBlock, TerminationReason))
{
fResult = true;
}
if (!fNotifyAll)
{
break;
}
it = nextIt;
}
return fResult;
}
// Routine Description:
// - A helper to delete successfully notified callbacks
// Arguments:
// - pWaitBlock - A block containing callback data
// - TerminationReason - Optional reason to tell the callback to terminate. If 0, we're not requesting termination.
// Return Value:
// - True if callback successfully delivered data. False if callback still needs to wait longer.
bool ConsoleWaitQueue::_NotifyBlock(_In_ ConsoleWaitBlock* pWaitBlock,
_In_ WaitTerminationReason TerminationReason)
{
// Attempt to notify block with the given reason.
bool const fResult = pWaitBlock->Notify(TerminationReason);
if (fResult)
{
// If it was successful, delete it. (It will remove itself from appropriate queues.)
delete pWaitBlock;
}
return fResult;
}