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.

600 lines
17 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 "ndptsp.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. static FIXSIZED_BLOCK_LIST gMSPLineObjList;
  77. VOID
  78. InitAllocator()
  79. {
  80. TspLog(DL_TRACE, "InitAllocator: entering...");
  81. InitializeCriticalSection(&gReqList.critSec);
  82. #if DBG
  83. gReqList.dwTotal = 0;
  84. #endif // DBG
  85. gReqList.pHead = NULL;
  86. InitializeCriticalSection(&gCallObjList.critSec);
  87. gCallObjList.dwSize = 0;
  88. #if DBG
  89. gCallObjList.dwTotal = 0;
  90. gCallObjList.dwUsed = 0;
  91. #endif //DBG
  92. gCallObjList.pHeadFree = NULL;
  93. InitializeCriticalSection(&gLineObjList.critSec);
  94. gLineObjList.dwSize = 0;
  95. #if DBG
  96. gLineObjList.dwTotal = 0;
  97. gLineObjList.dwUsed = 0;
  98. #endif //DBG
  99. gLineObjList.pHeadFree = NULL;
  100. InitializeCriticalSection(&gMSPLineObjList.critSec);
  101. gMSPLineObjList.dwSize = 0;
  102. #if DBG
  103. gMSPLineObjList.dwTotal = 0;
  104. gMSPLineObjList.dwUsed = 0;
  105. #endif //DBG
  106. gMSPLineObjList.pHeadFree = NULL;
  107. }
  108. VOID
  109. UninitAllocator()
  110. {
  111. DWORD i = 0, j = 0, k = 0, l = 0;
  112. while (gReqList.pHead != NULL)
  113. {
  114. PVARSIZED_BLOCK pBlock = gReqList.pHead;
  115. gReqList.pHead = gReqList.pHead->pNext;
  116. ASSERT(FALSE == pBlock->bInUse);
  117. FREE(pBlock);
  118. i++;
  119. }
  120. ASSERT(i == gReqList.dwTotal);
  121. DeleteCriticalSection(&gReqList.critSec);
  122. ASSERT(0 == gCallObjList.dwUsed);
  123. while (gCallObjList.pHeadFree != NULL)
  124. {
  125. PFIXSIZED_BLOCK pBlock = gCallObjList.pHeadFree;
  126. gCallObjList.pHeadFree = gCallObjList.pHeadFree->pNext;
  127. FREE(pBlock);
  128. j++;
  129. }
  130. ASSERT(j == gCallObjList.dwTotal);
  131. DeleteCriticalSection(&gCallObjList.critSec);
  132. ASSERT(0 == gLineObjList.dwUsed);
  133. while (gLineObjList.pHeadFree != NULL)
  134. {
  135. PFIXSIZED_BLOCK pBlock = gLineObjList.pHeadFree;
  136. gLineObjList.pHeadFree = gLineObjList.pHeadFree->pNext;
  137. FREE(pBlock);
  138. k++;
  139. }
  140. ASSERT(k == gLineObjList.dwTotal);
  141. DeleteCriticalSection(&gLineObjList.critSec);
  142. ASSERT(0 == gMSPLineObjList.dwUsed);
  143. while (gMSPLineObjList.pHeadFree != NULL)
  144. {
  145. PFIXSIZED_BLOCK pBlock = gMSPLineObjList.pHeadFree;
  146. gMSPLineObjList.pHeadFree = gMSPLineObjList.pHeadFree->pNext;
  147. FREE(pBlock);
  148. l++;
  149. }
  150. ASSERT(l == gMSPLineObjList.dwTotal);
  151. DeleteCriticalSection(&gMSPLineObjList.critSec);
  152. TspLog(DL_TRACE, "UninitAllocator: exited(%d, %d, %d, %d)", i, j, k, l);
  153. }
  154. PVOID
  155. AllocRequest(
  156. IN DWORD dwSize
  157. )
  158. {
  159. PVARSIZED_BLOCK pNew;
  160. PVARSIZED_BLOCK pPrevFree = NULL; // point to first free node's prev node
  161. BOOL bFoundFree = FALSE; // whether we have found a free node
  162. PVARSIZED_BLOCK pPrevSize = NULL; // point to node after which a node of
  163. // size dwSize would insert
  164. PVARSIZED_BLOCK pPPrevSize = NULL; // point to prev node of pPrevSize
  165. BOOL bFoundSize = FALSE; // whether we have found the right pos
  166. EnterCriticalSection(&gReqList.critSec);
  167. if (gReqList.pHead != NULL)
  168. {
  169. PVARSIZED_BLOCK pCurr = gReqList.pHead;
  170. // see if there is a large enough free mem block
  171. while ((pCurr != NULL) &&
  172. (pCurr->bInUse || // not a free node
  173. (dwSize > pCurr->dwSize))) // not large enough
  174. {
  175. if (!pCurr->bInUse) // found a free node
  176. {
  177. bFoundFree = TRUE;
  178. }
  179. if (!bFoundFree)
  180. {
  181. pPrevFree = pCurr; // move pPrevFree until
  182. // a free node is found
  183. }
  184. if (dwSize <= pCurr->dwSize) // found the location
  185. {
  186. bFoundSize = TRUE;
  187. }
  188. if (!bFoundSize)
  189. {
  190. pPPrevSize = pPrevSize;
  191. pPrevSize = pCurr; // move pPrevSize until
  192. // a larger node is found
  193. }
  194. pCurr = pCurr->pNext; // check the next one
  195. }
  196. if (pCurr != NULL) // found one
  197. {
  198. pCurr->bInUse = TRUE;
  199. LeaveCriticalSection(&gReqList.critSec);
  200. #if 0 //DBG
  201. TspLog(DL_TRACE, "pHead(%p)", gReqList.pHead);
  202. #endif //DBG
  203. return (PVOID)pCurr->bytes;
  204. }
  205. else // none of the free blocks is large enough
  206. {
  207. if (bFoundFree)
  208. {
  209. PVARSIZED_BLOCK pFree;
  210. // we are going to allocate one from the system,
  211. // to avoid having too many mem blocks outstanding
  212. // we free the smallest free block
  213. if (NULL == pPrevFree) // the head node is a free one
  214. {
  215. pFree = gReqList.pHead;
  216. gReqList.pHead = pFree->pNext;
  217. }
  218. else
  219. {
  220. pFree = pPrevFree->pNext;
  221. pPrevFree->pNext = pFree->pNext;
  222. }
  223. ASSERT(FALSE == pFree->bInUse);
  224. // if pPrevSize is the same as pFree,
  225. // reset pPrevSize to pPPrevSize
  226. if (pPrevSize == pFree)
  227. {
  228. pPrevSize = pPPrevSize;
  229. }
  230. FREE(pFree);
  231. #if DBG
  232. TspLog(DL_TRACE, "AllocRequest: after free, total(%d)",
  233. --gReqList.dwTotal);
  234. #endif //DBG
  235. }
  236. }
  237. }
  238. // make sure dwSize is ptr-size aligned
  239. dwSize = (dwSize + sizeof(PVOID) - 1) & ~(sizeof(PVOID) - 1);
  240. // need to allocate and zeroinit a mem block from the system
  241. pNew = (PVARSIZED_BLOCK)MALLOC(offsetof(VARSIZED_BLOCK, bytes) +
  242. dwSize * sizeof(BYTE));
  243. if (NULL == pNew)
  244. {
  245. TspLog(DL_ERROR, "AllocRequest: failed to alloc a req block");
  246. LeaveCriticalSection(&gReqList.critSec);
  247. return NULL;
  248. }
  249. #if DBG
  250. TspLog(DL_TRACE, "AllocRequest: after alloc, total(%d)",
  251. ++gReqList.dwTotal);
  252. #endif //DBG
  253. pNew->dwSize = dwSize;
  254. pNew->bInUse = TRUE;
  255. // insert the newly created node into the list
  256. if (NULL == pPrevSize)
  257. {
  258. pNew->pNext = gReqList.pHead;
  259. gReqList.pHead = pNew;
  260. }
  261. else
  262. {
  263. pNew->pNext = pPrevSize->pNext;
  264. pPrevSize->pNext = pNew;
  265. }
  266. LeaveCriticalSection(&gReqList.critSec);
  267. #if 0 //DBG
  268. TspLog(DL_TRACE, "pPrevSize(%p), pNew(%p), pHead(%p)",
  269. pPrevSize, pNew, gReqList.pHead);
  270. #endif //DBG
  271. // return the mem ptr
  272. return (PVOID)pNew->bytes;
  273. }
  274. VOID
  275. FreeRequest(
  276. IN PVOID pMem
  277. )
  278. {
  279. PVARSIZED_BLOCK pBlock = (PVARSIZED_BLOCK)((PBYTE)pMem -
  280. offsetof(VARSIZED_BLOCK, bytes));
  281. ASSERT((pBlock != NULL) && (TRUE == pBlock->bInUse) &&
  282. (FALSE == pBlock->bInDrv));
  283. EnterCriticalSection(&gReqList.critSec);
  284. pBlock->bInUse = FALSE;
  285. ZeroMemory(pBlock->bytes, pBlock->dwSize * sizeof(BYTE));
  286. LeaveCriticalSection(&gReqList.critSec);
  287. }
  288. //
  289. // called before passing the req to driver in an IOCTL
  290. //
  291. VOID
  292. MarkRequest(
  293. IN PVOID pMem
  294. )
  295. {
  296. PVARSIZED_BLOCK pBlock = (PVARSIZED_BLOCK)((PBYTE)pMem -
  297. offsetof(VARSIZED_BLOCK, bytes));
  298. ASSERT((pBlock != NULL) && (TRUE == pBlock->bInUse) &&
  299. (FALSE == pBlock->bInDrv));
  300. //EnterCriticalSection(&gReqList.critSec);
  301. pBlock->bInDrv = TRUE;
  302. //LeaveCriticalSection(&gReqList.critSec);
  303. }
  304. //
  305. // called after the IOCTL gets completed
  306. //
  307. VOID
  308. UnmarkRequest(
  309. IN PVOID pMem
  310. )
  311. {
  312. PVARSIZED_BLOCK pBlock = (PVARSIZED_BLOCK)((PBYTE)pMem -
  313. offsetof(VARSIZED_BLOCK, bytes));
  314. ASSERT((pBlock != NULL) && (TRUE == pBlock->bInUse) &&
  315. (TRUE == pBlock->bInDrv));
  316. //EnterCriticalSection(&gReqList.critSec);
  317. pBlock->bInDrv = FALSE;
  318. //LeaveCriticalSection(&gReqList.critSec);
  319. }
  320. PVOID
  321. AllocCallObj(
  322. DWORD dwSize
  323. )
  324. {
  325. PFIXSIZED_BLOCK pBlock;
  326. if (0 == gCallObjList.dwSize)
  327. {
  328. ASSERT(dwSize >= sizeof(PFIXSIZED_BLOCK));
  329. gCallObjList.dwSize = dwSize;
  330. }
  331. ASSERT(dwSize == gCallObjList.dwSize);
  332. EnterCriticalSection(&gCallObjList.critSec);
  333. // move the node out of the free list
  334. if (gCallObjList.pHeadFree != NULL)
  335. {
  336. pBlock = gCallObjList.pHeadFree;
  337. gCallObjList.pHeadFree = pBlock->pNext;
  338. }
  339. else
  340. {
  341. pBlock = (PFIXSIZED_BLOCK)MALLOC(dwSize);
  342. if (NULL == pBlock)
  343. {
  344. TspLog(DL_ERROR, "AllocCallObj: failed to alloc a call obj");
  345. LeaveCriticalSection(&gCallObjList.critSec);
  346. return NULL;
  347. }
  348. #if DBG
  349. TspLog(DL_TRACE, "AllocCallObj: after alloc, total(%d)",
  350. ++gCallObjList.dwTotal);
  351. #endif //DBG
  352. }
  353. #if DBG
  354. gCallObjList.dwUsed++;
  355. #endif //DBG
  356. LeaveCriticalSection(&gCallObjList.critSec);
  357. return (PVOID)pBlock;
  358. }
  359. VOID
  360. FreeCallObj(
  361. IN PVOID pCall
  362. )
  363. {
  364. PFIXSIZED_BLOCK pBlock = (PFIXSIZED_BLOCK)pCall;
  365. #if DBG
  366. static DWORD dwSum = 0;
  367. TspLog(DL_TRACE, "FreeCallObj(%d): pCall(%p)", ++dwSum, pCall);
  368. #endif //DBG
  369. ASSERT(pBlock != NULL);
  370. ZeroMemory(pBlock, gCallObjList.dwSize);
  371. EnterCriticalSection(&gCallObjList.critSec);
  372. // insert the node back into the free list
  373. pBlock->pNext = gCallObjList.pHeadFree;
  374. gCallObjList.pHeadFree = pBlock;
  375. #if DBG
  376. gCallObjList.dwUsed--;
  377. #endif //DBG
  378. LeaveCriticalSection(&gCallObjList.critSec);
  379. }
  380. PVOID
  381. AllocLineObj(
  382. DWORD dwSize
  383. )
  384. {
  385. PFIXSIZED_BLOCK pBlock;
  386. if (0 == gLineObjList.dwSize)
  387. {
  388. ASSERT(dwSize >= sizeof(PFIXSIZED_BLOCK));
  389. gLineObjList.dwSize = dwSize;
  390. }
  391. ASSERT(dwSize == gLineObjList.dwSize);
  392. EnterCriticalSection(&gLineObjList.critSec);
  393. // move the node out of the free list
  394. if (gLineObjList.pHeadFree != NULL)
  395. {
  396. pBlock = gLineObjList.pHeadFree;
  397. gLineObjList.pHeadFree = pBlock->pNext;
  398. }
  399. else
  400. {
  401. pBlock = (PFIXSIZED_BLOCK)MALLOC(dwSize);
  402. if (NULL == pBlock)
  403. {
  404. TspLog(DL_ERROR, "AllocLineObj: failed to alloc a line obj");
  405. LeaveCriticalSection(&gLineObjList.critSec);
  406. return NULL;
  407. }
  408. #if DBG
  409. TspLog(DL_TRACE, "AllocLineObj: after alloc, total(%d)",
  410. ++gLineObjList.dwTotal);
  411. #endif //DBG
  412. }
  413. #if DBG
  414. gLineObjList.dwUsed++;
  415. #endif //DBG
  416. LeaveCriticalSection(&gLineObjList.critSec);
  417. return (PVOID)pBlock;
  418. }
  419. VOID
  420. FreeLineObj(
  421. IN PVOID pLine
  422. )
  423. {
  424. PFIXSIZED_BLOCK pBlock = (PFIXSIZED_BLOCK)pLine;
  425. #if DBG
  426. static DWORD dwSum = 0;
  427. TspLog(DL_TRACE, "FreeLineObj(%d): pLine(%p)", ++dwSum, pLine);
  428. #endif //DBG
  429. ASSERT(pBlock != NULL);
  430. ZeroMemory(pBlock, gLineObjList.dwSize);
  431. EnterCriticalSection(&gLineObjList.critSec);
  432. // insert the node back into the free list
  433. pBlock->pNext = gLineObjList.pHeadFree;
  434. gLineObjList.pHeadFree = pBlock;
  435. #if DBG
  436. gLineObjList.dwUsed--;
  437. #endif //DBG
  438. LeaveCriticalSection(&gLineObjList.critSec);
  439. }
  440. PVOID
  441. AllocMSPLineObj(
  442. DWORD dwSize
  443. )
  444. {
  445. PFIXSIZED_BLOCK pBlock;
  446. if (0 == gMSPLineObjList.dwSize)
  447. {
  448. ASSERT(dwSize >= sizeof(PFIXSIZED_BLOCK));
  449. gMSPLineObjList.dwSize = dwSize;
  450. }
  451. ASSERT(dwSize == gMSPLineObjList.dwSize);
  452. EnterCriticalSection(&gMSPLineObjList.critSec);
  453. // move the node out of the free list
  454. if (gMSPLineObjList.pHeadFree != NULL)
  455. {
  456. pBlock = gMSPLineObjList.pHeadFree;
  457. gMSPLineObjList.pHeadFree = pBlock->pNext;
  458. }
  459. else
  460. {
  461. pBlock = (PFIXSIZED_BLOCK)MALLOC(dwSize);
  462. if (NULL == pBlock)
  463. {
  464. TspLog(DL_ERROR, "AllocLineObj: failed to alloc a line obj");
  465. LeaveCriticalSection(&gMSPLineObjList.critSec);
  466. return NULL;
  467. }
  468. #if DBG
  469. TspLog(DL_TRACE, "AllocLineObj: after alloc, total(%d)",
  470. ++gMSPLineObjList.dwTotal);
  471. #endif //DBG
  472. }
  473. #if DBG
  474. gMSPLineObjList.dwUsed++;
  475. #endif //DBG
  476. LeaveCriticalSection(&gMSPLineObjList.critSec);
  477. return (PVOID)pBlock;
  478. }
  479. VOID
  480. FreeMSPLineObj(
  481. IN PVOID pLine
  482. )
  483. {
  484. PFIXSIZED_BLOCK pBlock = (PFIXSIZED_BLOCK)pLine;
  485. #if DBG
  486. static DWORD dwSum = 0;
  487. TspLog(DL_TRACE, "FreeMSPLineObj(%d): pLine(%p)", ++dwSum, pLine);
  488. #endif //DBG
  489. ASSERT(pBlock != NULL);
  490. ZeroMemory(pBlock, gMSPLineObjList.dwSize);
  491. EnterCriticalSection(&gMSPLineObjList.critSec);
  492. // insert the node back into the free list
  493. pBlock->pNext = gMSPLineObjList.pHeadFree;
  494. gMSPLineObjList.pHeadFree = pBlock;
  495. #if DBG
  496. gMSPLineObjList.dwUsed--;
  497. #endif //DBG
  498. LeaveCriticalSection(&gMSPLineObjList.critSec);
  499. }