472 lines
12 KiB
C++
472 lines
12 KiB
C++
/*++
|
|
|
|
Copyright (c) 1997 Microsoft Corporation
|
|
|
|
Module Name :
|
|
abw.hxx
|
|
|
|
Abstract:
|
|
Declares constants, types and functions for bandwidth throttling.
|
|
|
|
Author:
|
|
|
|
Bilal Alam ( t-bilala ) 13-March-1997
|
|
|
|
Environment:
|
|
|
|
User Mode -- Win32
|
|
|
|
Project:
|
|
|
|
Internet Services Asynchronous Thread Queue Library
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
typedef struct _BANDWIDTH_LEVELS {
|
|
DWORD dwSpecifiedLevel;
|
|
DWORD dwLowThreshold; // uses 0.90 * bwSpecifiedLevel
|
|
DWORD dwHighThreshold; // uses 1.10 * bwSpecifiedLevel
|
|
} BANDWIDTH_LEVELS;
|
|
|
|
# define ATQ_LOW_BAND_THRESHOLD(bw) (bw.dwLowThreshold)
|
|
# define ATQ_HIGH_BAND_THRESHOLD(bw) (bw.dwHighThreshold)
|
|
|
|
# define CIRCULAR_INCREMENT( sm_pB, sm_rgB, size) \
|
|
(sm_pB) = ((((sm_pB) + 1) < (sm_rgB)+(size)) ? (sm_pB)+1 : (sm_rgB))
|
|
|
|
|
|
typedef enum {
|
|
|
|
ZoneLevelLow = 0, // if MeasuredBw < Bandwidth specified
|
|
ZoneLevelMedium, // if MeasuredBw approxEquals Bandwidth specified
|
|
ZoneLevelHigh, // if MeasuredBw > Bandwidth specified
|
|
ZoneLevelMax // just a boundary element
|
|
} ZoneLevel;
|
|
|
|
/*++
|
|
The following array specifies the status of operations for different
|
|
operations in different zones of the measured bandwidth.
|
|
|
|
We split the range of bandwidth into three zones as specified in
|
|
the type ZoneLevel. Depending upon the zone of operation, differet
|
|
operations are enabled/disabled. Priority is given to minimize the amount
|
|
of CPU work that needs to be redone when an operation is to be rejected.
|
|
We block operations on which considerable amount of CPU is spent earlier.
|
|
--*/
|
|
|
|
static OPERATION_STATUS sm_rgStatus[ZoneLevelMax][AtqIoMaxOp] = {
|
|
|
|
// For ZoneLevelLow: Allow All operations
|
|
{ StatusRejectOperation,
|
|
StatusAllowOperation,
|
|
StatusAllowOperation,
|
|
StatusAllowOperation,
|
|
StatusAllowOperation,
|
|
StatusAllowOperation,
|
|
},
|
|
|
|
// For ZoneLevelMedium:
|
|
{ StatusRejectOperation,
|
|
StatusBlockOperation, // Block Read
|
|
StatusAllowOperation,
|
|
StatusAllowOperation,
|
|
StatusAllowOperation,
|
|
StatusAllowOperation
|
|
},
|
|
|
|
// For ZoneLevelHigh
|
|
{ StatusRejectOperation,
|
|
StatusRejectOperation, // Reject Read
|
|
StatusAllowOperation, // Allow Writes
|
|
StatusBlockOperation, // Block TransmitFile
|
|
StatusBlockOperation, // Block TransmitFileAndRecv
|
|
StatusAllowOperation // Allow SendAndRecv
|
|
}
|
|
};
|
|
|
|
#define ATQ_BW_INFO_SIGNATURE ( (DWORD) 'BQTA')
|
|
#define ATQ_BW_INFO_SIGNATURE_FREE ( (DWORD) 'BQTX')
|
|
#define ATQ_BW_INFO_MAX_DESC 32
|
|
|
|
/*++
|
|
class BANDWIDTH_INFO
|
|
|
|
This class encapsulates all the statistics and state used in the
|
|
implementation of bandwidth throttling.
|
|
--*/
|
|
class BANDWIDTH_INFO
|
|
{
|
|
private:
|
|
|
|
DWORD _Signature;
|
|
LONG _cReference;
|
|
BOOL _fIsFreed;
|
|
BOOL _fPersistent;
|
|
|
|
// statistics
|
|
|
|
DWORD _cCurrentBlockedRequests;
|
|
DWORD _cTotalBlockedRequests;
|
|
DWORD _cTotalAllowedRequests;
|
|
DWORD _cTotalRejectedRequests;
|
|
DWORD _dwMeasuredBw;
|
|
|
|
// bandwidth status members
|
|
|
|
BANDWIDTH_LEVELS _bandwidth;
|
|
LARGE_INTEGER _rgBytesXfered[ ATQ_HISTOGRAM_SIZE ];
|
|
LARGE_INTEGER * _pBytesXferCur;
|
|
LARGE_INTEGER _cbXfered;
|
|
OPERATION_STATUS * _pStatus;
|
|
BOOL _fEnabled;
|
|
|
|
// list of blocked context manipulation
|
|
|
|
CRITICAL_SECTION _csPrivateLock;
|
|
LIST_ENTRY _BlockedListHead;
|
|
DWORD _cMaxBlockedList;
|
|
|
|
// user friendly description of this descriptor. Useful for debugging
|
|
|
|
#if DBG
|
|
CHAR _achDescription[ ATQ_BW_INFO_MAX_DESC ];
|
|
#endif
|
|
|
|
// private members shared by all BANDWIDTH_INFO objects
|
|
|
|
static CRITICAL_SECTION sm_csSharedLock;
|
|
static LIST_ENTRY sm_BornListHead;
|
|
static LIST_ENTRY sm_ActiveListHead;
|
|
static DWORD sm_cBornList;
|
|
static DWORD sm_cActiveList;
|
|
static ALLOC_CACHE_HANDLER * sm_pachBWInfos;
|
|
static BOOL sm_fGlobalEnabled;
|
|
static BOOL sm_fGlobalActive;
|
|
static DWORD sm_cNonInfinite;
|
|
|
|
// private member functions
|
|
|
|
VOID Initialize( IN BOOL fPersistent );
|
|
VOID Terminate( VOID );
|
|
BOOL UnblockRequest( IN OUT PATQ_CONT pAtqContext );
|
|
BOOL UpdateBandwidth( VOID );
|
|
|
|
VOID Lock( VOID )
|
|
{
|
|
EnterCriticalSection( &_csPrivateLock );
|
|
}
|
|
|
|
VOID Unlock( VOID )
|
|
{
|
|
LeaveCriticalSection( &_csPrivateLock );
|
|
}
|
|
|
|
static VOID SharedLock( VOID )
|
|
{
|
|
EnterCriticalSection( &sm_csSharedLock );
|
|
}
|
|
|
|
static VOID SharedUnlock( VOID )
|
|
{
|
|
LeaveCriticalSection( &sm_csSharedLock );
|
|
}
|
|
|
|
VOID RemoveFromActiveList( VOID )
|
|
// Assume caller has acquired shared lock!
|
|
{
|
|
sm_cActiveList--;
|
|
if ( !sm_cActiveList )
|
|
{
|
|
sm_fGlobalActive = FALSE;
|
|
}
|
|
#ifndef _NO_TRACING_
|
|
CHKINFO(( DBG_CONTEXT,
|
|
"Removed %p (%s) from active bandwidth info list (list size = %d)\n",
|
|
this,
|
|
_achDescription,
|
|
sm_cActiveList ));
|
|
#else
|
|
ATQ_PRINTF(( DBG_CONTEXT,
|
|
"Removed %p (%s) from active bandwidth info list (list size = %d)\n",
|
|
this,
|
|
_achDescription,
|
|
sm_cActiveList ));
|
|
#endif
|
|
RemoveEntryList( &_ActiveListEntry );
|
|
_fMemberOfActiveList = FALSE;
|
|
_ActiveListEntry.Flink = NULL;
|
|
}
|
|
|
|
VOID RemoveFromBornList( VOID )
|
|
{
|
|
SharedLock();
|
|
|
|
sm_cBornList--;
|
|
#ifndef _NO_TRACING_
|
|
CHKINFO(( DBG_CONTEXT,
|
|
"Removed %p (%s) from born bandwidth info list (list size = %d)\n",
|
|
this,
|
|
_achDescription,
|
|
sm_cBornList ));
|
|
#else
|
|
ATQ_PRINTF(( DBG_CONTEXT,
|
|
"Removed %p (%s) from born bandwidth info list (list size = %d)\n",
|
|
this,
|
|
_achDescription,
|
|
sm_cBornList ));
|
|
#endif
|
|
RemoveEntryList( &_BornListEntry );
|
|
_BornListEntry.Flink = NULL;
|
|
|
|
// Now remove from the active list
|
|
|
|
if ( _fMemberOfActiveList )
|
|
{
|
|
RemoveFromActiveList();
|
|
}
|
|
|
|
SharedUnlock();
|
|
}
|
|
|
|
public:
|
|
|
|
LIST_ENTRY _BornListEntry;
|
|
LIST_ENTRY _ActiveListEntry;
|
|
BOOL _fMemberOfActiveList;
|
|
|
|
static DWORD sm_cSamplesForTimeout;
|
|
|
|
// public member functions
|
|
|
|
VOID Reference( VOID )
|
|
{
|
|
InterlockedIncrement( &_cReference );
|
|
}
|
|
|
|
VOID Dereference( VOID )
|
|
{
|
|
if ( !_fPersistent && !InterlockedDecrement( &_cReference ) )
|
|
{
|
|
delete this;
|
|
}
|
|
}
|
|
|
|
OPERATION_STATUS QueryStatus( ATQ_OPERATION operation ) const
|
|
{
|
|
return _pStatus[ operation ];
|
|
}
|
|
|
|
BOOL IsFreed( VOID )
|
|
{
|
|
return _fIsFreed;
|
|
}
|
|
|
|
VOID IncTotalBlockedRequests( VOID )
|
|
{
|
|
INC_ATQ_COUNTER( _cTotalBlockedRequests );
|
|
}
|
|
|
|
DWORD QueryTotalBlockedRequests( VOID ) const
|
|
{
|
|
return _cTotalBlockedRequests;
|
|
}
|
|
|
|
VOID IncTotalAllowedRequests( VOID )
|
|
{
|
|
INC_ATQ_COUNTER( _cTotalAllowedRequests );
|
|
}
|
|
|
|
DWORD QueryTotalAllowedRequests( VOID ) const
|
|
{
|
|
return _cTotalAllowedRequests;
|
|
}
|
|
|
|
VOID IncTotalRejectedRequests( VOID )
|
|
{
|
|
INC_ATQ_COUNTER( _cTotalRejectedRequests );
|
|
}
|
|
|
|
DWORD QueryTotalRejectedRequests( VOID ) const
|
|
{
|
|
return _cTotalRejectedRequests;
|
|
}
|
|
|
|
VOID IncCurrentBlockedRequests( VOID )
|
|
{
|
|
INC_ATQ_COUNTER( _cCurrentBlockedRequests );
|
|
}
|
|
|
|
DWORD QueryCurrentBlockedRequests( VOID ) const
|
|
{
|
|
return _cCurrentBlockedRequests;
|
|
}
|
|
|
|
VOID DecCurrentBlockedRequests( VOID )
|
|
{
|
|
DEC_ATQ_COUNTER( _cCurrentBlockedRequests );
|
|
}
|
|
|
|
DWORD QueryMeasuredBw( VOID ) const
|
|
{
|
|
return _dwMeasuredBw;
|
|
}
|
|
|
|
BOOL Enabled( VOID ) const
|
|
{
|
|
return _fEnabled;
|
|
}
|
|
|
|
DWORD QuerySignature( VOID ) const
|
|
{
|
|
return _Signature;
|
|
}
|
|
|
|
DWORD QueryMaxBlockedSize( VOID ) const
|
|
{
|
|
return _cMaxBlockedList;
|
|
}
|
|
|
|
VOID SetMaxBlockedSize( DWORD Size )
|
|
{
|
|
_cMaxBlockedList = Size;
|
|
}
|
|
|
|
VOID AddToActiveList( VOID )
|
|
{
|
|
if ( _fEnabled && !_fMemberOfActiveList )
|
|
{
|
|
SharedLock();
|
|
if ( _fEnabled && !_fMemberOfActiveList )
|
|
{
|
|
sm_cActiveList++;
|
|
|
|
#ifndef _NO_TRACING_
|
|
CHKINFO(( DBG_CONTEXT,
|
|
"Added %p (%s) to active bandwidth info list (list size = %d)\n",
|
|
this,
|
|
_achDescription,
|
|
sm_cActiveList ));
|
|
#else
|
|
ATQ_PRINTF(( DBG_CONTEXT,
|
|
"Added %p (%s) to active bandwidth info list (list size = %d)\n",
|
|
this,
|
|
_achDescription,
|
|
sm_cActiveList ));
|
|
#endif
|
|
|
|
InsertTailList( &sm_ActiveListHead, &_ActiveListEntry );
|
|
|
|
_fMemberOfActiveList = TRUE;
|
|
|
|
sm_fGlobalActive = TRUE;
|
|
}
|
|
SharedUnlock();
|
|
}
|
|
}
|
|
|
|
VOID AddToBornList( VOID )
|
|
{
|
|
SharedLock();
|
|
|
|
sm_cBornList++;
|
|
|
|
InsertTailList( &sm_BornListHead, &_BornListEntry );
|
|
|
|
SharedUnlock();
|
|
}
|
|
|
|
BOOL UpdateBytesXfered( IN PATQ_CONT pAtqContext,
|
|
IN DWORD cbIo )
|
|
{
|
|
if ( _fEnabled )
|
|
{
|
|
Lock();
|
|
|
|
_pBytesXferCur->QuadPart = _pBytesXferCur->QuadPart + cbIo;
|
|
|
|
Unlock();
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
CHAR * QueryDescription( VOID ) const
|
|
{
|
|
// :(
|
|
#if DBG
|
|
return (CHAR*) _achDescription;
|
|
#else
|
|
return NULL;
|
|
#endif
|
|
}
|
|
|
|
VOID SetDescription( CHAR * pszDescription )
|
|
{
|
|
#if DBG
|
|
Lock();
|
|
strncpy( _achDescription,
|
|
pszDescription ? pszDescription : "Unknown",
|
|
sizeof( _achDescription ) );
|
|
Unlock();
|
|
#endif
|
|
}
|
|
|
|
BANDWIDTH_INFO( IN BOOL fPersistent )
|
|
{
|
|
Initialize( fPersistent );
|
|
}
|
|
|
|
~BANDWIDTH_INFO( VOID )
|
|
{
|
|
Terminate();
|
|
}
|
|
|
|
BOOL PrepareToFree( VOID );
|
|
BOOL RemoveFromBlockedList( IN PATQ_CONT patqContext );
|
|
BOOL BlockRequest( IN OUT PATQ_CONT patqContext );
|
|
DWORD SetBandwidthLevel( IN DWORD Data );
|
|
BOOL CheckAndUnblockRequests( VOID );
|
|
|
|
DWORD SetMaxBlockedListSize( IN DWORD Data );
|
|
DWORD QueryBandwidthLevel( VOID );
|
|
BOOL ClearStatistics( VOID );
|
|
BOOL GetStatistics( OUT ATQ_STATISTICS * patqStats );
|
|
|
|
static BOOL GlobalActive( VOID )
|
|
{
|
|
return sm_fGlobalActive;
|
|
}
|
|
|
|
static BOOL GlobalEnabled( VOID )
|
|
{
|
|
return sm_fGlobalEnabled;
|
|
}
|
|
|
|
static BOOL AbwInitialize( VOID );
|
|
static BOOL AbwTerminate( VOID );
|
|
static BOOL UpdateAllBandwidths( VOID );
|
|
|
|
void * operator new( size_t s )
|
|
{
|
|
ATQ_ASSERT( s == sizeof( BANDWIDTH_INFO ));
|
|
|
|
// allocate from allocation cache.
|
|
ATQ_ASSERT( sm_pachBWInfos != NULL );
|
|
return (sm_pachBWInfos->Alloc());
|
|
}
|
|
|
|
void operator delete( void * pBandwidthInfo )
|
|
{
|
|
ATQ_ASSERT( pBandwidthInfo != NULL );
|
|
|
|
// free to the allocation pool
|
|
ATQ_ASSERT( NULL != sm_pachBWInfos );
|
|
ATQ_REQUIRE( sm_pachBWInfos->Free( pBandwidthInfo ) );
|
|
|
|
return;
|
|
}
|
|
};
|
|
|
|
typedef BANDWIDTH_INFO * PBANDWIDTH_INFO;
|