Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

363 lines
8.0 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. BUFMGR.C
  5. Abstract:
  6. Buffer Descriptor and Memory Manager
  7. Author:
  8. Aaron Ogus (aarono)
  9. Environment:
  10. Win32/COM
  11. Revision History:
  12. Date Author Description
  13. ======= ====== ============================================================
  14. 1/13/97 aarono Original
  15. --*/
  16. #include <windows.h>
  17. #include "newdpf.h"
  18. #include <dplay.h>
  19. #include <dplaysp.h>
  20. #include <dplaypr.h>
  21. #include "arpdint.h"
  22. #include "bufmgr.h"
  23. #include "mydebug.h"
  24. #include "macros.h"
  25. CRITICAL_SECTION DoubleBufferListLock;
  26. PDOUBLEBUFFER pDoubleBufferList;
  27. UINT nDoubleBuffers;
  28. UINT cbDoubleBuffers;
  29. VOID InitBufferManager(VOID)
  30. {
  31. pDoubleBufferList=NULL;
  32. nDoubleBuffers=0;
  33. cbDoubleBuffers=0;
  34. InitializeCriticalSection(&DoubleBufferListLock);
  35. }
  36. VOID FiniBufferManager(VOID)
  37. {
  38. PDOUBLEBUFFER pDoubleBuffer = pDoubleBufferList;
  39. while(pDoubleBuffer){
  40. pDoubleBufferList=pDoubleBuffer->pNext;
  41. My_GlobalFree(pDoubleBuffer);
  42. pDoubleBuffer=pDoubleBufferList;
  43. }
  44. DeleteCriticalSection(&DoubleBufferListLock);
  45. }
  46. UINT MemDescTotalSize(PMEMDESC pMemDesc, UINT nDesc)
  47. {
  48. UINT i;
  49. UINT cbTotalSize=0;
  50. for(i=0 ; i < nDesc ; i++){
  51. cbTotalSize+=pMemDesc->len;
  52. pMemDesc++;
  53. }
  54. return cbTotalSize;
  55. }
  56. // Actually get the memory block or allocate it.
  57. PDOUBLEBUFFER GetDoubleBuffer(UINT TotalMessageSize)
  58. {
  59. PDOUBLEBUFFER pDoubleBuffer=NULL;
  60. // First Check the FreeList for a buffer of the appropriate size.
  61. if(nDoubleBuffers && (cbDoubleBuffers >= TotalMessageSize)){
  62. PDOUBLEBUFFER pPrevBuffer, pCurrentBuffer;
  63. UINT nAllowedWaste=TotalMessageSize >> 2;
  64. Lock(&DoubleBufferListLock);
  65. // Search for best fit packet. Cannot be more than 25% larger
  66. // than the actual required size.
  67. pPrevBuffer = (PDOUBLEBUFFER)&pDoubleBufferList;
  68. pCurrentBuffer = pPrevBuffer->pNext;
  69. while(pCurrentBuffer){
  70. if(pCurrentBuffer->totlen >= TotalMessageSize){
  71. if(pCurrentBuffer->totlen-TotalMessageSize < nAllowedWaste){
  72. // We have a winner, relink list over this buffer.
  73. pPrevBuffer->pNext = pCurrentBuffer->pNext;
  74. pDoubleBuffer = pCurrentBuffer;
  75. nDoubleBuffers--;
  76. cbDoubleBuffers-=pCurrentBuffer->totlen;
  77. break;
  78. }
  79. }
  80. pPrevBuffer = pCurrentBuffer;
  81. pCurrentBuffer = pCurrentBuffer->pNext;
  82. }
  83. Unlock(&DoubleBufferListLock);
  84. }
  85. if(!pDoubleBuffer){
  86. // No Buffer Found on the FreeList, so allocate one.
  87. pDoubleBuffer=(PDOUBLEBUFFER)My_GlobalAlloc(GMEM_FIXED,TotalMessageSize+sizeof(DOUBLEBUFFER));
  88. if(!pDoubleBuffer){
  89. // couldn't allocate... out of memory.
  90. DPF(0,"COULDN'T ALLOCATE DOUBLE BUFFER TO INDICATE RECEIVE, SIZE: %x\n",TotalMessageSize+sizeof(DOUBLEBUFFER));
  91. ASSERT(0);
  92. goto exit;
  93. }
  94. pDoubleBuffer->totlen = TotalMessageSize;
  95. pDoubleBuffer->dwFlags=BFLAG_DOUBLE; // double buffer buffer.
  96. // pDoubleBuffer->tLastUsed=GetTickCount(); only relevant when put back on list... throw this out??
  97. }
  98. pDoubleBuffer->pNext = NULL;
  99. pDoubleBuffer->pData = (PCHAR)&pDoubleBuffer->data;
  100. pDoubleBuffer->len = TotalMessageSize;
  101. exit:
  102. return pDoubleBuffer;
  103. }
  104. /*++
  105. Double Buffer Management strategy.
  106. When the system needs to allocate buffers locally, it does it on a per
  107. channel basis. A buffer of exactly the requested size is allocated and
  108. used to buffer the data. When the buffer is done with, it is put on
  109. the DoubleBufferList which caches the last few allocations. Since
  110. most clients tend to use the same size packet over and over, this saves
  111. the time it takes to call GlobalAlloc and My_GlobalFree for every send.
  112. Aging out entries: Every 15 seconds, a timer goes off and the system
  113. checks the age of each buffer on the DoubleBufferList. Any entry
  114. that has not been used in the last 15 seconds is actually freed.
  115. There is also a cap on the size of allocations allowed for the entire
  116. free list. It never exceeds 64K. If it does, oldest entries are
  117. thrown out until the free list is less than 64K.
  118. --*/
  119. PBUFFER GetDoubleBufferAndCopy(PMEMDESC pMemDesc, UINT nDesc)
  120. {
  121. UINT i;
  122. UINT TotalMessageSize;
  123. UINT WriteOffset;
  124. PDOUBLEBUFFER pDoubleBuffer=NULL;
  125. // Calculate the total size of the buffer
  126. TotalMessageSize=MemDescTotalSize(pMemDesc, nDesc);
  127. pDoubleBuffer=GetDoubleBuffer(TotalMessageSize);
  128. if(!pDoubleBuffer){
  129. goto exit;
  130. }
  131. // Scatter Gather Copy to Contiguous Local Buffer
  132. WriteOffset=0;
  133. for(i=0 ; i < nDesc ; i++){
  134. memcpy(&pDoubleBuffer->data[WriteOffset], pMemDesc->pData, pMemDesc->len);
  135. WriteOffset+=pMemDesc->len;
  136. pMemDesc++;
  137. }
  138. exit:
  139. return (PBUFFER)pDoubleBuffer;
  140. }
  141. VOID FreeDoubleBuffer(PBUFFER pBuffer)
  142. {
  143. PDOUBLEBUFFER pDoubleBuffer=(PDOUBLEBUFFER) pBuffer;
  144. PDOUBLEBUFFER pBufferWalker, pLargestBuffer;
  145. //
  146. // Put the local buffer on the free list.
  147. //
  148. pDoubleBuffer->tLastUsed = GetTickCount();
  149. Lock(&DoubleBufferListLock);
  150. pDoubleBuffer->pNext = pDoubleBufferList;
  151. pDoubleBufferList = pDoubleBuffer;
  152. cbDoubleBuffers += pDoubleBuffer->totlen;
  153. nDoubleBuffers++;
  154. Unlock(&DoubleBufferListLock);
  155. //
  156. // If the free list is too large, trim it
  157. //
  158. while(cbDoubleBuffers > MAX_CHANNEL_DATA || nDoubleBuffers > MAX_CHANNEL_BUFFERS){
  159. Lock(&DoubleBufferListLock);
  160. if(cbDoubleBuffers > MAX_CHANNEL_DATA || nDoubleBuffers > MAX_CHANNEL_BUFFERS){
  161. //
  162. // Free the largest buffer.
  163. //
  164. pLargestBuffer=pDoubleBufferList;
  165. pBufferWalker=pLargestBuffer->pNext;
  166. // Find the largest buffer.
  167. while(pBufferWalker){
  168. if(pBufferWalker->totlen > pLargestBuffer->totlen){
  169. pLargestBuffer=pBufferWalker;
  170. }
  171. pBufferWalker=pBufferWalker->pNext;
  172. }
  173. //
  174. // Remove the largest buffer from the list
  175. //
  176. // Find previous element - sneaky, since ptr first in struct,
  177. // take addr of list head.
  178. pBufferWalker=(PDOUBLEBUFFER)&pDoubleBufferList;
  179. while(pBufferWalker->pNext != pLargestBuffer){
  180. pBufferWalker=pBufferWalker->pNext;
  181. }
  182. // link over the largest buffer
  183. pBufferWalker->pNext=pLargestBuffer->pNext;
  184. // update object buffer information
  185. cbDoubleBuffers -= pLargestBuffer->totlen;
  186. nDoubleBuffers--;
  187. DPF(9,"Freeing Double Buffer Memory %x\n",pLargestBuffer->totlen);
  188. Unlock(&DoubleBufferListLock);
  189. My_GlobalFree(pLargestBuffer);
  190. } else {
  191. Unlock(&DoubleBufferListLock);
  192. }
  193. }
  194. DPF(9,"Total Free Double Buffer Memory %x\n",cbDoubleBuffers);
  195. }
  196. PBUFFER BuildBufferChain(PMEMDESC pMemDesc, UINT nDesc)
  197. {
  198. UINT i;
  199. PBUFFER pBuffer=NULL,pLastBuffer=NULL;
  200. ASSERT(nDesc);
  201. if(!nDesc){
  202. goto exit;
  203. }
  204. // walk backward through the array, allocating and linking
  205. // the buffers.
  206. i=nDesc;
  207. while(i){
  208. i--;
  209. // skip 0 length buffers
  210. //if(pMemDesc[i].len){
  211. pBuffer=GetBuffer();
  212. if(!pBuffer){
  213. goto err_exit;
  214. }
  215. pBuffer->pNext = pLastBuffer;
  216. pBuffer->pData = pMemDesc[i].pData;
  217. pBuffer->len = pMemDesc[i].len;
  218. pBuffer->dwFlags = 0;
  219. pLastBuffer = pBuffer;
  220. //}
  221. }
  222. // return the head of the chain to the caller
  223. exit:
  224. return pBuffer;
  225. err_exit:
  226. // Couldn't allocate enough buffers, free the ones we did alloc
  227. // and then fail.
  228. while(pLastBuffer){
  229. pBuffer=pLastBuffer->pNext;
  230. FreeBuffer(pLastBuffer);
  231. pLastBuffer=pBuffer;
  232. }
  233. ASSERT(pBuffer==NULL);
  234. goto exit;
  235. }
  236. VOID FreeBufferChainAndMemory(PBUFFER pBuffer)
  237. {
  238. PBUFFER pNext;
  239. while(pBuffer){
  240. pNext=pBuffer->pNext;
  241. if(pBuffer->dwFlags & BFLAG_DOUBLE){
  242. FreeDoubleBuffer(pBuffer);
  243. } else if(pBuffer->dwFlags & BFLAG_FRAME){
  244. FreeFrameBuffer(pBuffer);
  245. } else {
  246. FreeBuffer(pBuffer);
  247. }
  248. pBuffer=pNext;
  249. }
  250. }
  251. UINT BufferChainTotalSize(PBUFFER pBuffer)
  252. {
  253. UINT nTotalLen;
  254. ASSERT(pBuffer);
  255. if(!pBuffer){
  256. return 0;
  257. }
  258. nTotalLen=0;
  259. do{
  260. nTotalLen+=pBuffer->len;
  261. pBuffer=pBuffer->pNext;
  262. } while (pBuffer);
  263. return nTotalLen;
  264. }