787 lines
19 KiB
C++
787 lines
19 KiB
C++
/*==========================================================================
|
|
*
|
|
* Copyright (C) 2000 Microsoft Corporation. All Rights Reserved.
|
|
*
|
|
* File: Cancel.cpp
|
|
* Content: DirectNet Cancel Operations
|
|
*@@BEGIN_MSINTERNAL
|
|
* History:
|
|
* Date By Reason
|
|
* ==== == ======
|
|
* 04/07/00 mjn Created
|
|
* 04/08/00 mjn Added DNCancelEnum(), DNCancelSend()
|
|
* 04/11/00 mjn DNCancelEnum() uses CAsyncOp
|
|
* 04/17/00 mjn DNCancelSend() uses CAsyncOp
|
|
* 04/25/00 mjn Added DNCancelConnect()
|
|
* 07/05/00 mjn Added code to handle invalid async ops
|
|
* 07/08/00 mjn Fixed CAsyncOp to contain m_bilinkParent
|
|
* 08/05/00 mjn Added DNCancelChildren(),DNCancelActiveCommands(),DNCanCancelCommand()
|
|
* mjn Removed DNCancelEnum(),DNCancelListen(),DNCancelSend(),DNCancelConnect()
|
|
* 08/07/00 mjn Added DNCancelRequestCommands()
|
|
* 08/22/00 mjn Remove cancelled receive buffers from the active list in DNDoCancelCommand()
|
|
* 09/02/00 mjn Cancel active commands in reverse order (to prevent out of order messages at protocol level)
|
|
* 01/10/01 mjn Allow DNCancelActiveCommands() to set result code of cancelled commands
|
|
* 02/08/01 mjn Use SyncEvents on AsyncOps to prevent protocol completions from returning before cancels return
|
|
* mjn Added DNWaitForCancel()
|
|
* 04/13/01 mjn DNCancelRequestCommands() uses request bilink
|
|
* 05/23/01 mjn Only cancel commands that are allowed to be cancelled in DNDoCancelCommand()
|
|
* 06/03/01 mjn Ignore uncancelable children in DNCancelChildren()
|
|
*@@END_MSINTERNAL
|
|
*
|
|
***************************************************************************/
|
|
|
|
#include "dncorei.h"
|
|
|
|
|
|
// DNCanCancelCommand
|
|
//
|
|
// This will determine if an operation is cancelable based on the selection flags
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "DNCanCancelCommand"
|
|
|
|
BOOL DNCanCancelCommand(CAsyncOp *const pAsyncOp,
|
|
const DWORD dwFlags)
|
|
{
|
|
BOOL fReturnVal;
|
|
|
|
DPFX(DPFPREP, 8,"Parameters: pAsyncOp [0x%p], dwFlags [0x%lx]",pAsyncOp,dwFlags);
|
|
|
|
DNASSERT(pAsyncOp != NULL);
|
|
|
|
fReturnVal = FALSE;
|
|
switch(pAsyncOp->GetOpType())
|
|
{
|
|
case ASYNC_OP_CONNECT:
|
|
{
|
|
if (dwFlags & DN_CANCEL_FLAG_CONNECT)
|
|
{
|
|
fReturnVal = TRUE;
|
|
}
|
|
break;
|
|
}
|
|
case ASYNC_OP_DISCONNECT:
|
|
{
|
|
if (dwFlags & DN_CANCEL_FLAG_DISCONNECT)
|
|
{
|
|
fReturnVal = TRUE;
|
|
}
|
|
break;
|
|
}
|
|
case ASYNC_OP_ENUM_QUERY:
|
|
{
|
|
if (dwFlags & DN_CANCEL_FLAG_ENUM_QUERY)
|
|
{
|
|
fReturnVal = TRUE;
|
|
}
|
|
break;
|
|
}
|
|
case ASYNC_OP_ENUM_RESPONSE:
|
|
{
|
|
if (dwFlags & DN_CANCEL_FLAG_ENUM_RESPONSE)
|
|
{
|
|
fReturnVal = TRUE;
|
|
}
|
|
break;
|
|
}
|
|
case ASYNC_OP_LISTEN:
|
|
{
|
|
if (dwFlags & DN_CANCEL_FLAG_LISTEN)
|
|
{
|
|
fReturnVal = TRUE;
|
|
}
|
|
break;
|
|
}
|
|
case ASYNC_OP_SEND:
|
|
{
|
|
if (pAsyncOp->IsInternal())
|
|
{
|
|
if (dwFlags & DN_CANCEL_FLAG_INTERNAL_SEND)
|
|
{
|
|
fReturnVal = TRUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (dwFlags & DN_CANCEL_FLAG_USER_SEND)
|
|
{
|
|
fReturnVal = TRUE;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case ASYNC_OP_RECEIVE_BUFFER:
|
|
{
|
|
if (dwFlags & DN_CANCEL_FLAG_RECEIVE_BUFFER)
|
|
{
|
|
fReturnVal = TRUE;
|
|
}
|
|
break;
|
|
}
|
|
case ASYNC_OP_REQUEST:
|
|
{
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
DPFX(DPFPREP, 8,"Returning: [%ld]",fReturnVal);
|
|
return(fReturnVal);
|
|
}
|
|
|
|
|
|
// DNDoCancelCommand
|
|
//
|
|
// This will attempt to cancel a given operation based on its OpType
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "DNDoCancelCommand"
|
|
|
|
HRESULT DNDoCancelCommand(DIRECTNETOBJECT *const pdnObject,
|
|
CAsyncOp *const pAsyncOp)
|
|
{
|
|
HRESULT hResultCode;
|
|
|
|
DPFX(DPFPREP, 8,"Parameters: pAsyncOp [0x%p]",pAsyncOp);
|
|
|
|
hResultCode = DPNERR_CANNOTCANCEL;
|
|
|
|
switch(pAsyncOp->GetOpType())
|
|
{
|
|
case ASYNC_OP_CONNECT:
|
|
case ASYNC_OP_ENUM_QUERY:
|
|
case ASYNC_OP_ENUM_RESPONSE:
|
|
case ASYNC_OP_LISTEN:
|
|
case ASYNC_OP_SEND:
|
|
{
|
|
HANDLE hProtocol;
|
|
BOOL fCanCancel;
|
|
|
|
DNASSERT(pdnObject->pdnProtocolData != NULL );
|
|
|
|
//
|
|
// If this operation has been marked as not cancellable,
|
|
// we will return an error
|
|
//
|
|
pAsyncOp->Lock();
|
|
hProtocol = pAsyncOp->GetProtocolHandle();
|
|
fCanCancel = !pAsyncOp->IsCannotCancel();
|
|
pAsyncOp->Unlock();
|
|
|
|
if (fCanCancel && (hProtocol != NULL))
|
|
{
|
|
DPFX(DPFPREP, 9,"Attempting to cancel AsyncOp [0x%p]",pAsyncOp);
|
|
hResultCode = DNPCancelCommand(pdnObject->pdnProtocolData,hProtocol);
|
|
DPFX(DPFPREP, 9,"Result of cancelling AsyncOp [0x%p] was [0x%lx]",pAsyncOp,hResultCode);
|
|
}
|
|
else
|
|
{
|
|
DPFX(DPFPREP,9,"Not allowed to cancel this operation");
|
|
hResultCode = DPNERR_CANNOTCANCEL;
|
|
}
|
|
break;
|
|
}
|
|
case ASYNC_OP_RECEIVE_BUFFER:
|
|
{
|
|
if (pAsyncOp->GetHandle() != 0)
|
|
{
|
|
if ((hResultCode = pdnObject->HandleTable.Destroy( pAsyncOp->GetHandle() )) == DPN_OK)
|
|
{
|
|
//
|
|
// Remove from active list
|
|
//
|
|
DNEnterCriticalSection(&pdnObject->csActiveList);
|
|
pAsyncOp->m_bilinkActiveList.RemoveFromList();
|
|
DNLeaveCriticalSection(&pdnObject->csActiveList);
|
|
}
|
|
else
|
|
{
|
|
hResultCode = DPNERR_CANNOTCANCEL;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
// case ASYNC_OP_DISCONNECT:
|
|
case ASYNC_OP_REQUEST:
|
|
default:
|
|
{
|
|
DNASSERT(FALSE);
|
|
break;
|
|
}
|
|
}
|
|
|
|
DPFX(DPFPREP, 8,"Returning: [0x%lx]",hResultCode);
|
|
return(hResultCode);
|
|
}
|
|
|
|
|
|
// DNCancelChildren
|
|
//
|
|
// This will mark an operation as CANCELLED to prevent new children from attaching,
|
|
// build a cancel list of any children, and recursively call itself to cancel those children.
|
|
// At the bottom level, if there is a Protocol handle, we will actually call DNPCancelCommand()
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "DNCancelChildren"
|
|
|
|
HRESULT DNCancelChildren(DIRECTNETOBJECT *const pdnObject,
|
|
CAsyncOp *const pParent)
|
|
{
|
|
HRESULT hResultCode;
|
|
CBilink *pBilink;
|
|
CAsyncOp *pAsyncOp;
|
|
CAsyncOp **CancelList;
|
|
CSyncEvent *pSyncEvent;
|
|
DWORD dwCount;
|
|
DWORD dwActual;
|
|
|
|
DPFX(DPFPREP, 6,"Parameters: pParent [0x%p]",pParent);
|
|
|
|
DNASSERT(pdnObject != NULL);
|
|
DNASSERT(pParent != NULL);
|
|
|
|
pAsyncOp = NULL;
|
|
CancelList = NULL;
|
|
pSyncEvent = NULL;
|
|
|
|
//
|
|
// Mark the parent as cancelled so that no new children can attach
|
|
//
|
|
pParent->Lock();
|
|
if (pParent->IsCancelled() || pParent->IsComplete() || pParent->IsCannotCancel())
|
|
{
|
|
pParent->Unlock();
|
|
DPFX(DPFPREP, 7,"Ignoring pParent [0x%p]",pParent);
|
|
hResultCode = DPN_OK;
|
|
goto Exit;
|
|
}
|
|
pParent->SetCancelled();
|
|
|
|
//
|
|
// Determine size of cancel list
|
|
//
|
|
dwCount = 0;
|
|
pBilink = pParent->m_bilinkParent.GetNext();
|
|
while (pBilink != &pParent->m_bilinkParent)
|
|
{
|
|
pAsyncOp = CONTAINING_OBJECT(pBilink,CAsyncOp,m_bilinkChildren);
|
|
pAsyncOp->Lock();
|
|
if (!pAsyncOp->IsCancelled() && !pAsyncOp->IsComplete())
|
|
{
|
|
dwCount++;
|
|
}
|
|
pAsyncOp->Unlock();
|
|
pBilink = pBilink->GetNext();
|
|
}
|
|
DPFX(DPFPREP, 7,"Number of cancellable children [%ld]",dwCount);
|
|
|
|
//
|
|
// Create cancel list
|
|
//
|
|
if (dwCount > 0)
|
|
{
|
|
if ((CancelList = static_cast<CAsyncOp**>(DNMalloc(dwCount * sizeof(CAsyncOp*)))) == NULL)
|
|
{
|
|
#pragma BUGBUG( minara, "Should we unflag the cancel ?" )
|
|
pParent->Unlock();
|
|
DPFERR("Could not allocate space for cancel list");
|
|
hResultCode = DPNERR_OUTOFMEMORY;
|
|
goto Failure;
|
|
}
|
|
dwActual = 0;
|
|
pBilink = pParent->m_bilinkParent.GetNext();
|
|
while (pBilink != &pParent->m_bilinkParent)
|
|
{
|
|
pAsyncOp = CONTAINING_OBJECT(pBilink,CAsyncOp,m_bilinkChildren);
|
|
pAsyncOp->Lock();
|
|
if (!pAsyncOp->IsCancelled() && !pAsyncOp->IsComplete())
|
|
{
|
|
DNASSERT(dwActual < dwCount); // This list should NEVER grow !
|
|
pAsyncOp->AddRef();
|
|
CancelList[dwActual] = pAsyncOp;
|
|
dwActual++;
|
|
}
|
|
pAsyncOp->Unlock();
|
|
pBilink = pBilink->GetNext();
|
|
}
|
|
DPFX(DPFPREP, 7,"Actual number of cancellable children [%ld]",dwActual);
|
|
}
|
|
|
|
//
|
|
// Attach a sync event if this is a protocol operation
|
|
// This event may be cleared by the completion
|
|
//
|
|
if (pParent->GetProtocolHandle() != NULL)
|
|
{
|
|
if ((hResultCode = SyncEventNew(pdnObject,&pSyncEvent)) != DPN_OK)
|
|
{
|
|
DPFERR("Could not get new sync event");
|
|
DisplayDNError(0,hResultCode);
|
|
}
|
|
else
|
|
{
|
|
pSyncEvent->Reset();
|
|
pParent->SetCancelEvent( pSyncEvent );
|
|
pParent->SetCancelThreadID( GetCurrentThreadId() );
|
|
DPFX(DPFPREP,7,"Setting sync event [0x%p]",pSyncEvent);
|
|
}
|
|
}
|
|
|
|
pParent->Unlock();
|
|
|
|
//
|
|
// Preset the return
|
|
//
|
|
hResultCode = DPN_OK;
|
|
|
|
//
|
|
// Call ourselves with each of the children (if there are any)
|
|
// and clean up (release AsyncOp children and free list)
|
|
//
|
|
if (CancelList)
|
|
{
|
|
DWORD dw;
|
|
HRESULT hr;
|
|
|
|
for (dw = 0 ; dw < dwActual ; dw++ )
|
|
{
|
|
hr = DNCancelChildren(pdnObject,CancelList[dw]);
|
|
if ((hr != DPN_OK) && (hResultCode == DPN_OK))
|
|
{
|
|
hResultCode = hr;
|
|
}
|
|
CancelList[dw]->Release();
|
|
CancelList[dw] = NULL;
|
|
}
|
|
DNFree(CancelList);
|
|
CancelList = NULL;
|
|
}
|
|
|
|
//
|
|
// Cancel this operation (if we can)
|
|
// This will only work for CONNECTs,DISCONNECTs,ENUM_QUERYs,ENUM_RESPONSEs,LISTENs,SENDs with a protocol handle
|
|
//
|
|
if (pParent->GetProtocolHandle() != NULL)
|
|
{
|
|
HRESULT hr;
|
|
|
|
hr = DNDoCancelCommand(pdnObject,pParent);
|
|
if ((hr != DPN_OK) && (hResultCode == DPN_OK))
|
|
{
|
|
hResultCode = hr;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Set the cancel event and clear it from the async op if it's still there
|
|
//
|
|
if (pSyncEvent)
|
|
{
|
|
pSyncEvent->Set();
|
|
|
|
pParent->Lock();
|
|
pSyncEvent = pParent->GetCancelEvent();
|
|
pParent->SetCancelEvent( NULL );
|
|
pParent->Unlock();
|
|
|
|
if (pSyncEvent)
|
|
{
|
|
DPFX(DPFPREP,7,"Returning sync event [0x%p]",pSyncEvent);
|
|
pSyncEvent->ReturnSelfToPool();
|
|
pSyncEvent = NULL;
|
|
}
|
|
}
|
|
|
|
Exit:
|
|
DNASSERT( pSyncEvent == NULL );
|
|
|
|
DPFX(DPFPREP, 6,"Returning: [0x%lx]",hResultCode);
|
|
return(hResultCode);
|
|
|
|
Failure:
|
|
if (CancelList)
|
|
{
|
|
DNFree(CancelList);
|
|
CancelList = NULL;
|
|
}
|
|
goto Exit;
|
|
}
|
|
|
|
|
|
// DNCancelActiveCommands
|
|
//
|
|
// This will attempt to cancel ALL operations in the active list.
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "DNCancelActiveCommands"
|
|
|
|
HRESULT DNCancelActiveCommands(DIRECTNETOBJECT *const pdnObject,
|
|
const DWORD dwFlags,
|
|
const BOOL fSetResult,
|
|
const HRESULT hrCancel)
|
|
{
|
|
HRESULT hResultCode;
|
|
CAsyncOp *pAsyncOp;
|
|
CAsyncOp **CancelList;
|
|
CBilink *pBilink;
|
|
DWORD dwCount;
|
|
DWORD dwActual;
|
|
|
|
DPFX(DPFPREP, 6,"Parameters: dwFlags [0x%lx], fSetResult [%ld], hrCancel [0x%lx]",dwFlags,fSetResult,hrCancel);
|
|
|
|
DNASSERT(pdnObject != NULL);
|
|
|
|
CancelList = NULL;
|
|
|
|
//
|
|
// Prevent changes
|
|
//
|
|
DNEnterCriticalSection(&pdnObject->csActiveList);
|
|
|
|
//
|
|
// Determine size of cancel list
|
|
//
|
|
dwCount = 0;
|
|
pBilink = pdnObject->m_bilinkActiveList.GetPrev();
|
|
while (pBilink != &pdnObject->m_bilinkActiveList)
|
|
{
|
|
pAsyncOp = CONTAINING_OBJECT(pBilink,CAsyncOp,m_bilinkActiveList);
|
|
if (DNCanCancelCommand(pAsyncOp,dwFlags))
|
|
{
|
|
pAsyncOp->Lock();
|
|
if (!pAsyncOp->IsCancelled() && !pAsyncOp->IsComplete())
|
|
{
|
|
dwCount++;
|
|
}
|
|
pAsyncOp->Unlock();
|
|
}
|
|
pBilink = pBilink->GetPrev();
|
|
}
|
|
DPFX(DPFPREP, 7,"Number of cancellable ops [%ld]",dwCount);
|
|
|
|
//
|
|
// Create cancel list
|
|
//
|
|
if (dwCount > 0)
|
|
{
|
|
if ((CancelList = static_cast<CAsyncOp**>(DNMalloc(dwCount * sizeof(CAsyncOp*)))) == NULL)
|
|
{
|
|
DNLeaveCriticalSection(&pdnObject->csActiveList);
|
|
DPFERR("Could not allocate space for cancel list");
|
|
hResultCode = DPNERR_OUTOFMEMORY;
|
|
goto Failure;
|
|
}
|
|
dwActual = 0;
|
|
pBilink = pdnObject->m_bilinkActiveList.GetPrev();
|
|
while (pBilink != &pdnObject->m_bilinkActiveList)
|
|
{
|
|
pAsyncOp = CONTAINING_OBJECT(pBilink,CAsyncOp,m_bilinkActiveList);
|
|
if (DNCanCancelCommand(pAsyncOp,dwFlags))
|
|
{
|
|
pAsyncOp->Lock();
|
|
if (!pAsyncOp->IsCancelled() && !pAsyncOp->IsComplete())
|
|
{
|
|
DNASSERT(dwActual < dwCount); // This list should NEVER grow !
|
|
pAsyncOp->AddRef();
|
|
CancelList[dwActual] = pAsyncOp;
|
|
dwActual++;
|
|
}
|
|
pAsyncOp->Unlock();
|
|
}
|
|
pBilink = pBilink->GetPrev();
|
|
}
|
|
DPFX(DPFPREP, 7,"Actual number of cancellable ops [%ld]",dwActual);
|
|
}
|
|
|
|
//
|
|
// Allow changes, though the list should not grow any more here
|
|
//
|
|
DNLeaveCriticalSection(&pdnObject->csActiveList);
|
|
|
|
//
|
|
// Preset the return
|
|
//
|
|
hResultCode = DPN_OK;
|
|
|
|
//
|
|
// Cancel each operation in the cancel list operation (if we can)
|
|
// This will only work for CONNECTs,DISCONNECTs,ENUM_QUERYs,ENUM_RESPONSEs,LISTENs,SENDs with a protocol handle
|
|
//
|
|
if (CancelList)
|
|
{
|
|
DWORD dw;
|
|
HRESULT hr;
|
|
CSyncEvent *pSyncEvent;
|
|
|
|
pSyncEvent = NULL;
|
|
|
|
for (dw = 0 ; dw < dwActual ; dw++ )
|
|
{
|
|
//
|
|
// Ensure operation has not already been cancelled
|
|
// If this is a protocol operation, we will add a sync event to prevent any completions from returning
|
|
// until we're done
|
|
//
|
|
DNASSERT( CancelList[dw] != NULL );
|
|
CancelList[dw]->Lock();
|
|
if (CancelList[dw]->IsCancelled() || CancelList[dw]->IsComplete())
|
|
{
|
|
CancelList[dw]->Unlock();
|
|
CancelList[dw]->Release();
|
|
CancelList[dw] = NULL;
|
|
continue;
|
|
}
|
|
if (CancelList[dw]->GetProtocolHandle() != NULL)
|
|
{
|
|
if ((hr = SyncEventNew(pdnObject,&pSyncEvent)) != DPN_OK)
|
|
{
|
|
DPFERR("Could not get sync event");
|
|
DisplayDNError(0,hr);
|
|
}
|
|
else
|
|
{
|
|
pSyncEvent->Reset();
|
|
CancelList[dw]->SetCancelEvent( pSyncEvent );
|
|
CancelList[dw]->SetCancelThreadID( GetCurrentThreadId() );
|
|
DPFX(DPFPREP,7,"Setting sync event [0x%p]",pSyncEvent);
|
|
}
|
|
}
|
|
|
|
CancelList[dw]->SetCancelled();
|
|
CancelList[dw]->Unlock();
|
|
|
|
//
|
|
// Perform the actual cancel
|
|
//
|
|
hr = DNDoCancelCommand(pdnObject,CancelList[dw]);
|
|
if ((hr != DPN_OK) && (hResultCode == DPN_OK))
|
|
{
|
|
hResultCode = hr;
|
|
}
|
|
|
|
//
|
|
// If this operation was cancelled and we need to set the result, we will
|
|
//
|
|
if ((hr == DPN_OK) && fSetResult)
|
|
{
|
|
CancelList[dw]->Lock();
|
|
CancelList[dw]->SetResult( hrCancel );
|
|
CancelList[dw]->Unlock();
|
|
}
|
|
|
|
//
|
|
// Set the cancel event and clear it from the async op if it's still there
|
|
//
|
|
if (pSyncEvent)
|
|
{
|
|
pSyncEvent->Set();
|
|
|
|
CancelList[dw]->Lock();
|
|
pSyncEvent = CancelList[dw]->GetCancelEvent();
|
|
CancelList[dw]->SetCancelEvent( NULL );
|
|
CancelList[dw]->Unlock();
|
|
|
|
if (pSyncEvent)
|
|
{
|
|
DPFX(DPFPREP,7,"Returning sync event [0x%p]",pSyncEvent);
|
|
pSyncEvent->ReturnSelfToPool();
|
|
pSyncEvent = NULL;
|
|
}
|
|
}
|
|
|
|
CancelList[dw]->Release();
|
|
CancelList[dw] = NULL;
|
|
}
|
|
DNFree(CancelList);
|
|
CancelList = NULL;
|
|
|
|
DNASSERT(pSyncEvent == NULL);
|
|
}
|
|
|
|
Exit:
|
|
DPFX(DPFPREP, 6,"Returning: [0x%lx]",hResultCode);
|
|
return(hResultCode);
|
|
|
|
Failure:
|
|
if (CancelList)
|
|
{
|
|
DNFree(CancelList);
|
|
CancelList = NULL;
|
|
}
|
|
goto Exit;
|
|
}
|
|
|
|
|
|
// DNCancelRequestCommands
|
|
//
|
|
// This will attempt to cancel REQUEST operations in the HandleTable.
|
|
// Requests have handles which are matched up against responses. Since these
|
|
// typically have SEND children (which may have completed and thus vanished),
|
|
// there is no guarantee these are not orphaned off in the HandleTable.
|
|
// We will look through the HandleTable for them and cancel them.
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "DNCancelRequestCommands"
|
|
|
|
HRESULT DNCancelRequestCommands(DIRECTNETOBJECT *const pdnObject)
|
|
{
|
|
HRESULT hResultCode;
|
|
CAsyncOp **RequestList;
|
|
DWORD dwCount;
|
|
DWORD dwActual;
|
|
CBilink *pBilink;
|
|
|
|
DPFX(DPFPREP, 6,"Parameters: (none)");
|
|
|
|
DNASSERT(pdnObject != NULL);
|
|
|
|
RequestList = NULL;
|
|
|
|
dwCount = 0;
|
|
dwActual = 0;
|
|
|
|
//
|
|
// Determine outstanding request list size and build it
|
|
//
|
|
DNEnterCriticalSection(&pdnObject->csActiveList);
|
|
pBilink = pdnObject->m_bilinkRequestList.GetNext();
|
|
while (pBilink != &pdnObject->m_bilinkRequestList)
|
|
{
|
|
dwCount++;
|
|
pBilink = pBilink->GetNext();
|
|
}
|
|
if (dwCount > 0)
|
|
{
|
|
CAsyncOp *pAsyncOp;
|
|
|
|
if ((RequestList = static_cast<CAsyncOp**>(MemoryBlockAlloc(pdnObject,dwCount * sizeof(CAsyncOp*)))) == NULL)
|
|
{
|
|
DNLeaveCriticalSection(&pdnObject->csAsyncOperations);
|
|
DPFERR("Could not allocate request list");
|
|
hResultCode = DPNERR_OUTOFMEMORY;
|
|
goto Failure;
|
|
}
|
|
pBilink = pdnObject->m_bilinkRequestList.GetNext();
|
|
while (pBilink != &pdnObject->m_bilinkRequestList)
|
|
{
|
|
pAsyncOp = CONTAINING_OBJECT(pBilink,CAsyncOp,m_bilinkActiveList);
|
|
DNASSERT(dwActual < dwCount);
|
|
DNASSERT(pAsyncOp->GetOpType() == ASYNC_OP_REQUEST);
|
|
pAsyncOp->AddRef();
|
|
RequestList[dwActual] = pAsyncOp;
|
|
pAsyncOp = NULL;
|
|
dwActual++;
|
|
pBilink = pBilink->GetNext();
|
|
}
|
|
}
|
|
DNLeaveCriticalSection(&pdnObject->csActiveList);
|
|
|
|
//
|
|
// Remove requests from request list and handle table
|
|
//
|
|
for (dwActual = 0 ; dwActual < dwCount ; dwActual++)
|
|
{
|
|
DNEnterCriticalSection(&pdnObject->csActiveList);
|
|
RequestList[dwActual]->m_bilinkActiveList.RemoveFromList();
|
|
DNLeaveCriticalSection(&pdnObject->csActiveList);
|
|
|
|
RequestList[dwActual]->Lock();
|
|
RequestList[dwActual]->SetResult( DPNERR_USERCANCEL );
|
|
RequestList[dwActual]->Unlock();
|
|
if (RequestList[dwActual]->GetHandle())
|
|
{
|
|
pdnObject->HandleTable.Destroy(RequestList[dwActual]->GetHandle());
|
|
}
|
|
RequestList[dwActual]->Release();
|
|
RequestList[dwActual] = NULL;
|
|
}
|
|
|
|
//
|
|
// Clean up
|
|
//
|
|
if (RequestList)
|
|
{
|
|
MemoryBlockFree(pdnObject,RequestList);
|
|
RequestList = NULL;
|
|
}
|
|
hResultCode = DPN_OK;
|
|
|
|
Exit:
|
|
DNASSERT(RequestList == NULL);
|
|
|
|
DPFX(DPFPREP, 6,"Returning: [0x%lx]",hResultCode);
|
|
return(hResultCode);
|
|
|
|
Failure:
|
|
if (RequestList)
|
|
{
|
|
MemoryBlockFree(pdnObject,RequestList);
|
|
RequestList = NULL;
|
|
}
|
|
goto Exit;
|
|
}
|
|
|
|
|
|
// DNWaitForCancel
|
|
//
|
|
// This will strip a cancel event off an async op if it exists, wait on it, and then return it to the pool
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "DNWaitForCancel"
|
|
|
|
void DNWaitForCancel(DIRECTNETOBJECT *const pdnObject,
|
|
CAsyncOp *const pAsyncOp)
|
|
{
|
|
DPFX(DPFPREP, 6,"Parameters: pAsyncOp [0x%p]",pAsyncOp);
|
|
|
|
CSyncEvent *pSyncEvent;
|
|
|
|
DNASSERT(pdnObject != NULL);
|
|
DNASSERT(pAsyncOp != NULL);
|
|
|
|
pSyncEvent = NULL;
|
|
|
|
//
|
|
// Get (and clear) sync event from async op
|
|
//
|
|
pAsyncOp->Lock();
|
|
pSyncEvent = pAsyncOp->GetCancelEvent();
|
|
if (pSyncEvent)
|
|
{
|
|
// Only pull the SyncEvent out if we are going to wait on it
|
|
if (pAsyncOp->GetCancelThreadID() == GetCurrentThreadId())
|
|
{
|
|
// The other side of this will clean it up
|
|
DPFX(DPFPREP,7,"Cancel called on current thread - ignoring wait and continuing");
|
|
pSyncEvent = NULL;
|
|
}
|
|
else
|
|
{
|
|
// We are pulling it out, so we will clean it up
|
|
pAsyncOp->SetCancelEvent( NULL );
|
|
}
|
|
}
|
|
pAsyncOp->Unlock();
|
|
|
|
//
|
|
// If there was a sync event,
|
|
// - wait on it
|
|
// - return it to the pool
|
|
//
|
|
if (pSyncEvent)
|
|
{
|
|
DPFX(DPFPREP,7,"Waiting on sync event [0x%p]",pSyncEvent);
|
|
pSyncEvent->WaitForEvent(INFINITE);
|
|
|
|
DPFX(DPFPREP,7,"Returning sync event [0x%p]",pSyncEvent);
|
|
pSyncEvent->ReturnSelfToPool();
|
|
pSyncEvent = NULL;
|
|
}
|
|
|
|
DNASSERT(pSyncEvent == NULL);
|
|
|
|
DPFX(DPFPREP, 6,"Returning");
|
|
}
|