summaryrefslogtreecommitdiffstats
path: root/private/ntos/tdi/isn/spx/spxmem.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--private/ntos/tdi/isn/spx/spxmem.c897
1 files changed, 897 insertions, 0 deletions
diff --git a/private/ntos/tdi/isn/spx/spxmem.c b/private/ntos/tdi/isn/spx/spxmem.c
new file mode 100644
index 000000000..9cd400e5b
--- /dev/null
+++ b/private/ntos/tdi/isn/spx/spxmem.c
@@ -0,0 +1,897 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ spxmem.c
+
+Abstract:
+
+ This module contains code which implements the memory allocation wrappers.
+
+Author:
+
+ Nikhil Kamkolkar (nikhilk) 11-November-1993
+ Jameel Hyder (jameelh) Initial Version
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text( INIT, SpxInitMemorySystem)
+#pragma alloc_text( PAGE, SpxDeInitMemorySystem)
+#endif
+
+// Define module number for event logging entries
+#define FILENUM SPXMEM
+
+// Globals for this module
+// Some block sizes (like NDISSEND/NDISRECV are filled in after binding with IPX)
+USHORT spxBlkSize[NUM_BLKIDS] = // Size of each block
+ {
+ sizeof(BLK_HDR)+sizeof(TIMERLIST), // BLKID_TIMERLIST
+ 0, // BLKID_NDISSEND
+ 0 // BLKID_NDISRECV
+ };
+
+USHORT spxChunkSize[NUM_BLKIDS] = // Size of each Chunk
+ {
+ 512-BC_OVERHEAD, // BLKID_TIMERLIST
+ 512-BC_OVERHEAD, // BLKID_NDISSEND
+ 512-BC_OVERHEAD // BLKID_NDISRECV
+ };
+
+
+// Filled in after binding with IPX
+// Reference for below.
+// ( 512-BC_OVERHEAD-sizeof(BLK_CHUNK))/
+// (sizeof(BLK_HDR)+sizeof(TIMERLIST)), // BLKID_TIMERLIST
+USHORT spxNumBlks[NUM_BLKIDS] = // Number of blocks per chunk
+ {
+ ( 512-BC_OVERHEAD-sizeof(BLK_CHUNK))/
+ (sizeof(BLK_HDR)+sizeof(TIMERLIST)), // BLKID_TIMERLIST
+ 0, // BLKID_NDISSEND
+ 0 // BLKID_NDISRECV
+ };
+
+CTELock spxBPLock[NUM_BLKIDS] = { 0 };
+PBLK_CHUNK spxBPHead[NUM_BLKIDS] = { 0 };
+
+
+
+
+NTSTATUS
+SpxInitMemorySystem(
+ IN PDEVICE pSpxDevice
+ )
+/*++
+
+Routine Description:
+
+ !!! MUST BE CALLED AFTER BINDING TO IPX!!!
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ LONG i;
+ NDIS_STATUS ndisStatus;
+
+ // Try to allocate the ndis buffer pool.
+ NdisAllocateBufferPool(
+ &ndisStatus,
+ &pSpxDevice->dev_NdisBufferPoolHandle,
+ 20);
+
+ if (ndisStatus != NDIS_STATUS_SUCCESS)
+ return(STATUS_INSUFFICIENT_RESOURCES);
+
+ for (i = 0; i < NUM_BLKIDS; i++)
+ CTEInitLock (&spxBPLock[i]);
+
+ // Set the sizes in the block id info arrays.
+ for (i = 0; i < NUM_BLKIDS; i++)
+ {
+ // BUGBUG: Do it.
+ switch (i)
+ {
+ case BLKID_NDISSEND:
+
+#ifdef SPX_OWN_PACKETS
+ spxBlkSize[i] = sizeof(BLK_HDR) +
+ sizeof(SPX_SEND_RESD) +
+ NDIS_PACKET_SIZE +
+ IpxMacHdrNeeded +
+ MIN_IPXSPX2_HDRSIZE;
+#else
+ spxBlkSize[i] = sizeof(PNDIS_PACKET);
+#endif
+
+ //
+ // Round the block size up to the next 8-byte boundary.
+ //
+ spxBlkSize[i] = QWORDSIZEBLOCK(spxBlkSize[i]);
+
+ // Set number blocks
+ spxNumBlks[i] = ( 512-BC_OVERHEAD-sizeof(BLK_CHUNK))/spxBlkSize[i];
+ break;
+
+ case BLKID_NDISRECV:
+
+#ifdef SPX_OWN_PACKETS
+ spxBlkSize[i] = sizeof(BLK_HDR) +
+ sizeof(SPX_RECV_RESD) +
+ NDIS_PACKET_SIZE;
+#else
+ spxBlkSize[i] = sizeof(PNDIS_PACKET);
+#endif
+
+ //
+ // Round the block size up to the next 8-byte boundary.
+ //
+ spxBlkSize[i] = QWORDSIZEBLOCK(spxBlkSize[i]);
+
+ // Set number blocks
+ spxNumBlks[i] = ( 512-BC_OVERHEAD-sizeof(BLK_CHUNK))/spxBlkSize[i];
+ break;
+
+ default:
+
+ break;
+ }
+
+ }
+
+ SpxTimerScheduleEvent((TIMER_ROUTINE)spxBPAgePool,
+ BLOCK_POOL_TIMER,
+ NULL);
+}
+
+
+
+
+VOID
+SpxDeInitMemorySystem(
+ IN PDEVICE pSpxDevice
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ LONG i, j, NumBlksPerChunk;
+ PBLK_CHUNK pChunk, pFree;
+
+ for (i = 0; i < NUM_BLKIDS; i++)
+ {
+ NumBlksPerChunk = spxNumBlks[i];
+ for (pChunk = spxBPHead[i];
+ pChunk != NULL; )
+ {
+ DBGPRINT(RESOURCES, ERR,
+ ("SpxInitMemorySystem: Freeing %lx\n", pChunk));
+
+ CTEAssert (pChunk->bc_NumFrees == NumBlksPerChunk);
+
+ if ((pChunk->bc_BlkId == BLKID_NDISSEND) ||
+ (pChunk->bc_BlkId == BLKID_NDISRECV))
+ {
+ PBLK_HDR pBlkHdr;
+
+ // We need to free the Ndis stuff for these guys
+ for (j = 0, pBlkHdr = pChunk->bc_FreeHead;
+ j < NumBlksPerChunk;
+ j++, pBlkHdr = pBlkHdr->bh_Next)
+ {
+ PNDIS_PACKET pNdisPkt;
+ PNDIS_BUFFER pNdisBuffer;
+
+#ifdef SPX_OWN_PACKETS
+ // Only need to free the ndis buffer.
+ pNdisPkt = (PNDIS_PACKET)((PBYTE)pBlkHdr + sizeof(BLK_HDR));
+
+ if (pChunk->bc_BlkId == BLKID_NDISSEND)
+ {
+ NdisUnchainBufferAtFront(pNdisPkt, &pNdisBuffer);
+ if (pNdisBuffer == NULL)
+ {
+ // Something is terribly awry.
+ KeBugCheck(0);
+ }
+
+ NdisFreeBuffer(pNdisBuffer);
+
+ //
+ // Free the second MDL also
+ //
+ NdisUnchainBufferAtFront(pNdisPkt, &pNdisBuffer);
+ if (pNdisBuffer == NULL)
+ {
+ // Something is terribly awry.
+ KeBugCheck(0);
+ }
+
+ NdisFreeBuffer(pNdisBuffer);
+ }
+#else
+ // Need to free both the packet and the buffer.
+ ppNdisPkt = (PNDIS_PACKET *)((PBYTE)pBlkHdr + sizeof(BLK_HDR));
+
+ if (pChunk->bc_BlkId == BLKID_NDISSEND)
+ {
+
+ NdisUnchainBufferAtFront(*ppNdisPkt, &pNdisBuffer);
+ if (pNdisBuffer == NULL)
+ {
+ // Something is terribly awry.
+ KeBugCheck(0);
+ }
+
+ NdisFreeBuffer(pNdisBuffer);
+ }
+ NdisFreePacket(*ppNdisPkt);
+#endif
+ }
+ }
+ pFree = pChunk;
+ pChunk = pChunk->bc_Next;
+
+#ifndef SPX_OWN_PACKETS
+ // Free the ndis packet pool in chunk
+ NdisFreePacketPool((NDIS_HANDLE)pFree->bc_ChunkCtx);
+#endif
+ SpxFreeMemory(pFree);
+ }
+ }
+
+ // Free up the ndis buffer pool
+ NdisFreeBufferPool(
+ pSpxDevice->dev_NdisBufferPoolHandle);
+
+ return;
+}
+
+
+
+
+PVOID
+SpxAllocMem(
+#ifdef TRACK_MEMORY_USAGE
+ IN ULONG Size,
+ IN ULONG FileLine
+#else
+ IN ULONG Size
+#endif // TRACK_MEMORY_USAGE
+ )
+/*++
+
+Routine Description:
+
+ Allocate a block of non-paged memory. This is just a wrapper over ExAllocPool.
+ Allocation failures are error-logged. We always allocate a ULONG more than
+ the specified size to accomodate the size. This is used by SpxFreeMemory
+ to update the statistics.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PBYTE pBuf;
+ BOOLEAN zeroed;
+
+ // round up the size so that we can put a signature at the end
+ // that is on a LARGE_INTEGER boundary
+ zeroed = ((Size & ZEROED_MEMORY_TAG) == ZEROED_MEMORY_TAG);
+
+ Size = QWORDSIZEBLOCK(Size & ~ZEROED_MEMORY_TAG);
+
+ // Do the actual memory allocation. Allocate eight extra bytes so
+ // that we can store the size of the allocation for the free routine
+ // and still keep the buffer quadword aligned.
+
+ if ((pBuf = ExAllocatePoolWithTag(NonPagedPool, Size + sizeof(LARGE_INTEGER)
+#if DBG
+ + sizeof(ULONG)
+#endif
+ ,SPX_TAG)) == NULL)
+ {
+ DBGPRINT(RESOURCES, FATAL,
+ ("SpxAllocMemory: failed - size %lx\n", Size));
+
+ TMPLOGERR();
+ return NULL;
+ }
+
+ // Save the size of this block in the four extra bytes we allocated.
+ *((PULONG)pBuf) = (Size + sizeof(LARGE_INTEGER));
+
+ // Return a pointer to the memory after the size longword.
+ pBuf += sizeof(LARGE_INTEGER);
+
+#if DBG
+ *((PULONG)(pBuf+Size)) = SPX_MEMORY_SIGNATURE;
+ DBGPRINT(RESOURCES, INFO,
+ ("SpxAllocMemory: %lx Allocated %lx bytes @%lx\n",
+ *(PULONG)((PBYTE)(&Size) - sizeof(Size)), Size, pBuf));
+#endif
+
+ SpxTrackMemoryUsage((PVOID)(pBuf - sizeof(LARGE_INTEGER)), TRUE, FileLine);
+
+ if (zeroed)
+ RtlZeroMemory(pBuf, Size);
+
+ return (pBuf);
+}
+
+
+
+
+VOID
+SpxFreeMemory(
+ IN PVOID pBuf
+ )
+/*++
+
+Routine Description:
+
+ Free the block of memory allocated via SpxAllocMemory. This is
+ a wrapper around ExFreePool.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PULONG pRealBuffer;
+
+ // Get a pointer to the block allocated by ExAllocatePool --
+ // we allocate a LARGE_INTEGER at the front.
+ pRealBuffer = ((PULONG)pBuf - 2);
+
+ SpxTrackMemoryUsage(pRealBuffer, FALSE, 0);
+
+#if DBG
+ // Check the signature at the end
+ if (*(PULONG)((PCHAR)pRealBuffer + *(PULONG)pRealBuffer)
+ != SPX_MEMORY_SIGNATURE)
+ {
+ DBGPRINT(RESOURCES, FATAL,
+ ("SpxFreeMemory: Memory overrun on block %lx\n", pRealBuffer));
+
+ DBGBRK(FATAL);
+ }
+
+ *(PULONG)((PCHAR)pRealBuffer + *(PULONG)pRealBuffer) = 0;
+#endif
+
+#if DBG
+ *pRealBuffer = 0;
+#endif
+
+ // Free the pool and return.
+ ExFreePool(pRealBuffer);
+}
+
+
+
+
+#ifdef TRACK_MEMORY_USAGE
+
+#define MAX_PTR_COUNT 4*1024
+#define MAX_MEM_USERS 512
+CTELock spxMemTrackLock = {0};
+CTELockHandle lockHandle = {0};
+struct
+{
+ PVOID mem_Ptr;
+ ULONG mem_FileLine;
+} spxMemPtrs[MAX_PTR_COUNT] = {0};
+
+struct
+{
+ ULONG mem_FL;
+ ULONG mem_Count;
+} spxMemUsage[MAX_MEM_USERS] = {0};
+
+VOID
+SpxTrackMemoryUsage(
+ IN PVOID pMem,
+ IN BOOLEAN Alloc,
+ IN ULONG FileLine
+ )
+/*++
+
+Routine Description:
+
+ Keep track of memory usage by storing and clearing away pointers as and
+ when they are allocated or freed. This helps in keeping track of memory
+ leaks.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ static int i = 0;
+ int j, k;
+
+ CTEGetLock (&spxMemTrackLock, &lockHandle);
+
+ if (Alloc)
+ {
+ for (j = 0; j < MAX_PTR_COUNT; i++, j++)
+ {
+ i = i & (MAX_PTR_COUNT-1);
+ if (spxMemPtrs[i].mem_Ptr == NULL)
+ {
+ spxMemPtrs[i].mem_Ptr = pMem;
+ spxMemPtrs[i++].mem_FileLine = FileLine;
+ break;
+ }
+ }
+
+ for (k = 0; k < MAX_MEM_USERS; k++)
+ {
+ if (spxMemUsage[k].mem_FL == FileLine)
+ {
+ spxMemUsage[k].mem_Count ++;
+ break;
+ }
+ }
+ if (k == MAX_MEM_USERS)
+ {
+ for (k = 0; k < MAX_MEM_USERS; k++)
+ {
+ if (spxMemUsage[k].mem_FL == 0)
+ {
+ spxMemUsage[k].mem_FL = FileLine;
+ spxMemUsage[k].mem_Count = 1;
+ break;
+ }
+ }
+ }
+ if (k == MAX_MEM_USERS)
+ {
+ DBGPRINT(RESOURCES, ERR,
+ ("SpxTrackMemoryUsage: Out of space on spxMemUsage !!!\n"));
+
+ DBGBRK(FATAL);
+ }
+ }
+ else
+ {
+ for (j = 0, k = i; j < MAX_PTR_COUNT; j++, k--)
+ {
+ k = k & (MAX_PTR_COUNT-1);
+ if (spxMemPtrs[k].mem_Ptr == pMem)
+ {
+ spxMemPtrs[k].mem_Ptr = 0;
+ spxMemPtrs[k].mem_FileLine = 0;
+ break;
+ }
+ }
+ }
+
+ CTEFreeLock (&spxMemTrackLock, lockHandle);
+
+ if (j == MAX_PTR_COUNT)
+ {
+ DBGPRINT(RESOURCES, ERR,
+ ("SpxTrackMemoryUsage: %s\n", Alloc ? "Table Full" : "Can't find"));
+
+ DBGBRK(FATAL);
+ }
+}
+
+#endif // TRACK_MEMORY_USAGE
+
+
+
+
+PVOID
+SpxBPAllocBlock(
+ IN BLKID BlockId
+ )
+/*++
+
+Routine Description:
+
+ Alloc a block of memory from the block pool package. This is written to speed up
+ operations where a lot of small fixed size allocations/frees happen. Going to
+ ExAllocPool() in these cases is expensive.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PBLK_HDR pBlk = NULL;
+ PBLK_CHUNK pChunk, *ppChunkHead;
+ USHORT BlkSize;
+ CTELockHandle lockHandle;
+ PSPX_SEND_RESD pSendResd;
+ PSPX_RECV_RESD pRecvResd;
+ PNDIS_PACKET pNdisPkt;
+ PNDIS_BUFFER pNdisBuffer;
+ PNDIS_BUFFER pNdisIpxSpxBuffer;
+
+
+ CTEAssert (BlockId < NUM_BLKIDS);
+
+ if (BlockId < NUM_BLKIDS)
+ {
+ BlkSize = spxBlkSize[BlockId];
+ ppChunkHead = &spxBPHead[BlockId];
+
+ CTEGetLock(&spxBPLock[BlockId], &lockHandle);
+
+ for (pChunk = *ppChunkHead;
+ pChunk != NULL;
+ pChunk = pChunk->bc_Next)
+ {
+ CTEAssert(pChunk->bc_BlkId == BlockId);
+ if (pChunk->bc_NumFrees > 0)
+ {
+ DBGPRINT(SYSTEM, INFO,
+ ("SpxBPAllocBlock: Found space in Chunk %lx\n", pChunk));
+#ifdef PROFILING
+ InterlockedIncrement( &SpxStatistics.stat_NumBPHits);
+#endif
+ break;
+ }
+ }
+
+ if (pChunk == NULL)
+ {
+ DBGPRINT(SYSTEM, INFO,
+ ("SpxBPAllocBlock: Allocating a new chunk for Id %d\n", BlockId));
+
+#ifdef PROFILING
+ InterlockedIncrement( &SpxStatistics.stat_NumBPMisses);
+#endif
+ pChunk = SpxAllocateMemory(spxChunkSize[BlockId]);
+ if (pChunk != NULL)
+ {
+ LONG i, j;
+ PBLK_HDR pBlkHdr;
+ USHORT NumBlksPerChunk;
+
+ NumBlksPerChunk = spxNumBlks[BlockId];
+ pChunk->bc_NumFrees = NumBlksPerChunk;
+ pChunk->bc_BlkId = BlockId;
+ pChunk->bc_FreeHead = (PBLK_HDR)((PBYTE)pChunk + sizeof(BLK_CHUNK));
+
+ DBGPRINT(SYSTEM, INFO,
+ ("SpxBPAllocBlock: Initializing chunk %lx\n", pChunk));
+
+ // Initialize the blocks in the chunk
+ for (i = 0, pBlkHdr = pChunk->bc_FreeHead;
+ i < NumBlksPerChunk;
+ i++, pBlkHdr = pBlkHdr->bh_Next)
+ {
+ NDIS_STATUS ndisStatus;
+
+ pBlkHdr->bh_Next = (PBLK_HDR)((PBYTE)pBlkHdr + BlkSize);
+ if (BlockId == BLKID_NDISSEND)
+ {
+ PBYTE pHdrMem;
+
+#ifdef SPX_OWN_PACKETS
+ // Point to the ndis packet,initialize it.
+ pNdisPkt = (PNDIS_PACKET)((PBYTE)pBlkHdr + sizeof(BLK_HDR));
+ NdisReinitializePacket(pNdisPkt);
+
+ // Allocate a ndis buffer descriptor describing hdr memory
+ // and queue it in.
+ pHdrMem = (PBYTE)pNdisPkt +
+ NDIS_PACKET_SIZE +
+ sizeof(SPX_SEND_RESD);
+
+ NdisAllocateBuffer(
+ &ndisStatus,
+ &pNdisBuffer,
+ SpxDevice->dev_NdisBufferPoolHandle,
+ pHdrMem,
+ IpxMacHdrNeeded);
+
+ if (ndisStatus != NDIS_STATUS_SUCCESS)
+ {
+ break;
+ }
+
+ // Link the buffer descriptor into the packet descriptor
+ NdisChainBufferAtBack(
+ pNdisPkt,
+ pNdisBuffer);
+
+
+ NdisAllocateBuffer(
+ &ndisStatus,
+ &pNdisIpxSpxBuffer,
+ SpxDevice->dev_NdisBufferPoolHandle,
+ pHdrMem + IpxMacHdrNeeded,
+ MIN_IPXSPX2_HDRSIZE);
+
+ if (ndisStatus != NDIS_STATUS_SUCCESS)
+ {
+ break;
+ }
+
+ // Link the buffer descriptor into the packet descriptor
+ NdisChainBufferAtBack(
+ pNdisPkt,
+ pNdisIpxSpxBuffer);
+
+
+
+ pSendResd = (PSPX_SEND_RESD)pNdisPkt->ProtocolReserved;
+
+#else
+ // Allocate a ndis packet pool for this chunk
+ NdisAllocatePacketPool();
+ etc.
+#endif
+
+
+ // Initialize elements of the protocol reserved structure.
+ pSendResd->sr_Id = IDENTIFIER_SPX;
+ pSendResd->sr_Reserved1 = NULL;
+ pSendResd->sr_Reserved2 = NULL;
+ pSendResd->sr_State = SPX_SENDPKT_IDLE;
+ }
+ else if (BlockId == BLKID_NDISRECV)
+ {
+#ifdef SPX_OWN_PACKETS
+ // Point to the ndis packet,initialize it.
+ pNdisPkt = (PNDIS_PACKET)((PBYTE)pBlkHdr + sizeof(BLK_HDR));
+ NdisReinitializePacket(pNdisPkt);
+
+ pRecvResd = (PSPX_RECV_RESD)pNdisPkt->ProtocolReserved;
+
+#else
+ // Allocate a ndis packet pool for this chunk
+ NdisAllocatePacketPool();
+ etc.
+#endif
+
+ // Initialize elements of the protocol reserved structure.
+ pRecvResd->rr_Id = IDENTIFIER_SPX;
+ pRecvResd->rr_State = SPX_RECVPKT_IDLE;
+ }
+ }
+
+ if (i != NumBlksPerChunk)
+ {
+ // This has to be a failure from Ndis for send blocks!!!
+ // Undo a bunch of stuff
+ CTEAssert (BlockId == BLKID_NDISSEND);
+ pBlkHdr = pChunk->bc_FreeHead;
+ for (j = 0, pBlkHdr = pChunk->bc_FreeHead;
+ j < i; j++, pBlkHdr = pBlkHdr->bh_Next)
+ {
+ NdisUnchainBufferAtFront(
+ (PNDIS_PACKET)((PBYTE)pBlkHdr + sizeof(BLK_HDR)),
+ &pNdisBuffer);
+
+ CTEAssert(pNdisBuffer != NULL);
+ NdisFreeBuffer(pNdisBuffer);
+
+ NdisUnchainBufferAtFront(
+ (PNDIS_PACKET)((PBYTE)pBlkHdr + sizeof(BLK_HDR)),
+ &pNdisIpxSpxBuffer);
+
+ if (pNdisIpxSpxBuffer)
+ {
+ NdisFreeBuffer(pNdisIpxSpxBuffer);
+ }
+ }
+
+ SpxFreeMemory(pChunk);
+ pChunk = NULL;
+ }
+ else
+ {
+ // Successfully initialized the chunk, link it in
+ pChunk->bc_Next = *ppChunkHead;
+ *ppChunkHead = pChunk;
+ }
+ }
+ }
+
+ if (pChunk != NULL)
+ {
+ CTEAssert(pChunk->bc_BlkId == BlockId);
+ DBGPRINT(RESOURCES, INFO,
+ ("SpxBPAllocBlock: Allocating a block out of chunk %lx(%d) for Id %d\n",
+ pChunk, pChunk->bc_NumFrees, BlockId));
+
+ pChunk->bc_NumFrees --;
+ pChunk->bc_Age = 0; // Reset age
+ pBlk = pChunk->bc_FreeHead;
+ pChunk->bc_FreeHead = pBlk->bh_Next;
+ pBlk->bh_pChunk = pChunk;
+
+ // Skip the block header!
+ pBlk++;
+ }
+
+ CTEFreeLock(&spxBPLock[BlockId], lockHandle);
+ }
+
+ return pBlk;
+}
+
+
+
+VOID
+SpxBPFreeBlock(
+ IN PVOID pBlock,
+ IN BLKID BlockId
+ )
+/*++
+
+Routine Description:
+
+ Return a block to its owning chunk.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PBLK_CHUNK pChunk;
+ PBLK_HDR pBlkHdr = (PBLK_HDR)((PCHAR)pBlock - sizeof(BLK_HDR));
+ CTELockHandle lockHandle;
+
+ CTEGetLock(&spxBPLock[BlockId], &lockHandle);
+
+ for (pChunk = spxBPHead[BlockId];
+ pChunk != NULL;
+ pChunk = pChunk->bc_Next)
+ {
+ CTEAssert(pChunk->bc_BlkId == BlockId);
+ if (pBlkHdr->bh_pChunk == pChunk)
+ {
+ DBGPRINT(SYSTEM, INFO,
+ ("SpxBPFreeBlock: Returning Block %lx to chunk %lx for Id %d\n",
+ pBlkHdr, pChunk, BlockId));
+
+ CTEAssert (pChunk->bc_NumFrees < spxNumBlks[BlockId]);
+ pChunk->bc_NumFrees ++;
+ pBlkHdr->bh_Next = pChunk->bc_FreeHead;
+ pChunk->bc_FreeHead = pBlkHdr;
+ break;
+ }
+ }
+ CTEAssert ((pChunk != NULL) && (pChunk->bc_FreeHead == pBlkHdr));
+
+ CTEFreeLock(&spxBPLock[BlockId], lockHandle);
+ return;
+}
+
+
+
+
+ULONG
+spxBPAgePool(
+ IN PVOID Context,
+ IN BOOLEAN TimerShuttingDown
+ )
+/*++
+
+Routine Description:
+
+ Age out the block pool of unused blocks
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PBLK_CHUNK pChunk, *ppChunk, pFree = NULL;
+ LONG i, j, NumBlksPerChunk;
+ CTELockHandle lockHandle;
+ PNDIS_PACKET pNdisPkt;
+ PNDIS_BUFFER pNdisBuffer;
+
+ if (TimerShuttingDown)
+ {
+ return TIMER_DONT_REQUEUE;
+ }
+
+ for (i = 0; i < NUM_BLKIDS; i++)
+ {
+ NumBlksPerChunk = spxNumBlks[i];
+ CTEGetLock(&spxBPLock[i], &lockHandle);
+
+ for (ppChunk = &spxBPHead[i];
+ (pChunk = *ppChunk) != NULL; )
+ {
+ if ((pChunk->bc_NumFrees == NumBlksPerChunk) &&
+ (++(pChunk->bc_Age) >= MAX_BLOCK_POOL_AGE))
+ {
+ DBGPRINT(SYSTEM, INFO,
+ ("spxBPAgePool: freeing Chunk %lx, Id %d\n",
+ pChunk, pChunk->bc_BlkId));
+
+ *ppChunk = pChunk->bc_Next;
+#ifdef PROFILING
+ InterlockedIncrement( &SpxStatistics.stat_NumBPAge);
+#endif
+ if (pChunk->bc_BlkId == BLKID_NDISSEND)
+ {
+ PBLK_HDR pBlkHdr;
+
+ // We need to free Ndis stuff for these guys
+ pBlkHdr = pChunk->bc_FreeHead;
+ for (j = 0, pBlkHdr = pChunk->bc_FreeHead;
+ j < NumBlksPerChunk;
+ j++, pBlkHdr = pBlkHdr->bh_Next)
+ {
+ pNdisPkt = (PNDIS_PACKET)((PBYTE)pBlkHdr + sizeof(BLK_HDR));
+ NdisUnchainBufferAtFront(
+ pNdisPkt,
+ &pNdisBuffer);
+
+ NdisFreeBuffer(pNdisBuffer);
+
+ NdisUnchainBufferAtFront(
+ pNdisPkt,
+ &pNdisBuffer);
+
+ NdisFreeBuffer(pNdisBuffer);
+ }
+ }
+
+ SpxFreeMemory(pChunk);
+ }
+ else
+ {
+ ppChunk = &pChunk->bc_Next;
+ }
+ }
+ CTEFreeLock(&spxBPLock[i], lockHandle);
+ }
+
+ return TIMER_REQUEUE_CUR_VALUE;
+}