|
|
/*++
Copyright (c) 1999-2000 Microsoft Corporation
Module Name:
buf.c
Abstract:
Buffer management utilities
Revision History:
Who When What -------- -------- ---------------------------------------------- josephj 03-10-99 Created
Notes:
--*/ #include <precomp.h>
//
// File-specific debugging defaults.
//
#define TM_CURRENT TM_BUF
NDIS_STATUS arpInitializeConstBufferPool( IN UINT NumBuffersToCache, IN UINT MaxBuffers, IN const PVOID pvMem, IN UINT cbMem, IN PRM_OBJECT_HEADER pOwningObject, IN OUT ARP_CONST_BUFFER_POOL * pHdrPool, IN PRM_STACK_RECORD pSR ) /*++
Routine Description:
Initialize a pool of pre-initialized buffers (of type NDIS_BUFFER). Each buffer points to the same, CONSTANT piece of virtual memory, that is supplied by the caller (pvMem, of size cbMem).
Arguments:
NumBuffersToCache - Max number of pre-initialized buffers to keep in the internal cache. MaxBuffers - Max number of buffers allowed to be allocated at any one time. pvMem - The constant piece of memory that all the buffers point to. cbMem - The size (in bytes) of the above piece of memory. pOwningObject - The object that owns the const buffer pool. pHdrPool - Unitialized memory to hold the const buffer pool.
Return Value:
NDIS_STATUS_SUCCESS on successfill initialization of the const buffer pool. NDIS failure code on failure.
--*/ { ENTER("arpInitializeConstBufferPool", 0x943463d4) NDIS_STATUS Status;
ARP_ZEROSTRUCT(pHdrPool);
do { // Allocate the buffer pool
//
NdisAllocateBufferPool( &Status, &pHdrPool->NdisHandle, MaxBuffers ); if (FAIL(Status)) { TR_WARN(( "pOwningObj 0x%p, NdisAllocateBufferPool err status 0x%x\n", pOwningObject, Status));
break; }
pHdrPool->NumBuffersToCache = NumBuffersToCache; pHdrPool->MaxBuffers = MaxBuffers; pHdrPool->pvMem = pvMem; pHdrPool->cbMem = cbMem; pHdrPool->pOwningObject = pOwningObject;
// Initialize Slist to contain initialized and available buffers.
//
ExInitializeSListHead(&pHdrPool->BufferList);
// Initialize spin lock that serializes accesses to the above list.
//
NdisAllocateSpinLock(&pHdrPool->NdisLock);
// (DBG) Add an association to the owning object, to make sure that it
// deallocates us eventually!
//
DBG_ADDASSOC( pOwningObject, pHdrPool, // Entity1
NULL, // Entity2 (unused)
ARPASSOC_CBUFPOOL_ALLOC, // AssocID
" Buffer pool 0x%p\n", // Format string
pSR );
//
// Note: we don't populate the list at this stage -- instead we add items on
// demand.
//
Status = NDIS_STATUS_SUCCESS;
} while (FALSE);
EXIT() return Status; }
VOID arpDeinitializeConstBufferPool( IN ARP_CONST_BUFFER_POOL *pHdrPool, IN PRM_STACK_RECORD pSR ) /*++
Routine Description:
Deinitialize a previously-initialized const buffer pool. Free all buffers. buffers. This function must ONLY be called when there are no outstanding allocated buffers.
Arguments:
pHdrPool - const buffer pool to deinitialize
--*/ { SLIST_ENTRY * pListEntry; ENTER("arpDeinitializeConstBufferPool", 0x0db6f5b2)
// There should be no outstanding buffers...
//
ASSERTEX(pHdrPool->NumAllocd == pHdrPool->NumInCache, pHdrPool);
// (DBG) Delete the association we assume was previously added when pHdrPool
// was initialized.
//
DBG_DELASSOC( pHdrPool->pOwningObject, pHdrPool, // Entity1
NULL, // Entity2 (unused)
ARPASSOC_CBUFPOOL_ALLOC, // AssocID
pSR );
// Free any buffers in the cache...
//
while(1) {
pListEntry = ExInterlockedPopEntrySList( &pHdrPool->BufferList, &pHdrPool->NdisLock.SpinLock ); if (pListEntry!=NULL) { PNDIS_BUFFER pNdisBuffer = STRUCT_OF(NDIS_BUFFER, pListEntry, Next); InterlockedDecrement(&pHdrPool->NumInCache); NDIS_BUFFER_LINKAGE(pNdisBuffer) = NULL; NdisFreeBuffer(pNdisBuffer); } else { break; } }
ASSERTEX(pHdrPool->NumInCache==0, pHdrPool); ARP_ZEROSTRUCT(pHdrPool);
EXIT() }
PNDIS_BUFFER arpAllocateConstBuffer( ARP_CONST_BUFFER_POOL *pHdrPool ) /*++
Routine Description:
HOT PATH
Allocate and return a pre-initialized buffer from the the specified const buffer pool.
Arguments:
pHdrPool header pool from which buffer is to be allocated.
Return Value:
Non-NULL ptr to buffer on success NULL on failure (typically because the number of allocated buffers equals the maximum specified when the header pool was initialized)
--*/ { ENTER("arpAllocateConstBuffer", 0x52765841)
PNDIS_BUFFER pNdisBuffer; SLIST_ENTRY * pListEntry;
// Try to pick up a buffer from our list of pre-initialized
// buffers
//
pListEntry = ExInterlockedPopEntrySList( &pHdrPool->BufferList, &pHdrPool->NdisLock.SpinLock ); if (pListEntry != NULL) { LONG l; //
// FAST PATH
//
pNdisBuffer = STRUCT_OF(NDIS_BUFFER, pListEntry, Next); NDIS_BUFFER_LINKAGE(pNdisBuffer) = NULL; l = NdisInterlockedDecrement(&pHdrPool->NumInCache);
ASSERT(l>=0);
#define LOGBUFSTATS_TotCachedAllocs(_pHdrPool) \
NdisInterlockedIncrement(&(_pHdrPool)->stats.TotCacheAllocs);
LOGBUFSTATS_TotCachedAllocs(pHdrPool);
} else {
//
// SLOW PATH -- allocate a fresh buffer
//
if (pHdrPool->NumAllocd >= pHdrPool->MaxBuffers) { //
// Exceeded limit, we won't bother trying to allocate a new ndis buffer.
// (The MaxBuffers limit is hard for us, even if it's not for
// NdisAllocateBufferPool :-) ).
//
// Note that the above check is an approximate check, given that
// many threads may be concurrently making it.
//
#define LOGBUFSTATS_TotAllocFails(_pHdrPool) \
NdisInterlockedIncrement(&(_pHdrPool)->stats.TotAllocFails);
LOGBUFSTATS_TotAllocFails(pHdrPool); pNdisBuffer = NULL; } else { NDIS_STATUS Status;
//
// Allocate and initialize a buffer.
//
NdisAllocateBuffer( &Status, &pNdisBuffer, pHdrPool->NdisHandle, (PVOID) pHdrPool->pvMem, pHdrPool->cbMem );
//
// TODO: consider conditionally-compiling stats gathering.
//
if (FAIL(Status)) { TR_WARN( ("NdisAllocateBuffer failed: pObj 0x%p, status 0x%x\n", pHdrPool->pOwningObject, Status));
LOGBUFSTATS_TotAllocFails(pHdrPool); pNdisBuffer = NULL; } else { #define LOGBUFSTATS_TotBufAllocs(_pHdrPool) \
NdisInterlockedIncrement(&(_pHdrPool)->stats.TotBufAllocs);
LOGBUFSTATS_TotBufAllocs(pHdrPool);
NdisInterlockedIncrement(&pHdrPool->NumAllocd); } } }
return pNdisBuffer; }
VOID arpDeallocateConstBuffer( ARP_CONST_BUFFER_POOL * pHdrPool, PNDIS_BUFFER pNdisBuffer ) /*++
Routine Description:
HOT PATH
Free a buffer previously allocated by a call to arpAllocateConstBuffer.
Arguments:
pHdrPool header pool from which buffer is to be allocated. pNdisBuffer buffer to free.
--*/ { ENTER("arpDeallocateConstBuffer", 0x8a905115)
// Try to pick up a pre-initialized buffer from our list of pre-initialized
// buffers
//
if (pHdrPool->NumInCache < pHdrPool->NumBuffersToCache) { //
// FAST PATH
//
// Note that the above check is an approximate check, given that
// many threads may be concurrently making it.
//
ExInterlockedPushEntrySList( &pHdrPool->BufferList, STRUCT_OF(SLIST_ENTRY, &(pNdisBuffer->Next), Next), &(pHdrPool->NdisLock.SpinLock) );
NdisInterlockedIncrement(&pHdrPool->NumInCache); } else { LONG l; //
// SLOW PATH -- free back to buffer pool
//
NDIS_BUFFER_LINKAGE(pNdisBuffer) = NULL; NdisFreeBuffer(pNdisBuffer); l = NdisInterlockedDecrement(&pHdrPool->NumAllocd); ASSERT(l>=0); }
}
|