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.

468 lines
14 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 1994.
  5. //
  6. // File: freelist.cxx
  7. //
  8. // Contents: CFreeList implementations
  9. //
  10. // History: 07-Jul-94 BobDay Created
  11. //
  12. //----------------------------------------------------------------------------
  13. #include "headers.cxx"
  14. #pragma hdrstop
  15. //
  16. // Each element, when it is free, has a pointer stored within it that
  17. // points to the next free element. We can do this because we know that
  18. // the element is free, all of its data is unused. These pointers are used
  19. // as DWORDs since they can be virtual pointers (16:16).
  20. //
  21. #define CALC_NEXTPTR(lpElement) \
  22. ((LPDWORD)((DWORD)(lpElement) + m_iNextPtrOffset))
  23. //
  24. // Each block of elements has a pointer to the next block of elements. We
  25. // allocate extra room for this pointer just after all of the elements within
  26. // the block. These pointers are used as DWORDs since they can be virtual
  27. // pointers (16:16).
  28. #define CALC_BLOCKNEXTPTR(lpBlock,dwElementSectionSize) \
  29. ((LPDWORD)((DWORD)(lpBlock) + (dwElementSectionSize)))
  30. //
  31. // Here are our global free lists, created on DLL load
  32. // The block sizes are generally -1 to allow space for block
  33. // list overhead
  34. //
  35. CFreeList flFreeList16( // THUNK1632OBJ free list
  36. &mmodel16Public,
  37. sizeof(THUNK1632OBJ),
  38. 63,
  39. FIELD_OFFSET(THUNK1632OBJ, pphHolder));
  40. CFreeList flFreeList32( // THUNK3216OBJ free list
  41. &mmodel32,
  42. sizeof(THUNK3216OBJ),
  43. 63,
  44. FIELD_OFFSET(THUNK3216OBJ, pphHolder));
  45. CFreeList flHolderFreeList( // PROXYHOLDER free list
  46. &mmodel32,
  47. sizeof(PROXYHOLDER),
  48. 63,
  49. FIELD_OFFSET(PROXYHOLDER, dwFlags));
  50. CFreeList flRequestFreeList( // IID request free list
  51. &mmodel32,
  52. sizeof(IIDNODE),
  53. 7,
  54. FIELD_OFFSET(IIDNODE, pNextNode));
  55. //+---------------------------------------------------------------------------
  56. //
  57. // Method: CFreeList::CFreeList
  58. //
  59. // Arguments: pmm - Memory model to use
  60. // iElementSize - The size of the structure being made into a
  61. // free list. e.g. sizeof THUNK1632OBJ
  62. // iElementsPerBlock - How many elements to allocate at a time
  63. // (a block contains this many elements).
  64. // iNextPtrOffset - Offset within the element's structure for
  65. // the place to store the free list's next
  66. // element pointer. Sometimes (for debugging,
  67. // etc.) it is desirable to make this NOT 0
  68. // (the beginning of the element structure).
  69. //
  70. // Synopsis: constructor for CFreeList class
  71. //
  72. // History: 6-01-94 JohannP (Johann Posch) Created
  73. // 7-05-94 BobDay (Bob Day) Changed it to be list based
  74. //
  75. //----------------------------------------------------------------------------
  76. CFreeList::CFreeList( CMemoryModel *pmm,
  77. UINT iElementSize,
  78. UINT iElementsPerBlock,
  79. UINT iNextPtrOffset )
  80. {
  81. //
  82. // Save away the allocator information
  83. //
  84. m_pmm = pmm;
  85. m_iElementSize = iElementSize;
  86. m_iElementsPerBlock = iElementsPerBlock;
  87. m_iNextPtrOffset = iNextPtrOffset;
  88. //
  89. // Set the list of elements to empty
  90. //
  91. m_dwHeadElement = 0;
  92. m_dwTailElement = 0;
  93. //
  94. // Set the list of blocks to empty
  95. //
  96. m_dwHeadBlock = 0;
  97. }
  98. //+---------------------------------------------------------------------------
  99. //
  100. // Method: CFreeList::AllocElement
  101. //
  102. // Synopsis: Allocates an element from the various blocks of elements
  103. // and allocates a new block if necessary.
  104. //
  105. // Returns: 0 if failed to alloc an element,
  106. // otherwise the DWORD representing the alloc'd element.
  107. //
  108. // History: 7-05-94 BobDay (Bob Day) Created
  109. //
  110. //----------------------------------------------------------------------------
  111. DWORD CFreeList::AllocElement( void )
  112. {
  113. DWORD dwNewHeadBlock;
  114. DWORD dwElementSectionSize;
  115. DWORD dwBlockSize;
  116. LPVOID lpBlock;
  117. UINT iCnt;
  118. DWORD dwElement;
  119. LPVOID lpElement;
  120. LPDWORD lpElementNextPtr;
  121. //
  122. // If the list of available elements is empty, callback to the derived
  123. // class and make them add an entire new block of elements.
  124. //
  125. if ( m_dwHeadElement == 0 )
  126. {
  127. //
  128. // Allocate a new block
  129. //
  130. iCnt = m_iElementsPerBlock;
  131. dwElementSectionSize = m_iElementSize * m_iElementsPerBlock;
  132. //
  133. // Here we allocate an extra DWORD so that we can store in the block
  134. // the address of the next block. In this way we have a list of
  135. // blocks so that when the time comes to free them, we can find them
  136. // all.
  137. //
  138. dwBlockSize = dwElementSectionSize + sizeof(DWORD);
  139. dwNewHeadBlock = m_pmm->AllocMemory( dwBlockSize );
  140. if ( dwNewHeadBlock == 0 )
  141. {
  142. //
  143. // Yikes, the block allocator failed!
  144. //
  145. thkDebugOut((DEB_ERROR,
  146. "CFreeList::AllocElement, AllocMemory failed\n"));
  147. return 0;
  148. }
  149. //
  150. // Now initialize the block and link it into the block list.
  151. //
  152. lpBlock = m_pmm->ResolvePtr( dwNewHeadBlock, dwBlockSize );
  153. if ( lpBlock == NULL )
  154. {
  155. //
  156. // Couldn't get a pointer to the block, some memory mapping
  157. // problem?
  158. //
  159. thkDebugOut((DEB_ERROR,
  160. "CFreeList::AllocElement, "
  161. "ResolvePtr for block failed "
  162. "for address %08lX, size %08lX\n",
  163. dwNewHeadBlock, dwBlockSize ));
  164. // Try to return bad block to pool
  165. m_pmm->FreeMemory( dwNewHeadBlock );
  166. return 0;
  167. }
  168. #if DBG == 1
  169. // 0xDE = Alloc'd but not init'd
  170. memset( lpBlock, 0xDE, dwBlockSize );
  171. #endif
  172. //
  173. // Make this block point to the previous block
  174. //
  175. *CALC_BLOCKNEXTPTR(lpBlock,dwElementSectionSize) = m_dwHeadBlock;
  176. m_dwHeadBlock = dwNewHeadBlock; // Update block list
  177. m_pmm->ReleasePtr(dwNewHeadBlock);
  178. //
  179. // Now initialize all of the elements within the block to be free.
  180. //
  181. // The below loop skips the first element, free's all of the remaining
  182. // ones. This way we can return the first one and all of the rest will
  183. // be in accending order; The order doesn't really matter, but its
  184. // nice.
  185. //
  186. dwElement = dwNewHeadBlock;
  187. while ( iCnt > 1 ) // Free n-1 items (we skip the first)
  188. {
  189. --iCnt;
  190. dwElement += m_iElementSize; // Skip to next one (miss 1st one)
  191. FreeElement( dwElement );
  192. }
  193. dwElement = dwNewHeadBlock; // Use the first one as our alloc'd one
  194. }
  195. else
  196. {
  197. // We better have some blocks by now
  198. thkAssert( m_dwHeadBlock != 0 );
  199. // Better have a "end of list" too!
  200. thkAssert( m_dwTailElement != 0 );
  201. //
  202. // Grab an available element off the top (head) of the list.
  203. //
  204. dwElement = m_dwHeadElement;
  205. lpElement = m_pmm->ResolvePtr( dwElement, m_iElementSize );
  206. if ( lpElement == NULL )
  207. {
  208. //
  209. // Yikes, we weren't able to get a pointer to the element!
  210. //
  211. thkDebugOut((DEB_ERROR,
  212. "CFreeList::AllocElement, "
  213. "ResolvePtr for element failed "
  214. "for address %08lX, size %08lX\n",
  215. dwElement, m_iElementSize ));
  216. return 0;
  217. }
  218. //
  219. // Update the list to reflect the fact that we just removed the head
  220. // and replace it with the one which was pointed to by the head.
  221. //
  222. lpElementNextPtr = CALC_NEXTPTR(lpElement);
  223. m_dwHeadElement = *lpElementNextPtr;
  224. m_pmm->ReleasePtr(dwElement);
  225. //
  226. // Also, if we are now at the end of the list, then the tail element
  227. // should point to nowhere (i.e. there is nothing to insert after).
  228. //
  229. if ( m_dwHeadElement == 0 )
  230. {
  231. m_dwTailElement = 0;
  232. }
  233. }
  234. #if DBG == 1
  235. // Erase the memory being returned to highlight reuse of dead values
  236. lpElement = m_pmm->ResolvePtr( dwElement, m_iElementSize );
  237. memset( lpElement, 0xED, m_iElementSize );
  238. m_pmm->ReleasePtr(dwElement);
  239. thkDebugOut((DEB_ITRACE,
  240. "CFreeList::AllocElement, allocated element at %08lX\n",
  241. dwElement ));
  242. #endif
  243. return dwElement;
  244. }
  245. //+---------------------------------------------------------------------------
  246. //
  247. // Method: CFreeList::FreeElement
  248. //
  249. // Synopsis: Un-Allocates an element from the various blocks of elements,
  250. // basically put the element back on the free list.
  251. //
  252. // Arguments: dwElement - Element to free
  253. //
  254. // Returns: -none- Asserts if failed.
  255. //
  256. // History: 7-05-94 BobDay (Bob Day) Created
  257. //
  258. //----------------------------------------------------------------------------
  259. void CFreeList::FreeElement( DWORD dwElement )
  260. {
  261. LPVOID lpElement;
  262. LPDWORD lpElementNextPtr;
  263. DWORD dwResolved;
  264. //
  265. // First, make sure we can set this new element's next element pointer
  266. // to zero (he's going to be a the end of the list).
  267. //
  268. lpElement = m_pmm->ResolvePtr( dwElement, m_iElementSize );
  269. if ( lpElement == NULL )
  270. {
  271. //
  272. // Yikes, we couldn't get a pointer to this element's place to store
  273. // its next pointer.
  274. //
  275. thkDebugOut((DEB_ERROR,
  276. "CFreeList::FreeElement, "
  277. "ResolvePtr failed for free'd element\n"
  278. "for address %08lX, size %08lX\n",
  279. dwElement, m_iElementSize ));
  280. thkAssert(FALSE && "CFreeList::FreeElement, "
  281. "Resolve Ptr failed for free'd element\n");
  282. return;
  283. }
  284. #if DBG == 1
  285. // Fill memory so its values can't be reused
  286. if ( fZapProxy ) // Not doing this is important for
  287. // the "PrepareForCleanup" processing the OLE32
  288. // does on thread detach. ZapProxy can be used
  289. // to turn it back on.
  290. {
  291. memset(lpElement, 0xDD, m_iElementSize);
  292. }
  293. #endif
  294. lpElementNextPtr = CALC_NEXTPTR(lpElement);
  295. *lpElementNextPtr = 0; // Zap his next pointer since he'll be on the end
  296. m_pmm->ReleasePtr(dwElement);
  297. //
  298. // Add this element back onto the end (tail) of the list.
  299. //
  300. if ( m_dwTailElement == 0 )
  301. {
  302. //
  303. // Well, the list was empty, time to set it up
  304. //
  305. thkAssert( m_dwHeadElement == 0 );
  306. lpElementNextPtr = &m_dwHeadElement;
  307. dwResolved = 0;
  308. }
  309. else
  310. {
  311. //
  312. // Ok, the list wasn't empty, so we add this new one onto the end.
  313. //
  314. thkAssert( m_dwHeadElement != 0 );
  315. dwResolved = m_dwTailElement;
  316. lpElement = m_pmm->ResolvePtr( m_dwTailElement, m_iElementSize );
  317. if ( lpElement == NULL )
  318. {
  319. //
  320. // Oh no, we couldn't get a pointer to the next element pointer for
  321. // the guy who is currently the tail of the list.
  322. //
  323. thkDebugOut((DEB_ERROR,
  324. "CFreeList::FreeElement, "
  325. "ResolvePtr failed for last element\n"
  326. "for address %08lX, size %08lX\n",
  327. m_dwTailElement, m_iElementSize ));
  328. thkAssert(FALSE && "CFreeList::FreeElement, "
  329. "Resolve Ptr failed for last element\n");
  330. return;
  331. }
  332. lpElementNextPtr = CALC_NEXTPTR(lpElement);
  333. }
  334. //
  335. // Update our tail pointer to point to our newly free'd guy.
  336. //
  337. m_dwTailElement = dwElement;
  338. //
  339. // Make the last guy point to this newly free'd guy
  340. //
  341. *lpElementNextPtr = dwElement;
  342. if (dwResolved != 0)
  343. {
  344. m_pmm->ReleasePtr(dwResolved);
  345. }
  346. thkDebugOut((DEB_ITRACE,
  347. "CFreeList::FreeElement, free'd element at %08lX\n",
  348. dwElement ));
  349. }
  350. //+---------------------------------------------------------------------------
  351. //
  352. // Method: CFreeList::FreeMemoryBlocks
  353. //
  354. // Arguments: -none-
  355. //
  356. // Returns: -nothing-
  357. //
  358. // Synopsis: Called by derived destructors to allow them to free up their
  359. // contents before going away.
  360. //
  361. // History: 7-05-94 BobDay (Bob Day) Created it
  362. //
  363. //----------------------------------------------------------------------------
  364. void CFreeList::FreeMemoryBlocks( void )
  365. {
  366. DWORD dwBlock;
  367. DWORD dwElementSectionSize;
  368. DWORD dwBlockSize;
  369. DWORD dwNextBlock;
  370. LPVOID lpBlock;
  371. //
  372. // Compute some constants for this list ahead of time
  373. //
  374. dwElementSectionSize = m_iElementSize * m_iElementsPerBlock;
  375. //
  376. // Add room for that extra DWORD, block next pointer. (See comment in
  377. // AllocElement where it allocates an extra DWORD)
  378. //
  379. dwBlockSize = dwElementSectionSize + sizeof(DWORD);
  380. //
  381. // Iterate through the list of blocks free'ing them
  382. //
  383. dwBlock = m_dwHeadBlock;
  384. while( dwBlock != 0 )
  385. {
  386. //
  387. // Find the next block ptr
  388. //
  389. lpBlock = m_pmm->ResolvePtr( dwBlock, dwBlockSize );
  390. if ( lpBlock == NULL )
  391. {
  392. //
  393. // If we get an error here, we just drop out of loop
  394. //
  395. dwNextBlock = 0;
  396. }
  397. else
  398. {
  399. dwNextBlock = *CALC_BLOCKNEXTPTR(lpBlock,dwElementSectionSize);
  400. #if DBG == 1
  401. memset(lpBlock, 0xEE, dwBlockSize);
  402. #endif
  403. m_pmm->ReleasePtr(dwBlock);
  404. m_pmm->FreeMemory( dwBlock );
  405. }
  406. dwBlock = dwNextBlock;
  407. }
  408. m_dwHeadElement = 0;
  409. m_dwTailElement = 0;
  410. m_dwHeadBlock = 0;
  411. }