/*++ Copyright (c) 1996,1997 Microsoft Corporation Module Name: FRAMEBUF.CPP Abstract: Manages Memory for Send/Receive Frames. BUGBUG: when you have time do an intelligent implementation, for now this is just a frame cache. Author: Aaron Ogus (aarono) Environment: Win32/COM Revision History: Date Author Description ====== ====== ============================================================ 12/10/96 aarono Original 6/6/98 aarono More debug checks, shrink pool. --*/ #include #include "newdpf.h" #include #include #include #include "mydebug.h" #include "bufmgr.h" #include "macros.h" #define MAX_FRAMES_ON_LIST 16 #define MIN_FRAMES_ON_LIST 8 typedef struct _frame { BILINK Bilink; UINT len; UCHAR data[0]; } FRAME, *PFRAME; BILINK FrameList; UINT nFramesOnList=0; UINT TotalFrameMemory=0; CRITICAL_SECTION FrameLock; #ifdef DEBUG void DebugChkFrameList() { BILINK *pBilink; PFRAME pFrameWalker; DWORD count=0; DWORD totalsize=0; DWORD fBreak=FALSE; Lock(&FrameLock); pBilink=FrameList.next; while(pBilink != &FrameList){ pFrameWalker=CONTAINING_RECORD(pBilink,FRAME,Bilink); pBilink=pBilink->next; count++; totalsize+=pFrameWalker->len; } if(totalsize != TotalFrameMemory){ DPF(0, "Total Frame Memory says %d but I count %d\n",TotalFrameMemory, totalsize); fBreak=TRUE; } if(count != nFramesOnList){ DPF(0, "nFramesOnList %d but I count %d\n",nFramesOnList, count); fBreak=TRUE; } if(fBreak){ DEBUG_BREAK(); } Unlock(&FrameLock); } #else #define DebugChkFrameList() #endif VOID InitFrameBuffers(VOID) { InitBilink(&FrameList); InitializeCriticalSection(&FrameLock); nFramesOnList=0; TotalFrameMemory=0; } VOID FiniFrameBuffers(VOID) { BILINK *pBilink; PFRAME pFrame; Lock(&FrameLock); while(!EMPTY_BILINK(&FrameList)){ pBilink=FrameList.next; pFrame=CONTAINING_RECORD(pBilink,FRAME,Bilink); Delete(pBilink); My_GlobalFree(pFrame); } nFramesOnList=0; TotalFrameMemory=0; Unlock(&FrameLock); DeleteCriticalSection(&FrameLock); } VOID ReleaseFrameBufferMemory(PUCHAR pFrameData) { PFRAME pFrame; BILINK FramesToFree; BILINK *pBilink; Lock(&FrameLock); DebugChkFrameList(); InitBilink(&FramesToFree); pFrame=CONTAINING_RECORD(pFrameData,FRAME,data); InsertAfter(&pFrame->Bilink, &FrameList); nFramesOnList++; TotalFrameMemory+=pFrame->len; if(nFramesOnList > MAX_FRAMES_ON_LIST){ while(nFramesOnList > MIN_FRAMES_ON_LIST){ pBilink=FrameList.next; pFrame=CONTAINING_RECORD(pBilink,FRAME,Bilink); nFramesOnList--; TotalFrameMemory-=pFrame->len; Delete(pBilink); DebugChkFrameList(); InsertAfter(pBilink, &FramesToFree); } } DebugChkFrameList(); ASSERT(nFramesOnList); Unlock(&FrameLock); // Drop lock before freeing, to make more effecient. while(!EMPTY_BILINK(&FramesToFree)){ pBilink=FramesToFree.next; pFrame=CONTAINING_RECORD(pBilink,FRAME,Bilink); Delete(pBilink); My_GlobalFree(pFrame); } DebugChkFrameList(); } PBUFFER GetFrameBuffer(UINT FrameLen) { PBUFFER pBuffer; PFRAME pFrame; MEMDESC memdesc; BILINK *pBilinkWalker; PFRAME pFrameBest=NULL, pFrameWalker; UINT difference=FrameLen; DPF(9,"==>GetFrameBuffer Len %d\n",FrameLen); Lock(&FrameLock); if(!EMPTY_BILINK(&FrameList)){ ASSERT(nFramesOnList); pBilinkWalker=FrameList.next; while(pBilinkWalker != &FrameList){ pFrameWalker=CONTAINING_RECORD(pBilinkWalker, FRAME, Bilink); if(pFrameWalker->len >= FrameLen){ if(FrameLen-pFrameWalker->len < difference){ difference=FrameLen-pFrameWalker->len; pFrameBest=pFrameWalker; if(!difference){ break; } } } pBilinkWalker=pBilinkWalker->next; } if(!pFrameBest){ goto alloc_new_frame; } else { pFrame=pFrameBest; } DebugChkFrameList(); Delete(&pFrame->Bilink); nFramesOnList--; TotalFrameMemory-=pFrame->len; DebugChkFrameList(); Unlock(&FrameLock); } else { alloc_new_frame: Unlock(&FrameLock); pFrame=(PFRAME)My_GlobalAlloc(GMEM_FIXED,FrameLen+sizeof(FRAME)); if(!pFrame){ return NULL; } pFrame->len=FrameLen; } memdesc.pData=&pFrame->data[0]; memdesc.len=pFrame->len; pBuffer=BuildBufferChain((&memdesc),1); if(!pBuffer){ ReleaseFrameBufferMemory(pFrame->data); DPF(9,"<==GetFrameBuffer FAILED returning %x\n",pBuffer); } else { pBuffer->dwFlags |= BFLAG_FRAME; DPF(9,"<==GetFrameBuffer %x, len %d\n",pBuffer, pFrame->len); } DebugChkFrameList(); return pBuffer; } // Release the buffer, put the memory back on the frame buffer list. VOID FreeFrameBuffer(PBUFFER pBuffer) { ASSERT(pBuffer->dwFlags & BFLAG_FRAME); ReleaseFrameBufferMemory(pBuffer->pData); FreeBuffer(pBuffer); }