Leaked source code of windows server 2003
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.
 
 
 
 
 
 

441 lines
13 KiB

//-----------------------------------------------------------------------------
//
//
// File: asncwrkq.cpp
//
// Description: Implementation of CAsyncWorkQueue.
//
// Author: Mike Swafford (MikeSwa)
//
// History:
// 3/8/99 - MikeSwa Created
//
// Copyright (C) 1999 Microsoft Corporation
//
//-----------------------------------------------------------------------------
#include "aqprecmp.h"
#include "asncwrkq.h"
#include "asyncq.inl"
CPool CAsyncWorkQueueItem::s_CAsyncWorkQueueItemPool;
DWORD CAsyncWorkQueueItem::s_cCurrentHeapAllocations = 0;
DWORD CAsyncWorkQueueItem::s_cTotalHeapAllocations = 0;
//---[ CAsyncWorkQueueItem::new ]----------------------------------------------
//
//
// Description:
// Wrapper for new that will use CPool or Exchmem to allocate...
// whichever is appropriate.
// Parameters:
// size size of item to allocate (should always be
// sizeof (CAsyncWorkQueueItem)
// Returns:
// Pointer to newly allocated CAsyncWorkQueueItem
// History:
// 7/8/99 - MikeSwa Created
//
//-----------------------------------------------------------------------------
void * CAsyncWorkQueueItem::operator new(size_t size)
{
CAsyncWorkQueueItemAllocatorBlock *pcpaqwi = NULL;
_ASSERT(sizeof(CAsyncWorkQueueItem) == size);
pcpaqwi = (CAsyncWorkQueueItemAllocatorBlock *) s_CAsyncWorkQueueItemPool.Alloc();
if (pcpaqwi)
{
pcpaqwi->m_dwSignature = ASYNC_WORK_QUEUE_ENTRY_ALLOC_CPOOL_SIG;
}
else
{
//Fallback on Exchmem
pcpaqwi = (CAsyncWorkQueueItemAllocatorBlock *)
pvMalloc(sizeof(CAsyncWorkQueueItemAllocatorBlock));
if (pcpaqwi)
{
pcpaqwi->m_dwSignature = ASYNC_WORK_QUEUE_ENTRY_ALLOC_HEAP_SIG;
DEBUG_DO_IT(InterlockedIncrement((PLONG) &s_cCurrentHeapAllocations));
DEBUG_DO_IT(InterlockedIncrement((PLONG) &s_cTotalHeapAllocations));
}
}
if (pcpaqwi)
return ((void *) &(pcpaqwi->m_pawqi));
else
return NULL;
}
//---[ CAsyncWorkQueueItem::delete ]-------------------------------------------
//
//
// Description:
// Delete operator that will handle deleting via CPool or exchmem
// Parameters:
// pv Object to delete
// size Size of object
// Returns:
// -
// History:
// 7/8/99 - MikeSwa Created
//
//-----------------------------------------------------------------------------
void CAsyncWorkQueueItem::operator delete(void *pv, size_t size)
{
_ASSERT(sizeof(CAsyncWorkQueueItem) == size);
_ASSERT(pv);
CAsyncWorkQueueItemAllocatorBlock *pcpaqwi = CONTAINING_RECORD(pv,
CAsyncWorkQueueItemAllocatorBlock, m_pawqi);
DWORD dwOldSignature = pcpaqwi->m_dwSignature;
_ASSERT(ASYNC_WORK_QUEUE_ENTRY_ALLOC_INVALID_SIG != dwOldSignature);
//Reset signature before we free it, in case memory allocators
//do not overwrite it (we want our asserts to fire at the time
//of the double-free).
pcpaqwi->m_dwSignature = ASYNC_WORK_QUEUE_ENTRY_ALLOC_INVALID_SIG;
switch(dwOldSignature)
{
case ASYNC_WORK_QUEUE_ENTRY_ALLOC_CPOOL_SIG:
s_CAsyncWorkQueueItemPool.Free(pcpaqwi);
break;
case ASYNC_WORK_QUEUE_ENTRY_ALLOC_HEAP_SIG:
DEBUG_DO_IT(InterlockedDecrement((PLONG) &s_cCurrentHeapAllocations));
FreePv(pcpaqwi);
break;
default:
_ASSERT(0 && "Invalid signature when freeing CAsyncWorkQueueItem");
}
}
//---[ CAsyncWorkQueueItem::CAsyncWorkQueueItem ]------------------------------
//
//
// Description:
// Default constructor for CAsyncWorkQueueItem
// Parameters:
// pvData Data to pass to completion function
// pfnCompletion Completion function
// Returns:
// -
// History:
// 3/8/99 - MikeSwa Created
//
//-----------------------------------------------------------------------------
CAsyncWorkQueueItem::CAsyncWorkQueueItem(PVOID pvData,
PASYNC_WORK_QUEUE_FN pfnCompletion)
{
_ASSERT(pfnCompletion);
m_dwSignature = ASYNC_WORK_QUEUE_ENTRY;
m_pvData = pvData;
m_pfnCompletion = pfnCompletion;
}
//---[ CAsyncWorkQueueItem::~CAsyncWorkQueueItem ]-----------------------------
//
//
// Description:
// Default destructor for CAsyncWorkQueueItem
// Parameters:
// -
// Returns:
// -
// History:
// 3/8/99 - MikeSwa Created
//
//-----------------------------------------------------------------------------
CAsyncWorkQueueItem::~CAsyncWorkQueueItem()
{
m_dwSignature = ASYNC_WORK_QUEUE_ENTRY_FREE;
}
//---[ CAsyncWorkQueue::CAsyncWorkQueue ]--------------------------------------
//
//
// Description:
// Default constructor for CAsyncWorkQueue
// Parameters:
// -
// Returns:
// -
// History:
// 3/8/99 - MikeSwa Created
//
//-----------------------------------------------------------------------------
CAsyncWorkQueue::CAsyncWorkQueue()
{
m_dwSignature = ASYNC_WORK_QUEUE_SIG;
m_cWorkQueueItems = 0;
m_dwStateFlags = ASYNC_WORK_QUEUE_NORMAL;
}
//---[ CAsyncWorkQueue::~CAsyncWorkQueue ]-------------------------------------
//
//
// Description:
// Destructor for CAsyncWorkQueue
// Parameters:
// -
// Returns:
// -
// History:
// 3/8/99 - MikeSwa Created
//
//-----------------------------------------------------------------------------
CAsyncWorkQueue::~CAsyncWorkQueue()
{
m_dwSignature = ASYNC_WORK_QUEUE_SIG_FREE;
}
//---[ CAsyncWorkQueue::HrInitialize ]-----------------------------------------
//
//
// Description:
// Initialization routing for CAsyncWorkQueue base. Initializes the
// CAsyncQueue
// Parameters:
// cItemsPerThread The number of items to process per async thread
// Returns:
// S_OK on success
// Failure code from CAsyncQueue::HrInitialize()
// History:
// 3/8/99 - MikeSwa Created
//
//-----------------------------------------------------------------------------
HRESULT CAsyncWorkQueue::HrInitialize(DWORD cItemsPerThread)
{
HRESULT hr = S_OK;
hr = m_asyncq.HrInitialize(0, //there can be *no* sync threads
cItemsPerThread,
1,//init requires this value to be at least 1
this,
CAsyncWorkQueue::fQueueCompletion,
CAsyncWorkQueue::fQueueFailure,
NULL);
return hr;
}
//---[ CAsyncWorkQueue::HrDeinitialize ]---------------------------------------
//
//
// Description:
// Signals shutdown for queue code
// Parameters:
// paqinst Pointer to AQ server instance object
// Returns:
// S_OK on success
// History:
// 3/8/99 - MikeSwa Created
// 7/7/99 - MikeSwa Allow async threads to help process shutdown
//
//-----------------------------------------------------------------------------
HRESULT CAsyncWorkQueue::HrDeinitialize(CAQSvrInst *paqinst)
{
const DWORD MAX_ITERATIONS_NO_PROGRESS = 1000; //iterations before assert
HRESULT hr = S_OK;
DWORD cLastCount = cGetWorkQueueItems();
DWORD cIterationsNoProgress = 0;
_ASSERT(paqinst);
//Start processing all items in "shutdown" mode
m_dwStateFlags = ASYNC_WORK_QUEUE_SHUTDOWN;
//
// Make sure we have threads actively processing this queue before
// we settle down and wait for them to stop.
//
_ASSERT(!cGetWorkQueueItems() || m_asyncq.dwGetTotalThreads());
m_asyncq.StartRetry();
//Let the worker threads have some fun before we stop and do the single
//theaded initialization
while (cLastCount && (cIterationsNoProgress < MAX_ITERATIONS_NO_PROGRESS))
{
if (cLastCount <= cGetWorkQueueItems())
cIterationsNoProgress++;
//I'd like to see this case
_ASSERT(cIterationsNoProgress < MAX_ITERATIONS_NO_PROGRESS);
cLastCount = cGetWorkQueueItems();
paqinst->ServerStopHintFunction();
//Since it may take longer than our stop hint to process a
//single item in the queue, we need to sleep instead of
//attempting to process an item (Bug #X5:118258).
Sleep(10000);
}
hr = m_asyncq.HrDeinitialize(CAsyncWorkQueue::HrShutdownWalkFn,
paqinst);
return hr;
}
//---[ CAsyncWorkQueue::HrQueueWorkItem ]--------------------------------------
//
//
// Description:
// Queues items to async work queue
// Parameters:
// pvData Data item to pass to completion function
// pfCompletion Completion function
// Returns:
// S_OK on success
// E_OUTOFMEMORY if queue item could not be allocated
// History:
// 3/8/99 - MikeSwa Created
//
//-----------------------------------------------------------------------------
HRESULT CAsyncWorkQueue::HrQueueWorkItem(PVOID pvData,
PASYNC_WORK_QUEUE_FN pfnCompletion)
{
HRESULT hr = S_OK;
CAsyncWorkQueueItem *pawqi = NULL;
_ASSERT(pvData);
_ASSERT(pfnCompletion);
if (!pfnCompletion)
{
hr = E_INVALIDARG;
goto Exit;
}
//Create queue item, initialize it, and queue it
pawqi = new CAsyncWorkQueueItem(pvData, pfnCompletion);
if (!pawqi)
{
hr = E_OUTOFMEMORY;
goto Exit;
}
hr = m_asyncq.HrQueueRequest(pawqi, FALSE);
if (FAILED(hr))
goto Exit;
InterlockedIncrement((PLONG) &m_cWorkQueueItems);
Exit:
if (FAILED(hr) && pfnCompletion)
{
//call completion function
pfnCompletion(pvData,
ASYNC_WORK_QUEUE_FAILURE |
ASYNC_WORK_QUEUE_ENQUEUE_THREAD);
}
if (pawqi)
pawqi->Release();
return hr;
}
//---[ CAsyncWorkQueue::fQueueCompletion ]-------------------------------------
//
//
// Description:
// Completion function called by CAsyncQueue
// Parameters:
// pawqi CAsyncWorkQueueItem to process
// pvContext "this" pointer
// Returns:
// TRUE if item was process
// FALSE otherwise
// History:
// 3/8/99 - MikeSwa Created
//
//-----------------------------------------------------------------------------
BOOL CAsyncWorkQueue::fQueueCompletion(CAsyncWorkQueueItem *pawqi,
PVOID pvContext)
{
BOOL fRet = TRUE;
CAsyncWorkQueue *pawq = (CAsyncWorkQueue *) pvContext;
_ASSERT(pawqi);
_ASSERT(pawq);
_ASSERT(ASYNC_WORK_QUEUE_ENTRY == pawqi->m_dwSignature);
_ASSERT(ASYNC_WORK_QUEUE_SIG == pawq->m_dwSignature);
fRet = pawqi->m_pfnCompletion(pawqi->m_pvData,
pawq->m_dwStateFlags);
if (fRet)
InterlockedDecrement((PLONG)
&(((CAsyncWorkQueue *)pawq)->m_cWorkQueueItems));
return fRet;
}
//---[ CAsyncWorkQueue::fQueueFailure ]----------------------------------------
//
//
// Description:
// Function to handle internal failures in CAsyncQueue
// Parameters:
// pawq "this" pointer
// pawqi CAsyncWorkQueueItem to process
// Returns:
// TRUE always
// History:
// 3/8/99 - MikeSwa Created
//
//-----------------------------------------------------------------------------
BOOL CAsyncWorkQueue::fQueueFailure(CAsyncWorkQueueItem *pawqi,
PVOID pawq)
{
_ASSERT(pawqi);
_ASSERT(pawq);
_ASSERT(ASYNC_WORK_QUEUE_ENTRY == pawqi->m_dwSignature);
_ASSERT(ASYNC_WORK_QUEUE_SIG == ((CAsyncWorkQueue *)pawq)->m_dwSignature);
pawqi->m_pfnCompletion(pawqi->m_pvData, ASYNC_WORK_QUEUE_FAILURE);
InterlockedDecrement((PLONG) &(((CAsyncWorkQueue *)pawq)->m_cWorkQueueItems));
return TRUE;
}
//---[ CAsyncWorkQueue::HrShutdownWalkFn ]-------------------------------------
//
//
// Description:
// Function to walk an CAsyncWorkQueue queue at shutdown and clear out
// all of the pending work items
// Parameters:
// IN CAsyncWorkQueueItem ptr to data on queue
// IN PVOID pvContext AQ server intstance
// OUT BOOL *pfContinue, TRUE if we should continue
// OUT BOOL *pfDelete); TRUE if item should be deleted
// Returns:
// S_OK always
// History:
// 3/8/99 - MikeSwa Created
//
//-----------------------------------------------------------------------------
HRESULT CAsyncWorkQueue::HrShutdownWalkFn(
CAsyncWorkQueueItem *pawqi,
PVOID pvContext,
BOOL *pfContinue,
BOOL *pfDelete)
{
CAQSvrInst *paqinst = (CAQSvrInst *) pvContext;
_ASSERT(pfContinue);
_ASSERT(pfDelete);
_ASSERT(pawqi);
_ASSERT(ASYNC_WORK_QUEUE_ENTRY == pawqi->m_dwSignature);
*pfContinue = TRUE;
*pfDelete = TRUE;
//call server stop hint function
paqinst->ServerStopHintFunction();
pawqi->m_pfnCompletion(pawqi->m_pvData, ASYNC_WORK_QUEUE_SHUTDOWN);
return S_OK;
}