windows-nt/Source/XPSP1/NT/net/1394/arp/sys/buf.c

378 lines
9.4 KiB
C
Raw Permalink Normal View History

2020-09-26 03:20:57 -05:00
/*++
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);
}
}