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.

505 lines
14 KiB

  1. //============================================================================
  2. // Copyright (c) 2000, Microsoft Corporation
  3. //
  4. // File: allocatr.c
  5. //
  6. // History:
  7. // Yi Sun June-28-2000 Created
  8. //
  9. // Abstract:
  10. // There could be tens of thousands of calls each day for a RAS server.
  11. // 6 or 7 requests on average per call. Each request requires to allocate
  12. // a request block of which the size can be as small as 20 bytes and as
  13. // large as 1000 bytes, all depending on both the request type and the
  14. // parameters. If all request allocation comes directly from OS, you can
  15. // imagine how bad the memory fragmentation situation would be after a
  16. // while. To avoid that, we keep a list of request blocks from the
  17. // smallest to the largest. Whenever we need to allocate one, we traverse
  18. // the list looking for the first free one that's large enough to host
  19. // the current request. If we can't find one, we allocate a block
  20. // directly from OS and insert it into the list. To avoid having lots of
  21. // small blocks in the list, we free back to the OS the smallest block
  22. // which is not currently being occupied by any request whenever we are
  23. // going to allocate a new block from the OS.
  24. // We also keep lists of call objs and line objs instead of allocating
  25. // and freeing them directly from/to OS, for the same reason (although to
  26. // a less extent) stated above.
  27. //============================================================================
  28. #include "nt.h"
  29. #include "ntrtl.h"
  30. #include "nturtl.h"
  31. #include "windows.h"
  32. #include "stddef.h"
  33. #include "tapi.h"
  34. #include "kmddsp.h"
  35. typedef struct _VARSIZED_BLOCK
  36. {
  37. DWORD dwSize; // size of the mem block
  38. BOOL bInUse; // whether occupied by a request
  39. BOOL bInDrv; // whether req is being processed by drv
  40. struct _VARSIZED_BLOCK *pNext; // points to the next block node
  41. BYTE bytes[1]; // the mem block starts from here
  42. // NOTE: bytes needs to be the last
  43. // field in the struct
  44. // NOTE: make sure bytes is following
  45. // a pointer. That way, we won't have
  46. // alignment problem
  47. } VARSIZED_BLOCK, *PVARSIZED_BLOCK;
  48. //
  49. // a sorted list of req blocks from smallest to largest
  50. //
  51. typedef struct _VARSIZED_BLOCK_LIST
  52. {
  53. #if DBG
  54. DWORD dwTotal; // total number of mem blks outstanding
  55. #endif //DBG
  56. PVARSIZED_BLOCK pHead; // points to the head of req block list
  57. CRITICAL_SECTION critSec; // shared mem protection
  58. } VARSIZED_BLOCK_LIST;
  59. typedef struct _FIXSIZED_BLOCK
  60. {
  61. struct _FIXSIZED_BLOCK *pNext; // points to the next block node
  62. } FIXSIZED_BLOCK, *PFIXSIZED_BLOCK;
  63. typedef struct _FIXSIZED_BLOCK_LIST
  64. {
  65. #if DBG
  66. DWORD dwTotal; // total number of mem blks outstanding
  67. DWORD dwUsed; // total number of mem blocks used
  68. #endif //DBG
  69. DWORD dwSize; // size of each mem block in the list
  70. PFIXSIZED_BLOCK pHeadFree; // points to the head of free blk list
  71. CRITICAL_SECTION critSec; // shared mem protection
  72. } FIXSIZED_BLOCK_LIST;
  73. static VARSIZED_BLOCK_LIST gReqList;
  74. static FIXSIZED_BLOCK_LIST gCallObjList;
  75. static FIXSIZED_BLOCK_LIST gLineObjList;
  76. VOID
  77. InitAllocator()
  78. {
  79. TspLog(DL_TRACE, "InitAllocator: entering...");
  80. InitializeCriticalSection(&gReqList.critSec);
  81. #if DBG
  82. gReqList.dwTotal = 0;
  83. #endif // DBG
  84. gReqList.pHead = NULL;
  85. InitializeCriticalSection(&gCallObjList.critSec);
  86. gCallObjList.dwSize = 0;
  87. #if DBG
  88. gCallObjList.dwTotal = 0;
  89. gCallObjList.dwUsed = 0;
  90. #endif //DBG
  91. gCallObjList.pHeadFree = NULL;
  92. InitializeCriticalSection(&gLineObjList.critSec);
  93. gLineObjList.dwSize = 0;
  94. #if DBG
  95. gLineObjList.dwTotal = 0;
  96. gLineObjList.dwUsed = 0;
  97. #endif //DBG
  98. gLineObjList.pHeadFree = NULL;
  99. }
  100. VOID
  101. UninitAllocator()
  102. {
  103. DWORD i = 0, j = 0, k = 0;
  104. while (gReqList.pHead != NULL)
  105. {
  106. PVARSIZED_BLOCK pBlock = gReqList.pHead;
  107. gReqList.pHead = gReqList.pHead->pNext;
  108. ASSERT(FALSE == pBlock->bInUse);
  109. FREE(pBlock);
  110. i++;
  111. }
  112. ASSERT(i == gReqList.dwTotal);
  113. DeleteCriticalSection(&gReqList.critSec);
  114. ASSERT(0 == gCallObjList.dwUsed);
  115. while (gCallObjList.pHeadFree != NULL)
  116. {
  117. PFIXSIZED_BLOCK pBlock = gCallObjList.pHeadFree;
  118. gCallObjList.pHeadFree = gCallObjList.pHeadFree->pNext;
  119. FREE(pBlock);
  120. j++;
  121. }
  122. ASSERT(j == gCallObjList.dwTotal);
  123. DeleteCriticalSection(&gCallObjList.critSec);
  124. ASSERT(0 == gLineObjList.dwUsed);
  125. while (gLineObjList.pHeadFree != NULL)
  126. {
  127. PFIXSIZED_BLOCK pBlock = gLineObjList.pHeadFree;
  128. gLineObjList.pHeadFree = gLineObjList.pHeadFree->pNext;
  129. FREE(pBlock);
  130. k++;
  131. }
  132. ASSERT(k == gLineObjList.dwTotal);
  133. DeleteCriticalSection(&gLineObjList.critSec);
  134. TspLog(DL_TRACE, "UninitAllocator: exited(%d, %d, %d)", i, j, k);
  135. }
  136. PVOID
  137. AllocRequest(
  138. IN DWORD dwSize
  139. )
  140. {
  141. PVARSIZED_BLOCK pNew;
  142. PVARSIZED_BLOCK pPrevFree = NULL; // point to first free node's prev node
  143. BOOL bFoundFree = FALSE; // whether we have found a free node
  144. PVARSIZED_BLOCK pPrevSize = NULL; // point to node after which a node of
  145. // size dwSize would insert
  146. PVARSIZED_BLOCK pPPrevSize = NULL; // point to prev node of pPrevSize
  147. BOOL bFoundSize = FALSE; // whether we have found the right pos
  148. EnterCriticalSection(&gReqList.critSec);
  149. if (gReqList.pHead != NULL)
  150. {
  151. PVARSIZED_BLOCK pCurr = gReqList.pHead;
  152. // see if there is a large enough free mem block
  153. while ((pCurr != NULL) &&
  154. (pCurr->bInUse || // not a free node
  155. (dwSize > pCurr->dwSize))) // not large enough
  156. {
  157. if (!pCurr->bInUse) // found a free node
  158. {
  159. bFoundFree = TRUE;
  160. }
  161. if (!bFoundFree)
  162. {
  163. pPrevFree = pCurr; // move pPrevFree until
  164. // a free node is found
  165. }
  166. if (dwSize <= pCurr->dwSize) // found the location
  167. {
  168. bFoundSize = TRUE;
  169. }
  170. if (!bFoundSize)
  171. {
  172. pPPrevSize = pPrevSize;
  173. pPrevSize = pCurr; // move pPrevSize until
  174. // a larger node is found
  175. }
  176. pCurr = pCurr->pNext; // check the next one
  177. }
  178. if (pCurr != NULL) // found one
  179. {
  180. pCurr->bInUse = TRUE;
  181. LeaveCriticalSection(&gReqList.critSec);
  182. #if 0 //DBG
  183. TspLog(DL_TRACE, "pHead(%p)", gReqList.pHead);
  184. #endif //DBG
  185. return (PVOID)pCurr->bytes;
  186. }
  187. else // none of the free blocks is large enough
  188. {
  189. if (bFoundFree)
  190. {
  191. PVARSIZED_BLOCK pFree;
  192. // we are going to allocate one from the system,
  193. // to avoid having too many mem blocks outstanding
  194. // we free the smallest free block
  195. if (NULL == pPrevFree) // the head node is a free one
  196. {
  197. pFree = gReqList.pHead;
  198. gReqList.pHead = pFree->pNext;
  199. }
  200. else
  201. {
  202. pFree = pPrevFree->pNext;
  203. pPrevFree->pNext = pFree->pNext;
  204. }
  205. ASSERT(FALSE == pFree->bInUse);
  206. // if pPrevSize is the same as pFree,
  207. // reset pPrevSize to pPPrevSize
  208. if (pPrevSize == pFree)
  209. {
  210. pPrevSize = pPPrevSize;
  211. }
  212. FREE(pFree);
  213. #if DBG
  214. TspLog(DL_TRACE, "AllocRequest: after free, total(%d)",
  215. --gReqList.dwTotal);
  216. #endif //DBG
  217. }
  218. }
  219. }
  220. // make sure dwSize is ptr-size aligned
  221. dwSize = (dwSize + sizeof(PVOID) - 1) & ~(sizeof(PVOID) - 1);
  222. // need to allocate and zeroinit a mem block from the system
  223. pNew = (PVARSIZED_BLOCK)MALLOC(offsetof(VARSIZED_BLOCK, bytes) +
  224. dwSize * sizeof(BYTE));
  225. if (NULL == pNew)
  226. {
  227. TspLog(DL_ERROR, "AllocRequest: failed to alloc a req block");
  228. LeaveCriticalSection(&gReqList.critSec);
  229. return NULL;
  230. }
  231. #if DBG
  232. TspLog(DL_TRACE, "AllocRequest: after alloc, total(%d)",
  233. ++gReqList.dwTotal);
  234. #endif //DBG
  235. pNew->dwSize = dwSize;
  236. pNew->bInUse = TRUE;
  237. // insert the newly created node into the list
  238. if (NULL == pPrevSize)
  239. {
  240. pNew->pNext = gReqList.pHead;
  241. gReqList.pHead = pNew;
  242. }
  243. else
  244. {
  245. pNew->pNext = pPrevSize->pNext;
  246. pPrevSize->pNext = pNew;
  247. }
  248. LeaveCriticalSection(&gReqList.critSec);
  249. #if 0 //DBG
  250. TspLog(DL_TRACE, "pPrevSize(%p), pNew(%p), pHead(%p)",
  251. pPrevSize, pNew, gReqList.pHead);
  252. #endif //DBG
  253. // return the mem ptr
  254. return (PVOID)pNew->bytes;
  255. }
  256. VOID
  257. FreeRequest(
  258. IN PVOID pMem
  259. )
  260. {
  261. PVARSIZED_BLOCK pBlock = (PVARSIZED_BLOCK)((PBYTE)pMem -
  262. offsetof(VARSIZED_BLOCK, bytes));
  263. ASSERT((pBlock != NULL) && (TRUE == pBlock->bInUse) &&
  264. (FALSE == pBlock->bInDrv));
  265. EnterCriticalSection(&gReqList.critSec);
  266. pBlock->bInUse = FALSE;
  267. ZeroMemory(pBlock->bytes, pBlock->dwSize * sizeof(BYTE));
  268. LeaveCriticalSection(&gReqList.critSec);
  269. }
  270. //
  271. // called before passing the req to driver in an IOCTL
  272. //
  273. VOID
  274. MarkRequest(
  275. IN PVOID pMem
  276. )
  277. {
  278. PVARSIZED_BLOCK pBlock = (PVARSIZED_BLOCK)((PBYTE)pMem -
  279. offsetof(VARSIZED_BLOCK, bytes));
  280. ASSERT((pBlock != NULL) && (TRUE == pBlock->bInUse) &&
  281. (FALSE == pBlock->bInDrv));
  282. //EnterCriticalSection(&gReqList.critSec);
  283. pBlock->bInDrv = TRUE;
  284. //LeaveCriticalSection(&gReqList.critSec);
  285. }
  286. //
  287. // called after the IOCTL gets completed
  288. //
  289. VOID
  290. UnmarkRequest(
  291. IN PVOID pMem
  292. )
  293. {
  294. PVARSIZED_BLOCK pBlock = (PVARSIZED_BLOCK)((PBYTE)pMem -
  295. offsetof(VARSIZED_BLOCK, bytes));
  296. ASSERT((pBlock != NULL) && (TRUE == pBlock->bInUse) &&
  297. (TRUE == pBlock->bInDrv));
  298. //EnterCriticalSection(&gReqList.critSec);
  299. pBlock->bInDrv = FALSE;
  300. //LeaveCriticalSection(&gReqList.critSec);
  301. }
  302. PVOID
  303. AllocCallObj(
  304. DWORD dwSize
  305. )
  306. {
  307. PFIXSIZED_BLOCK pBlock;
  308. if (0 == gCallObjList.dwSize)
  309. {
  310. ASSERT(dwSize >= sizeof(PFIXSIZED_BLOCK));
  311. gCallObjList.dwSize = dwSize;
  312. }
  313. ASSERT(dwSize == gCallObjList.dwSize);
  314. EnterCriticalSection(&gCallObjList.critSec);
  315. // move the node out of the free list
  316. if (gCallObjList.pHeadFree != NULL)
  317. {
  318. pBlock = gCallObjList.pHeadFree;
  319. gCallObjList.pHeadFree = pBlock->pNext;
  320. }
  321. else
  322. {
  323. pBlock = (PFIXSIZED_BLOCK)MALLOC(dwSize);
  324. if (NULL == pBlock)
  325. {
  326. TspLog(DL_ERROR, "AllocCallObj: failed to alloc a call obj");
  327. LeaveCriticalSection(&gCallObjList.critSec);
  328. return NULL;
  329. }
  330. #if DBG
  331. TspLog(DL_TRACE, "AllocCallObj: after alloc, total(%d)",
  332. ++gCallObjList.dwTotal);
  333. #endif //DBG
  334. }
  335. #if DBG
  336. gCallObjList.dwUsed++;
  337. #endif //DBG
  338. LeaveCriticalSection(&gCallObjList.critSec);
  339. return (PVOID)pBlock;
  340. }
  341. VOID
  342. FreeCallObj(
  343. IN PVOID pCall
  344. )
  345. {
  346. PFIXSIZED_BLOCK pBlock = (PFIXSIZED_BLOCK)pCall;
  347. #if DBG
  348. static DWORD dwSum = 0;
  349. TspLog(DL_TRACE, "FreeCallObj(%d): pCall(%p)", ++dwSum, pCall);
  350. #endif //DBG
  351. ASSERT(pBlock != NULL);
  352. ZeroMemory(pBlock, gCallObjList.dwSize);
  353. EnterCriticalSection(&gCallObjList.critSec);
  354. // insert the node back into the free list
  355. pBlock->pNext = gCallObjList.pHeadFree;
  356. gCallObjList.pHeadFree = pBlock;
  357. #if DBG
  358. gCallObjList.dwUsed--;
  359. #endif //DBG
  360. LeaveCriticalSection(&gCallObjList.critSec);
  361. }
  362. PVOID
  363. AllocLineObj(
  364. DWORD dwSize
  365. )
  366. {
  367. PFIXSIZED_BLOCK pBlock;
  368. if (0 == gLineObjList.dwSize)
  369. {
  370. ASSERT(dwSize >= sizeof(PFIXSIZED_BLOCK));
  371. gLineObjList.dwSize = dwSize;
  372. }
  373. ASSERT(dwSize == gLineObjList.dwSize);
  374. EnterCriticalSection(&gLineObjList.critSec);
  375. // move the node out of the free list
  376. if (gLineObjList.pHeadFree != NULL)
  377. {
  378. pBlock = gLineObjList.pHeadFree;
  379. gLineObjList.pHeadFree = pBlock->pNext;
  380. }
  381. else
  382. {
  383. pBlock = (PFIXSIZED_BLOCK)MALLOC(dwSize);
  384. if (NULL == pBlock)
  385. {
  386. TspLog(DL_ERROR, "AllocLineObj: failed to alloc a line obj");
  387. LeaveCriticalSection(&gLineObjList.critSec);
  388. return NULL;
  389. }
  390. #if DBG
  391. TspLog(DL_TRACE, "AllocLineObj: after alloc, total(%d)",
  392. ++gLineObjList.dwTotal);
  393. #endif //DBG
  394. }
  395. #if DBG
  396. gLineObjList.dwUsed++;
  397. #endif //DBG
  398. LeaveCriticalSection(&gLineObjList.critSec);
  399. return (PVOID)pBlock;
  400. }
  401. VOID
  402. FreeLineObj(
  403. IN PVOID pLine
  404. )
  405. {
  406. PFIXSIZED_BLOCK pBlock = (PFIXSIZED_BLOCK)pLine;
  407. #if DBG
  408. static DWORD dwSum = 0;
  409. TspLog(DL_TRACE, "FreeLineObj(%d): pLine(%p)", ++dwSum, pLine);
  410. #endif //DBG
  411. ASSERT(pBlock != NULL);
  412. ZeroMemory(pBlock, gLineObjList.dwSize);
  413. EnterCriticalSection(&gLineObjList.critSec);
  414. // insert the node back into the free list
  415. pBlock->pNext = gLineObjList.pHeadFree;
  416. gLineObjList.pHeadFree = pBlock;
  417. #if DBG
  418. gLineObjList.dwUsed--;
  419. #endif //DBG
  420. LeaveCriticalSection(&gLineObjList.critSec);
  421. }