You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
806 lines
24 KiB
806 lines
24 KiB
// --------------------------------------------------------------------------
|
|
// Module Name: APIDispatcher.cpp
|
|
//
|
|
// Copyright (c) 1999-2000, Microsoft Corporation
|
|
//
|
|
// A class that handles API requests in the server on a separate thread. Each
|
|
// thread is dedicated to respond to a single client. This is acceptable for
|
|
// a lightweight server.
|
|
//
|
|
// History: 1999-11-07 vtan created
|
|
// 2000-08-25 vtan moved from Neptune to Whistler
|
|
// --------------------------------------------------------------------------
|
|
|
|
#include "StandardHeader.h"
|
|
#include "APIDispatcher.h"
|
|
|
|
#include "APIRequest.h"
|
|
#include "SingleThreadedExecution.h"
|
|
#include "StatusCode.h"
|
|
|
|
// --------------------------------------------------------------------------
|
|
// CAPIDispatcher::CAPIDispatcher
|
|
//
|
|
// Arguments: hClientProcess = HANDLE to the client process.
|
|
//
|
|
// Returns: <none>
|
|
//
|
|
// Purpose: Constructor for CAPIDispatcher. The handle to the client
|
|
// process is transferred to this object.
|
|
//
|
|
// History: 1999-11-07 vtan created
|
|
// 2000-08-25 vtan moved from Neptune to Whistler
|
|
// --------------------------------------------------------------------------
|
|
|
|
CAPIDispatcher::CAPIDispatcher (HANDLE hClientProcess) :
|
|
_hSection(NULL),
|
|
_pSection(NULL),
|
|
_hProcessClient(hClientProcess),
|
|
_hPort(NULL),
|
|
_fRequestsPending(false),
|
|
_fConnectionClosed(false),
|
|
_pAPIDispatchSync(NULL)
|
|
{
|
|
}
|
|
|
|
// --------------------------------------------------------------------------
|
|
// CAPIDispatcher::~CAPIDispatcher
|
|
//
|
|
// Arguments: <none>
|
|
//
|
|
// Returns: <none>
|
|
//
|
|
// Purpose: Destructor for CAPIDispatcher. Release the port handle if
|
|
// present. Release the process handle.
|
|
//
|
|
// History: 1999-11-07 vtan created
|
|
// 2000-08-25 vtan moved from Neptune to Whistler
|
|
// --------------------------------------------------------------------------
|
|
|
|
CAPIDispatcher::~CAPIDispatcher (void)
|
|
|
|
{
|
|
ASSERTMSG(_fConnectionClosed, "Destructor invoked without connection being closed in CAPIDispatcher::~CAPIDispatcher");
|
|
if (_pSection != NULL)
|
|
{
|
|
TBOOL(UnmapViewOfFile(_pSection));
|
|
_pSection = NULL;
|
|
}
|
|
ReleaseHandle(_hSection);
|
|
ReleaseHandle(_hPort);
|
|
ReleaseHandle(_hProcessClient);
|
|
}
|
|
|
|
// --------------------------------------------------------------------------
|
|
// CAPIDispatcher::GetClientProcess
|
|
//
|
|
// Arguments: <none>
|
|
//
|
|
// Returns: HANDLE
|
|
//
|
|
// Purpose: Returns the handle to the client process. This is not
|
|
// duplicated. DO NOT CLOSE THIS HANDLE.
|
|
//
|
|
// History: 1999-11-07 vtan created
|
|
// 2000-08-25 vtan moved from Neptune to Whistler
|
|
// --------------------------------------------------------------------------
|
|
|
|
HANDLE CAPIDispatcher::GetClientProcess (void) const
|
|
|
|
{
|
|
return(_hProcessClient);
|
|
}
|
|
|
|
// --------------------------------------------------------------------------
|
|
// CAPIDispatcher::GetClientSessionID
|
|
//
|
|
// Arguments: <none>
|
|
//
|
|
// Returns: DWORD
|
|
//
|
|
// Purpose: Returns the client session ID.
|
|
//
|
|
// History: 2000-11-11 vtan created
|
|
// --------------------------------------------------------------------------
|
|
|
|
DWORD CAPIDispatcher::GetClientSessionID (void) const
|
|
|
|
{
|
|
DWORD dwSessionID;
|
|
ULONG ulReturnLength;
|
|
PROCESS_SESSION_INFORMATION processSessionInformation;
|
|
|
|
if (NT_SUCCESS(NtQueryInformationProcess(_hProcessClient,
|
|
ProcessSessionInformation,
|
|
&processSessionInformation,
|
|
sizeof(processSessionInformation),
|
|
&ulReturnLength)))
|
|
{
|
|
dwSessionID = processSessionInformation.SessionId;
|
|
}
|
|
else
|
|
{
|
|
dwSessionID = 0;
|
|
}
|
|
return(dwSessionID);
|
|
}
|
|
|
|
// --------------------------------------------------------------------------
|
|
// CAPIDispatcher::SetPort
|
|
//
|
|
// Arguments: hPort = Reply port received from
|
|
// ntdll!NtAcceptConnectionPort.
|
|
//
|
|
// Returns: <none>
|
|
//
|
|
// Purpose: Sets the given port handle into this object. The handle
|
|
// ownership is transferred. Wait until the thread processing
|
|
// requests is ready before returning.
|
|
//
|
|
// History: 1999-11-07 vtan created
|
|
// 2000-08-25 vtan moved from Neptune to Whistler
|
|
// --------------------------------------------------------------------------
|
|
|
|
void CAPIDispatcher::SetPort (HANDLE hPort)
|
|
|
|
{
|
|
_hPort = hPort;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------
|
|
// CAPIDispatcher::GetSection
|
|
//
|
|
// Arguments: <none>
|
|
//
|
|
// Returns: HANDLE
|
|
//
|
|
// Purpose: Returns a handle to a section used to communicate large
|
|
// quantities of data from client to server. If the section has
|
|
// not been created then create it.
|
|
//
|
|
// History: 2000-10-10 vtan created
|
|
// --------------------------------------------------------------------------
|
|
|
|
HANDLE CAPIDispatcher::GetSection (void)
|
|
|
|
{
|
|
if (_hSection == NULL)
|
|
{
|
|
TSTATUS(CreateSection());
|
|
}
|
|
return(_hSection);
|
|
}
|
|
|
|
// --------------------------------------------------------------------------
|
|
// CAPIDispatcher::GetSectionAddress
|
|
//
|
|
// Arguments: <none>
|
|
//
|
|
// Returns: void*
|
|
//
|
|
// Purpose: Returns the mapped address of the section.
|
|
//
|
|
// History: 2000-10-10 vtan created
|
|
// --------------------------------------------------------------------------
|
|
|
|
void* CAPIDispatcher::GetSectionAddress (void) const
|
|
|
|
{
|
|
return(_pSection);
|
|
}
|
|
|
|
// --------------------------------------------------------------------------
|
|
// CAPIDispatcher::CloseConnection
|
|
//
|
|
// Arguments: <none>
|
|
//
|
|
// Returns: NTSTATUS
|
|
//
|
|
// Purpose: Sets the member variable indicating the dispatcher's port has
|
|
// been closed and that any pending requests are now invalid.
|
|
// The object is reference counted so if there are any pending
|
|
// requests they will release their reference when they're done.
|
|
// The caller of this function releases its reference.
|
|
//
|
|
// History: 1999-11-07 vtan created
|
|
// 2000-08-25 vtan moved from Neptune to Whistler
|
|
// 2000-11-08 vtan reference counted object
|
|
// --------------------------------------------------------------------------
|
|
|
|
NTSTATUS CAPIDispatcher::CloseConnection (void)
|
|
|
|
{
|
|
CSingleThreadedExecution requestsPendingLock(_lock);
|
|
|
|
_fConnectionClosed = true;
|
|
return(STATUS_SUCCESS);
|
|
}
|
|
|
|
// --------------------------------------------------------------------------
|
|
// CAPIDispatcher::QueueRequest
|
|
//
|
|
// Arguments: portMessage = CPortMessage of request.
|
|
//
|
|
// Returns: NTSTATUS
|
|
//
|
|
// Purpose: Checks if the connection has been closed. If closed then it
|
|
// rejects the request. Otherwise it queues it.
|
|
//
|
|
// History: 2000-12-02 vtan created
|
|
// 2002-03-21 scotthan Copy APIDispatchSync address,
|
|
// update count of queued requests
|
|
// --------------------------------------------------------------------------
|
|
|
|
NTSTATUS CAPIDispatcher::QueueRequest (const CPortMessage& portMessage, CAPIDispatchSync* pAPIDispatchSync)
|
|
|
|
{
|
|
NTSTATUS status;
|
|
|
|
if (_fConnectionClosed)
|
|
{
|
|
status = RejectRequest(portMessage, STATUS_PORT_DISCONNECTED);
|
|
}
|
|
else
|
|
{
|
|
// Note: we should receive one and the same CAPIDispatchSync address for the lifetime
|
|
// of this CAPIDispatcher instance. We do not own this pointer, but only maintain a copy.
|
|
#ifdef DEBUG
|
|
if( NULL == _pAPIDispatchSync )
|
|
{
|
|
#endif DEBUG
|
|
|
|
_pAPIDispatchSync = pAPIDispatchSync;
|
|
|
|
#ifdef DEBUG
|
|
}
|
|
else
|
|
{
|
|
ASSERTBREAKMSG(pAPIDispatchSync == _pAPIDispatchSync, "CAPIDispatcher::QueueRequest - invalid APIDispatchSync");
|
|
}
|
|
#endif DEBUG
|
|
|
|
// track this request queue.
|
|
CAPIDispatchSync::DispatchEnter(_pAPIDispatchSync);
|
|
|
|
status = CreateAndQueueRequest(portMessage);
|
|
|
|
// on failure to queue the request, remove counter reference.
|
|
if( !NT_SUCCESS(status) )
|
|
{
|
|
CAPIDispatchSync::DispatchLeave(_pAPIDispatchSync);
|
|
}
|
|
}
|
|
return(status);
|
|
}
|
|
|
|
// --------------------------------------------------------------------------
|
|
// CAPIDispatcher::ExecuteRequest
|
|
//
|
|
// Arguments: portMessage = CPortMessage of request.
|
|
//
|
|
// Returns: NTSTATUS
|
|
//
|
|
// Purpose: Checks if the connection has been closed. If closed then it
|
|
// rejects the request. Otherwise it executes it.
|
|
//
|
|
// History: 2000-12-02 vtan created
|
|
// --------------------------------------------------------------------------
|
|
|
|
NTSTATUS CAPIDispatcher::ExecuteRequest (const CPortMessage& portMessage)
|
|
{
|
|
NTSTATUS status;
|
|
|
|
if (_fConnectionClosed)
|
|
{
|
|
status = RejectRequest(portMessage, STATUS_PORT_DISCONNECTED);
|
|
}
|
|
else
|
|
{
|
|
status = CreateAndExecuteRequest(portMessage);
|
|
}
|
|
return(status);
|
|
}
|
|
|
|
// --------------------------------------------------------------------------
|
|
// CAPIDispatcher::RejectRequest
|
|
//
|
|
// Arguments: portMessage = CPortMessage of request.
|
|
//
|
|
// Returns: NTSTATUS
|
|
//
|
|
// Purpose: Sends back a reply to the caller STATUS_PORT_DISCONNECTED to
|
|
// reject the request.
|
|
//
|
|
// History: 2000-12-02 vtan created
|
|
// --------------------------------------------------------------------------
|
|
|
|
NTSTATUS CAPIDispatcher::RejectRequest (const CPortMessage& portMessage, NTSTATUS status) const
|
|
|
|
{
|
|
CPortMessage portMessageOut(portMessage);
|
|
|
|
// Send the message back to the client.
|
|
|
|
portMessageOut.SetDataLength(sizeof(NTSTATUS));
|
|
portMessageOut.SetReturnCode(status);
|
|
return(SendReply(portMessageOut));
|
|
}
|
|
|
|
// --------------------------------------------------------------------------
|
|
// CAPIDispatcher::Entry
|
|
//
|
|
// Arguments: <none>
|
|
//
|
|
// Returns: <none>
|
|
//
|
|
// Purpose: Main entry point for processing LPC requests. If there are
|
|
// pending requests in the queue pick them off and process them.
|
|
// While processing them more items can get queued. Keep
|
|
// processing until there are no more queued items. There is a
|
|
// possible overlap where a newly queued item can be missed. In
|
|
// that case a new work item is queued to execute those requests.
|
|
//
|
|
// History: 1999-11-07 vtan created
|
|
// 2000-08-25 vtan moved from Neptune to Whistler
|
|
// 2002-03-21 scotthan Add queue synchronization via CAPIDispatchSynch.
|
|
// --------------------------------------------------------------------------
|
|
|
|
void CAPIDispatcher::Entry (void)
|
|
|
|
{
|
|
CAPIRequest *pAPIRequest;
|
|
|
|
// artificial addref our dispatch sync to prevent us from signalling prematurely,
|
|
// before we can safely allow ourselves to be destroyed by our parent APIConnection.
|
|
CAPIDispatchSync::DispatchEnter(_pAPIDispatchSync);
|
|
|
|
// Acquire the requests pending lock before fetching the first
|
|
// request. This will ensure an accurate result.
|
|
_lock.Acquire();
|
|
pAPIRequest = static_cast<CAPIRequest*>(_queue.Get());
|
|
|
|
// If there are more requests in the queue keep looping.
|
|
|
|
while (pAPIRequest != NULL)
|
|
{
|
|
|
|
// Release the requests pending lock to allow more requests to
|
|
// get queued to this dispatcher while the dispatch is executing.
|
|
|
|
if (!_fConnectionClosed)
|
|
{
|
|
NTSTATUS status;
|
|
|
|
// Before executing the API request release the lock to allow
|
|
// more requests to get queued while executing this one.
|
|
|
|
_lock.Release();
|
|
|
|
// Execute the request.
|
|
|
|
status = Execute(pAPIRequest);
|
|
|
|
// Acquire the requests pending lock again before getting
|
|
// the next available request. If the loop continues the
|
|
// lock will be released at the top of the loop. If the loop
|
|
// exits then the lock must be released outside.
|
|
|
|
_lock.Acquire();
|
|
|
|
// On debug builds ignore STATUS_REPLY_MESSAGE_MISMATCH.
|
|
// This typically happens on stress machines where timing
|
|
// causes the thread waiting on the reply to go away before
|
|
// the service has a chance to reply to the LPC request.
|
|
|
|
#ifdef DEBUG
|
|
if (!_fConnectionClosed && !ExcludedStatusCodeForDebug(status))
|
|
{
|
|
TSTATUS(status);
|
|
}
|
|
#endif /* DEBUG */
|
|
|
|
}
|
|
|
|
// Remove this processed request.
|
|
|
|
_queue.Remove();
|
|
|
|
// Decrement dispatch sync object. The matching DispatchEnter()
|
|
// took place at time of queuing, in CAPIDispatcher::QueueRequest().
|
|
CAPIDispatchSync::DispatchLeave(_pAPIDispatchSync);
|
|
|
|
// Get the next request. A request may have been queued while
|
|
// processing the request just processed. So keep looping until
|
|
// there really are no requests left.
|
|
|
|
pAPIRequest = static_cast<CAPIRequest*>(_queue.Get());
|
|
}
|
|
|
|
// Set the state to no longer processing requests so that any
|
|
// further queued requests will cause the dispatcher to be
|
|
// re-invoked in a new worker thread. Release the lock.
|
|
|
|
_fRequestsPending = false;
|
|
_lock.Release();
|
|
|
|
// remove defensive addref
|
|
CAPIDispatchSync::DispatchLeave(_pAPIDispatchSync);
|
|
}
|
|
|
|
// --------------------------------------------------------------------------
|
|
// CAPIDispatcher::Execute
|
|
//
|
|
// Arguments: pAPIRequest = API request to execute.
|
|
//
|
|
// Returns: NTSTATUS
|
|
//
|
|
// Purpose: Execute the API request. This can be done from a queued work
|
|
// item executing on a different thread or execute in the server
|
|
// port listen thread.
|
|
//
|
|
// History: 2000-10-19 vtan created
|
|
// --------------------------------------------------------------------------
|
|
|
|
NTSTATUS CAPIDispatcher::Execute (CAPIRequest *pAPIRequest) const
|
|
|
|
{
|
|
|
|
NTSTATUS status;
|
|
|
|
// Set the return data size to NTSTATUS by default. Execute the
|
|
// request. Store the result. If the executed function has more
|
|
// data to return it will set the size itself.
|
|
|
|
pAPIRequest->SetDataLength(sizeof(NTSTATUS));
|
|
|
|
// Protect the execution with an exception block. If the code
|
|
// throws an exception it would normally just kill the worker
|
|
// thread. However, the CAPIDispatcher would be left in a state
|
|
// where it was marked as still executing requests even though
|
|
// the thread died. If an exception is thrown the function is
|
|
// considered unsuccessful.
|
|
|
|
__try
|
|
{
|
|
status = pAPIRequest->Execute(_pAPIDispatchSync);
|
|
}
|
|
__except (DispatcherExceptionFilter(GetExceptionInformation()))
|
|
{
|
|
status = STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
pAPIRequest->SetReturnCode(status);
|
|
|
|
// Reply to the client with the result.
|
|
|
|
return(SendReply(*pAPIRequest));
|
|
}
|
|
|
|
// --------------------------------------------------------------------------
|
|
// CAPIDispatcher::CreateSection
|
|
//
|
|
// Arguments: <none>
|
|
//
|
|
// Returns: NTSTATUS
|
|
//
|
|
// Purpose: Overridable function that creates a section object. Because
|
|
// size is not determinable it can be inheritable.
|
|
//
|
|
// The default implementation does nothing.
|
|
//
|
|
// History: 2000-10-10 vtan created
|
|
// --------------------------------------------------------------------------
|
|
|
|
NTSTATUS CAPIDispatcher::CreateSection (void)
|
|
|
|
{
|
|
return(STATUS_NOT_IMPLEMENTED);
|
|
}
|
|
|
|
// --------------------------------------------------------------------------
|
|
// CAPIDispatcher::SignalRequestPending
|
|
//
|
|
// Arguments: <none>
|
|
//
|
|
// Returns: NTSTATUS
|
|
//
|
|
// Purpose: Signals the event to wake up the thread processing requests.
|
|
//
|
|
// History: 1999-11-07 vtan created
|
|
// 2000-08-25 vtan moved from Neptune to Whistler
|
|
// --------------------------------------------------------------------------
|
|
|
|
NTSTATUS CAPIDispatcher::SignalRequestPending (void)
|
|
|
|
{
|
|
NTSTATUS status;
|
|
CSingleThreadedExecution requestsPendingLock(_lock);
|
|
|
|
// Only check the validity of _fRequestsPending after acquiring the
|
|
// lock. This will guarantee that the value of this variable is
|
|
// 100% correct in a multi worker threaded environment.
|
|
|
|
if (!_fRequestsPending)
|
|
{
|
|
_fRequestsPending = true;
|
|
status = Queue();
|
|
}
|
|
else
|
|
{
|
|
status = STATUS_SUCCESS;
|
|
}
|
|
return(status);
|
|
}
|
|
|
|
// --------------------------------------------------------------------------
|
|
// CAPIDispatcher::SendReply
|
|
//
|
|
// Arguments: portMessage = CPortMessage to send in the reply.
|
|
//
|
|
// Returns: NTSTATUS
|
|
//
|
|
// Purpose: Sends a reply to the LPC port so the caller can be unblocked.
|
|
//
|
|
// History: 2000-10-19 vtan created
|
|
// --------------------------------------------------------------------------
|
|
|
|
NTSTATUS CAPIDispatcher::SendReply (const CPortMessage& portMessage) const
|
|
|
|
{
|
|
return(NtReplyPort(_hPort, const_cast<PORT_MESSAGE*>(portMessage.GetPortMessage())));
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
|
|
// --------------------------------------------------------------------------
|
|
// CAPIDispatcher::ExcludedStatusCodeForDebug
|
|
//
|
|
// Arguments: status = NTSTATUS code to check.
|
|
//
|
|
// Returns: bool
|
|
//
|
|
// Purpose: Returns whether this status code should be ignored on asserts.
|
|
//
|
|
// History: 2001-03-30 vtan created
|
|
// --------------------------------------------------------------------------
|
|
|
|
bool CAPIDispatcher::ExcludedStatusCodeForDebug (NTSTATUS status)
|
|
|
|
{
|
|
return((status == STATUS_REPLY_MESSAGE_MISMATCH) ||
|
|
(status == STATUS_INVALID_CID));
|
|
}
|
|
|
|
#endif /* DEBUG */
|
|
|
|
// --------------------------------------------------------------------------
|
|
// CAPIDispatcher::DispatcherExceptionFilter
|
|
//
|
|
// Arguments: <none>
|
|
//
|
|
// Returns: LONG
|
|
//
|
|
// Purpose: Filters exceptions that occur when dispatching API requests.
|
|
//
|
|
// History: 2000-10-13 vtan created
|
|
// --------------------------------------------------------------------------
|
|
|
|
LONG WINAPI CAPIDispatcher::DispatcherExceptionFilter (struct _EXCEPTION_POINTERS *pExceptionInfo)
|
|
|
|
{
|
|
(LONG)RtlUnhandledExceptionFilter(pExceptionInfo);
|
|
return(EXCEPTION_EXECUTE_HANDLER);
|
|
}
|
|
|
|
|
|
|
|
// --------------------------------------------------------------------------
|
|
// CAPIDispatchSync impl
|
|
// History: 2002-03-18 scotthan created.
|
|
// --------------------------------------------------------------------------
|
|
|
|
// --------------------------------------------------------------------------
|
|
CAPIDispatchSync::CAPIDispatchSync()
|
|
: _cDispatches(0)
|
|
, _hServiceStopping(NULL)
|
|
, _hZeroDispatches(NULL)
|
|
, _hPortShutdown(NULL)
|
|
, _hServiceControlStop(NULL)
|
|
{
|
|
if( !InitializeCriticalSectionAndSpinCount(&_cs, 0) )
|
|
{
|
|
ZeroMemory(&_cs, sizeof(_cs));
|
|
}
|
|
|
|
_hServiceStopping = CreateEvent(NULL, TRUE /* manual-rest */, FALSE /* unsignalled */, NULL);
|
|
_hZeroDispatches = CreateEvent(NULL, TRUE /* manual-rest */, TRUE /* signalled */, NULL);
|
|
_hPortShutdown = CreateEvent(NULL, FALSE /* auto-reset */, FALSE /* unsignalled */, NULL);
|
|
_hServiceControlStop = CreateEvent(NULL, FALSE /* auto-reset */, FALSE /* unsignalled */, NULL);
|
|
}
|
|
|
|
// --------------------------------------------------------------------------
|
|
CAPIDispatchSync::~CAPIDispatchSync()
|
|
{
|
|
HANDLE h;
|
|
|
|
h = _hServiceStopping;
|
|
_hServiceStopping = NULL;
|
|
if( h )
|
|
{
|
|
CloseHandle(h);
|
|
}
|
|
|
|
h = _hZeroDispatches;
|
|
_hZeroDispatches = NULL;
|
|
if( h )
|
|
{
|
|
CloseHandle(h);
|
|
}
|
|
|
|
h = _hPortShutdown;
|
|
_hPortShutdown = NULL;
|
|
if( h )
|
|
{
|
|
CloseHandle(h);
|
|
}
|
|
|
|
h = _hServiceControlStop;
|
|
_hServiceControlStop = NULL;
|
|
if( h )
|
|
{
|
|
CloseHandle(h);
|
|
}
|
|
|
|
|
|
if( _cs.DebugInfo )
|
|
{
|
|
DeleteCriticalSection(&_cs);
|
|
}
|
|
}
|
|
|
|
// --------------------------------------------------------------------------
|
|
void CAPIDispatchSync::SignalServiceStopping(CAPIDispatchSync* pds)
|
|
{
|
|
if( pds )
|
|
{
|
|
pds->Lock();
|
|
if( pds->_hServiceStopping )
|
|
{
|
|
SetEvent(pds->_hServiceStopping);
|
|
}
|
|
pds->Unlock();
|
|
}
|
|
}
|
|
|
|
// --------------------------------------------------------------------------
|
|
BOOL CAPIDispatchSync::IsServiceStopping(CAPIDispatchSync* pds)
|
|
{
|
|
BOOL fRet = FALSE;
|
|
if( pds )
|
|
{
|
|
if( pds->_hServiceStopping )
|
|
{
|
|
fRet = (WaitForSingleObject(pds->_hPortShutdown, 0) != WAIT_TIMEOUT);
|
|
}
|
|
}
|
|
return fRet;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------
|
|
HANDLE CAPIDispatchSync::GetServiceStoppingEvent(CAPIDispatchSync* pds)
|
|
{
|
|
return pds ? pds->_hServiceStopping : NULL;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------
|
|
void CAPIDispatchSync::DispatchEnter(CAPIDispatchSync* pds)
|
|
{
|
|
if( pds )
|
|
{
|
|
pds->Lock();
|
|
if( (++(pds->_cDispatches) > 0) && pds->_hZeroDispatches )
|
|
{
|
|
ResetEvent(pds->_hZeroDispatches);
|
|
}
|
|
pds->Unlock();
|
|
}
|
|
}
|
|
|
|
// --------------------------------------------------------------------------
|
|
void CAPIDispatchSync::DispatchLeave(CAPIDispatchSync* pds)
|
|
{
|
|
if( pds )
|
|
{
|
|
pds->Lock();
|
|
if( (--(pds->_cDispatches) == 0) && pds->_hZeroDispatches )
|
|
{
|
|
SetEvent(pds->_hZeroDispatches);
|
|
}
|
|
ASSERTMSG(pds->_cDispatches >= 0, "CAPIDispatchSync::Leave - refcount < 0: Mismatched Enter/Leave");
|
|
pds->Unlock();
|
|
}
|
|
}
|
|
|
|
// --------------------------------------------------------------------------
|
|
DWORD CAPIDispatchSync::WaitForZeroDispatches(CAPIDispatchSync* pds, DWORD dwTimeout)
|
|
{
|
|
if( pds )
|
|
{
|
|
if( pds->_hZeroDispatches )
|
|
{
|
|
return WaitForSingleObject(pds->_hZeroDispatches, dwTimeout);
|
|
}
|
|
}
|
|
return WAIT_ABANDONED;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------
|
|
void CAPIDispatchSync::SignalPortShutdown(CAPIDispatchSync* pds)
|
|
{
|
|
if( pds )
|
|
{
|
|
pds->Lock();
|
|
if( pds->_hPortShutdown )
|
|
{
|
|
SetEvent(pds->_hPortShutdown);
|
|
}
|
|
pds->Unlock();
|
|
}
|
|
}
|
|
|
|
// --------------------------------------------------------------------------
|
|
DWORD CAPIDispatchSync::WaitForPortShutdown(CAPIDispatchSync* pds, DWORD dwTimeout)
|
|
{
|
|
if( pds )
|
|
{
|
|
if( pds->_hPortShutdown )
|
|
{
|
|
return WaitForSingleObject(pds->_hPortShutdown, dwTimeout);
|
|
}
|
|
}
|
|
return WAIT_ABANDONED;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------
|
|
void CAPIDispatchSync::SignalServiceControlStop(CAPIDispatchSync* pds)
|
|
{
|
|
if( pds )
|
|
{
|
|
pds->Lock();
|
|
if( pds->_hServiceControlStop )
|
|
{
|
|
SetEvent(pds->_hServiceControlStop);
|
|
}
|
|
pds->Unlock();
|
|
}
|
|
}
|
|
|
|
// --------------------------------------------------------------------------
|
|
DWORD CAPIDispatchSync::WaitForServiceControlStop(CAPIDispatchSync* pds, DWORD dwTimeout)
|
|
{
|
|
if( pds )
|
|
{
|
|
if( pds->_hServiceControlStop )
|
|
{
|
|
return WaitForSingleObject(pds->_hServiceControlStop, dwTimeout);
|
|
}
|
|
}
|
|
return WAIT_ABANDONED;
|
|
}
|
|
// --------------------------------------------------------------------------
|
|
void CAPIDispatchSync::Lock()
|
|
{
|
|
if( _cs.DebugInfo )
|
|
{
|
|
EnterCriticalSection(&_cs);
|
|
}
|
|
}
|
|
|
|
// --------------------------------------------------------------------------
|
|
void CAPIDispatchSync::Unlock()
|
|
{
|
|
if( _cs.DebugInfo )
|
|
{
|
|
LeaveCriticalSection(&_cs);
|
|
}
|
|
}
|