378 lines
9.4 KiB
C
378 lines
9.4 KiB
C
/*++
|
|
|
|
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
|
|
|
|
--*/
|
|
{
|
|
SINGLE_LIST_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;
|
|
SINGLE_LIST_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(SINGLE_LIST_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);
|
|
}
|
|
|
|
}
|