2025-04-27 07:49:33 -04:00

333 lines
7.8 KiB
C++

/********************************************************************++
Copyright (c) 1998 Microsoft Corporation
Module Name :
wreqpool.cxx
Abstract:
This module implements the functions for managing the
pool of worker requests.
Author:
Murali R. Krishnan ( MuraliK ) 29-Oct-1998
Environment:
Win32 - User Mode
Project:
IIS Worker Process (web service)
--********************************************************************/
/************************************************************
* Include Headers
************************************************************/
#include "winbase.h"
#include "precomp.hxx"
#include "wreqpool.hxx"
extern WP_CONTEXT * g_pwpContext;
/************************************************************
* Functions
************************************************************/
/**
* UL_NATIVE_REQUEST_POOL::UL_NATIVE_REQUEST_POOL()
*
* o Construct a new worker requst pool object.
* This pool will maintain a list of all native request objects.
*
*/
UL_NATIVE_REQUEST_POOL::UL_NATIVE_REQUEST_POOL(void)
: m_nRequests ( 0),
m_nIdleRequests( 0),
m_fShutdown( FALSE),
m_fAddingItems( FALSE),
m_dwSignature( NREQ_POOL_SIGNATURE)
{
InitializeListHead( &m_lRequestList);
//
// Use spinned critical section.
// All operations using the CS are short lived and
// hence we keep the spins to a small amount.
//
//InitializeCriticalSection(&m_csRequestList);
InitializeCriticalSectionAndSpinCount(
&m_csRequestList,
UL_NATIVE_REQUEST_CS_SPINS
);
} // UL_NATIVE_REQUEST_POOL::UL_NATIVE_REQUEST_POOL()
/**
* ~UL_NATIVE_REQUEST_POOL
*
*/
UL_NATIVE_REQUEST_POOL::~UL_NATIVE_REQUEST_POOL(void)
{
if (m_nRequests > 0)
{
ReleaseAllWorkerRequests();
}
DeleteCriticalSection( &m_csRequestList);
InitializeListHead( &m_lRequestList);
m_dwSignature = ( NREQ_POOL_SIGNATURE_FREE);
} // UL_NATIVE_REQUEST_POOL::~UL_NATIVE_REQUEST_POOL()
/**
*
* UL_NATIVE_REQUEST_POOL::ReleaseAllWorkerRequests()
*
* o Walks the global list of all request objects and releases
* the requests
*
* NYI: For now it directly frees up the request. We need to post
* cancellations for the same as appropriate.
*/
HRESULT
UL_NATIVE_REQUEST_POOL::ReleaseAllWorkerRequests(void)
{
LIST_ENTRY * plScan;
// Wait for all requests's references drain away.
while(m_nRequests > 0)
{
PUL_NATIVE_REQUEST pwr;
// Should change to DEBUGGING CODE ONLY
// IF_DEBUG(DEBUG) {
DBGPRINTF((DBG_CONTEXT, "%d Requests still needs to be cleaned\n",
m_nRequests));
plScan = m_lRequestList.Flink;
pwr = CONTAINING_RECORD( plScan, UL_NATIVE_REQUEST, m_lRequestEntry);
DBGPRINTF((DBG_CONTEXT, "The unreleased request's ref count is %d\n",
pwr->ReferenceCount()));
// }
Sleep(2000);
}
DBG_ASSERT(m_nIdleRequests == 0);
DBGPRINTF((DBG_CONTEXT, "Released all native request objects\n"));
return (NOERROR);
} // UL_NATIVE_REQUEST_POOL::ReleaseAllWorkerRequests();
/**
* AddRequestToList
*
* Add an UL_NATIVE_REQUEST to the request list.
*
*/
void
UL_NATIVE_REQUEST_POOL::AddRequestToList(UL_NATIVE_REQUEST * pRequest)
{
EnterCriticalSection( &m_csRequestList);
InsertTailList( &m_lRequestList, &pRequest->m_lRequestEntry);
m_nRequests++;
LeaveCriticalSection( &m_csRequestList);
} // UL_NATIVE_REQUEST_POOL::AddRequestToList()
/**
* RemoveRequestFromList
*
* Remove an UL_NATIVE_REQUEST from the request list.
* This function is called within ~UL_NATIVE_REQUEST.
*
*/
void
UL_NATIVE_REQUEST_POOL::RemoveRequestFromList(UL_NATIVE_REQUEST * pRequest)
{
LONG nReqs;
EnterCriticalSection( &m_csRequestList);
RemoveEntryList( &pRequest->m_lRequestEntry);
nReqs = m_nRequests--;
LeaveCriticalSection( &m_csRequestList);
InitializeListHead( &pRequest->m_lRequestEntry);
} // UL_NATIVE_REQUEST_POOL::RemoveRequestFromList()
/**
* Description:
* UL_NATIVE_REQUEST_POOL::AddPoolItems()
*
* o Adds a fixed number of items to the pool and adds them to the
* current list of worker requests. After creating the object,
* an async read for request is posted on the worker request objects.
*
* Arguments:
* pContext - pointer to the CONTEXT object for IO operations
* nWorkerItemsToAdd - count of new worker requests to be added to the list
*
* Returns:
* ULONG
*
*/
ULONG
UL_NATIVE_REQUEST_POOL::AddPoolItems(
IN WP_CONTEXT * pContext,
IN int nWorkerItemsToAdd)
{
int i;
ULONG rc;
LONG nReqs;
BOOL fAdding;
PUL_NATIVE_REQUEST pwr;
EnterCriticalSection( &m_csRequestList);
if (nWorkerItemsToAdd + m_nRequests > REQUEST_POOL_MAX) {
nWorkerItemsToAdd = REQUEST_POOL_MAX - m_nRequests;
}
if (!m_fAddingItems) {
m_fAddingItems = TRUE;
fAdding = TRUE;
} else {
nWorkerItemsToAdd = 0;
fAdding = FALSE;
}
LeaveCriticalSection( &m_csRequestList);
//
// Loop through and create specified # of worker request objects
// Attach the current context to these objects
//
for (i = 0; i < nWorkerItemsToAdd; i++)
{
if (m_fShutdown) {
return i;
}
pwr = new UL_NATIVE_REQUEST( this);
if ( NULL == pwr)
{
rc = GetLastError();
if (NO_ERROR != rc)
{
IF_DEBUG( ERROR)
{
DPERROR(( DBG_CONTEXT, rc,
"Unable to create worker request %d.\n",
i));
}
}
//
// NYI: Log an event to the evnet log on this failure
//
//
// For now bail out of this loop on error
//
break;
}
else
{
AddRequestToList( pwr);
//
// Initialize the Context for the object.
//
pwr->SetWPContext( pContext);
rc = pwr->DoWork( 0, 0, &pwr->m_overlapped);
// assume no failure in initial req. read operations
DBG_ASSERT( NO_ERROR == rc);
}
} // for
if (fAdding) {
EnterCriticalSection(&m_csRequestList);
DBG_ASSERT(m_fAddingItems);
m_fAddingItems = FALSE;
LeaveCriticalSection(&m_csRequestList);
}
return (NOERROR);
} // UL_NATIVE_REQUEST_POOL::AddPoolItems()
/**
* Description:
* UL_NATIVE_REQUEST_POOL::DecIdleRequests()
*
* Decrements the count of objects available to process new requests.
* If we fall below 1/4 the number of initial items, we add some more.
*
* Arguments:
* None.
*
* Returns:
* None.
*
*/
VOID
UL_NATIVE_REQUEST_POOL::DecIdleRequests()
{
LONG idle;
idle = InterlockedDecrement(&m_nIdleRequests);
DBG_ASSERT(idle >= 0);
if (idle < (NUM_INITIAL_REQUEST_POOL_ITEMS / 4)) {
AddPoolItems(g_pwpContext, REQUEST_POOL_INCREMENT);
}
}
/**
* Description:
* UL_NATIVE_REQUEST_POOL::IncIdleRequests()
*
* Increments the count of objects available to process new requests.
*
* Arguments:
* None.
*
* Returns:
* None.
*
*/
VOID
UL_NATIVE_REQUEST_POOL::IncIdleRequests()
{
InterlockedIncrement(&m_nIdleRequests);
}
/***************************** End of File ***************************/