Source code of Windows XP (NT5)
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.

498 lines
12 KiB

  1. /////////////////////////////////////////////////////////////////////////////
  2. // INTEL Corporation Proprietary Information
  3. // This listing is supplied under the terms of a license agreement with Intel
  4. // Corporation and many not be copied nor disclosed except in accordance
  5. // with the terms of that agreement.
  6. // Copyright (c) 1995, 1996 Intel Corporation.
  7. //
  8. //
  9. // Module Name: freelist.cpp
  10. // Abstract: source file. a data structure for maintaining a pool of memory.
  11. // Environment: MSVC 4.0, OLE 2
  12. /////////////////////////////////////////////////////////////////////////////
  13. #include "freelist.h"
  14. #include "que.h"
  15. #include "ppmerr.h"
  16. #include "debug.h" // for the ASSERT macro and assert.h; OK since compile time only
  17. long lFreeListHeapCreate = 0;
  18. long lFreeListHeapDestroy = 0;
  19. long lFreeListHeapAlloc = 0;
  20. long lFreeListHeapFree = 0;
  21. long lFreeListHeapCreateFailed = 0;
  22. // Uncomment next line to have some extra debug information
  23. // (also in free builds)
  24. // set to 1 for checking but no messages
  25. // set to 2 for error messages
  26. // set to 3 for the max available and DebugBreak
  27. // DEBUG_FREELIST is defined in sources
  28. #if DEBUG_FREELIST > 0
  29. long lFreeListLeak = 0;
  30. long lFreeListEnqueueTwice = 0;
  31. long lFreeListFreeTwice = 0;
  32. long lFreeListCorruptBegin = 0;
  33. long lFreeListCorruptEnd = 0;
  34. char begin_buf_pattern[FREE_LIST_SIG_SIZE] =
  35. {'F', 'R', 'E', 'E', 'B', 'E','G', 'N'};
  36. char end_buf_pattern[FREE_LIST_SIG_SIZE] =
  37. {'F', 'R', 'E', 'E', ' ', 'E', 'N','D'};
  38. char free_buf_pattern[FREE_LIST_SIG_SIZE] =
  39. {'F', 'R', 'E', 'E', 'B', 'U', 'F','F'};
  40. #endif
  41. #if DEBUG_FREELIST > 2
  42. #define DEBUGBREAK() DebugBreak()
  43. #else
  44. #define DEBUGBREAK()
  45. #endif
  46. FreeList::FreeList(HRESULT *phr)
  47. {
  48. DBG_MSG(DBG_ERROR, ("FreeList::FreeList: Constructor with no Params"));
  49. m_Size = 0;
  50. InitializeCriticalSection(&m_CritSect);
  51. m_HighWaterCount = 0;
  52. m_AllocatedCount = 0;
  53. m_Increment = 0;
  54. m_Tag = FREE_LIST_TAG;
  55. *phr = PPMERR(PPM_E_OUTOFMEMORY);
  56. //m_hMemAlloc = HeapCreate(HEAP_GENERATE_EXCEPTIONS, 1, 0);
  57. m_hMemAlloc = HeapCreate(0, 1, 0);
  58. ASSERT(m_hMemAlloc);
  59. if (m_hMemAlloc) {
  60. SetHandleInformation(m_hMemAlloc,
  61. HANDLE_FLAG_PROTECT_FROM_CLOSE,
  62. HANDLE_FLAG_PROTECT_FROM_CLOSE);
  63. InterlockedIncrement(&lFreeListHeapCreate);
  64. *phr = NOERROR;
  65. } else {
  66. InterlockedIncrement(&lFreeListHeapCreateFailed);
  67. }
  68. }
  69. FreeList::FreeList(int NumElements, size_t Size, HRESULT *phr)
  70. {
  71. int enqueued = 0;
  72. #ifdef PDEBUG
  73. DBG_MSG(DBG_TRACE, ("FreeList::Freelist: Constructor with 2 params"));
  74. #endif
  75. /*
  76. //Make sure there is enough memory to typecast
  77. //each item to a QueItem for storage.
  78. ASSERT(Size >= sizeof(QueueItem));
  79. ASSERT( NumElements > 0 );
  80. InitializeCriticalSection(&m_CritSect);
  81. EnterCriticalSection(&m_CritSect);
  82. m_Size = Size;
  83. m_pMemory = new char [(Size*NumElements)]; //new may not be the best memory allocator here.
  84. if (m_pMemory) {
  85. for (int i=0; i < NumElements; i++)
  86. {
  87. m_List.Enqueue((QueueItem*)&(m_pMemory[Size*i]));
  88. }
  89. }
  90. */
  91. //Make sure there is enough memory to typecast
  92. //each item to a QueItem for storage.
  93. ASSERT(Size >= sizeof(QueueItem));
  94. ASSERT( NumElements > 0 );
  95. InitializeCriticalSection(&m_CritSect);
  96. m_Size = Size;
  97. m_AllocatedCount = 0;
  98. m_Tag = FREE_LIST_TAG;
  99. *phr = PPMERR(PPM_E_OUTOFMEMORY);
  100. m_hMemAlloc = HeapCreate(0, 1, 0);
  101. ASSERT(m_hMemAlloc);
  102. if (m_hMemAlloc) {
  103. SetHandleInformation(m_hMemAlloc,
  104. HANDLE_FLAG_PROTECT_FROM_CLOSE,
  105. HANDLE_FLAG_PROTECT_FROM_CLOSE);
  106. InterlockedIncrement(&lFreeListHeapCreate);
  107. } else {
  108. InterlockedIncrement(&lFreeListHeapCreateFailed);
  109. }
  110. if ( (enqueued = AllocateAndEnqueue( NumElements )) > 0 )
  111. *phr = NOERROR;
  112. EnterCriticalSection(&m_CritSect);
  113. m_HighWaterCount = enqueued;
  114. m_Increment = 0;
  115. LeaveCriticalSection(&m_CritSect);
  116. }
  117. FreeList::FreeList(int NumElements, size_t Size, unsigned HighWaterCount,
  118. unsigned Increment, HRESULT *phr)
  119. {
  120. int enqueued = 0;
  121. ASSERT(HighWaterCount >= (unsigned)NumElements);
  122. //Make sure there is enough memory to typecast
  123. //each item to a QueItem for storage.
  124. ASSERT(Size >= sizeof(QueueItem));
  125. ASSERT( NumElements > 0 );
  126. InitializeCriticalSection(&m_CritSect);
  127. m_Size = Size;
  128. m_AllocatedCount = 0;
  129. m_Tag = FREE_LIST_TAG;
  130. *phr = PPMERR(PPM_E_OUTOFMEMORY);
  131. m_hMemAlloc = HeapCreate(0, 1, 0);
  132. ASSERT(m_hMemAlloc);
  133. if (m_hMemAlloc) {
  134. SetHandleInformation(m_hMemAlloc,
  135. HANDLE_FLAG_PROTECT_FROM_CLOSE,
  136. HANDLE_FLAG_PROTECT_FROM_CLOSE);
  137. InterlockedIncrement(&lFreeListHeapCreate);
  138. } else {
  139. InterlockedIncrement(&lFreeListHeapCreateFailed);
  140. }
  141. if ( (enqueued = AllocateAndEnqueue( NumElements )) > 0 )
  142. *phr = NOERROR;
  143. EnterCriticalSection(&m_CritSect);
  144. m_HighWaterCount = HighWaterCount;
  145. m_Increment = Increment;
  146. LeaveCriticalSection(&m_CritSect);
  147. }
  148. void * FreeList::Get()
  149. {
  150. void *v_ptr;
  151. int enqueued = 0;
  152. EnterCriticalSection(&m_CritSect);
  153. v_ptr = (void *) m_List.DequeueHead();
  154. #if DEBUG_FREELIST > 2
  155. {
  156. char str[128];
  157. wsprintf(str, "0x%X +++ %5d %5d/%2d 0x%X\n",
  158. this, m_Size, m_List.NumItems(), m_AllocatedCount, v_ptr);
  159. OutputDebugString(str);
  160. }
  161. #endif
  162. LeaveCriticalSection(&m_CritSect);
  163. if( v_ptr != NULL )
  164. {
  165. #ifdef PDEBUG
  166. DBG_MSG(DBG_TRACE, ("FreeList::Get: Successful deque"));
  167. #endif
  168. #if DEBUG_FREELIST > 0
  169. // Set signature in boundaries
  170. memcpy((char *)v_ptr - FREE_LIST_SIG_SIZE,
  171. begin_buf_pattern, FREE_LIST_SIG_SIZE);
  172. memcpy((char *)v_ptr + m_Size, end_buf_pattern, FREE_LIST_SIG_SIZE);
  173. #endif
  174. return v_ptr;
  175. }
  176. else
  177. {
  178. #ifdef PDEBUG
  179. DBG_MSG(DBG_TRACE, ("FreeList::Get: High Water Mark-case deque"));
  180. #endif
  181. if( m_AllocatedCount < m_HighWaterCount )
  182. {
  183. #if DEBUG_FREELIST > 1
  184. {
  185. char msg[128];
  186. wsprintf(msg,
  187. "0x%X +++ %5d %5d/%2d add +%d\n",
  188. this, m_Size, 0, m_AllocatedCount, m_Increment);
  189. OutputDebugString(msg);
  190. DEBUGBREAK();
  191. }
  192. #endif
  193. enqueued = AllocateAndEnqueue( m_Increment );
  194. if( enqueued > 0 )
  195. {
  196. #ifdef PDEBUG
  197. DBG_MSG(DBG_TRACE, ("FreeList::Get: High Water Mark-Successful allocate & deque"));
  198. #endif
  199. EnterCriticalSection(&m_CritSect);
  200. v_ptr = (void *)m_List.DequeueHead();
  201. #if DEBUG_FREELIST > 2
  202. {
  203. char str[128];
  204. wsprintf(str, "0x%X +++ %5d %5d/%2d 0x%X\n",
  205. this, m_Size, m_List.NumItems(),
  206. m_AllocatedCount, v_ptr);
  207. OutputDebugString(str);
  208. }
  209. #endif
  210. LeaveCriticalSection(&m_CritSect);
  211. #if DEBUG_FREELIST > 0
  212. // Set signature in boundaries
  213. memcpy((char *)v_ptr - FREE_LIST_SIG_SIZE,
  214. begin_buf_pattern, FREE_LIST_SIG_SIZE);
  215. memcpy((char *)v_ptr + m_Size,
  216. end_buf_pattern, FREE_LIST_SIG_SIZE);
  217. #endif
  218. return(v_ptr);
  219. }
  220. else
  221. {
  222. DBG_MSG(DBG_ERROR, ("FreeList::Get: High Water Mark-Could not allocate"));
  223. return NULL;
  224. }
  225. }
  226. else
  227. {
  228. DBG_MSG(DBG_ERROR, ("FreeList::Get: High Water mark-exceeded"));
  229. return NULL;
  230. }
  231. }
  232. }
  233. HRESULT FreeList::Free(void * Element)
  234. {
  235. #if DEBUG_FREELIST > 0
  236. int error = 0;
  237. int nofree = 0;
  238. #endif
  239. EnterCriticalSection(&m_CritSect);
  240. #if DEBUG_FREELIST > 2
  241. {
  242. char str[128];
  243. wsprintf(str, "0x%X --- %5d %5d/%2d 0x%X\n",
  244. this, m_Size, m_List.NumItems()+1, m_AllocatedCount, Element);
  245. OutputDebugString(str);
  246. }
  247. #endif
  248. #if DEBUG_FREELIST > 0
  249. // Check if the buffer was already released
  250. if (!memcmp((char *)Element - FREE_LIST_SIG_SIZE,
  251. free_buf_pattern, FREE_LIST_SIG_SIZE)) {
  252. #if DEBUG_FREELIST > 1
  253. char str[128];
  254. wsprintf(str,
  255. "0x%X --- Heap[0x%X]: Element in 0x%X size=0x%X "
  256. "is been freed twice\n",
  257. this, m_hMemAlloc,
  258. (char *)Element - FREE_LIST_SIG_SIZE,
  259. m_Size);
  260. OutputDebugString(str);
  261. #endif
  262. InterlockedIncrement(&lFreeListFreeTwice);
  263. nofree = 1;
  264. }
  265. // Check signatures on each boundary
  266. if (memcmp((char *)Element - FREE_LIST_SIG_SIZE,
  267. begin_buf_pattern, FREE_LIST_SIG_SIZE)) {
  268. #if DEBUG_FREELIST > 1
  269. char str[128];
  270. wsprintf(str,
  271. "0x%X --- Heap[0x%X]: Element in 0x%X size=0x%X "
  272. "has beginning signature corrupted at: 0x%X\n",
  273. this, m_hMemAlloc,
  274. (char *)Element - FREE_LIST_SIG_SIZE,
  275. m_Size,
  276. (char *)Element - FREE_LIST_SIG_SIZE);
  277. OutputDebugString(str);
  278. #endif
  279. InterlockedIncrement(&lFreeListCorruptBegin);
  280. error = 1;
  281. }
  282. if (memcmp((char *)Element + m_Size,
  283. end_buf_pattern, FREE_LIST_SIG_SIZE)) {
  284. #if DEBUG_FREELIST > 1
  285. char str[128];
  286. wsprintf(str,
  287. "0x%X --- Heap[0x%X]: Element in 0x%X size=0x%X "
  288. "has ending signature corrupted at: 0x%X\n",
  289. this, m_hMemAlloc,
  290. (char *)Element - FREE_LIST_SIG_SIZE,
  291. m_Size,
  292. (char *)Element + m_Size);
  293. OutputDebugString(str);
  294. #endif
  295. InterlockedIncrement(&lFreeListCorruptEnd);
  296. error = 1;
  297. }
  298. if (error || nofree) {
  299. DEBUGBREAK();
  300. }
  301. #endif
  302. HRESULT err;
  303. #if DEBUG_FREELIST > 0
  304. if (!nofree) {
  305. memcpy((char *)Element - FREE_LIST_SIG_SIZE,
  306. free_buf_pattern, FREE_LIST_SIG_SIZE);
  307. err = m_List.EnqueueHead((QueueItem *)Element);
  308. } else {
  309. err = NOERROR;
  310. }
  311. #else
  312. err = m_List.EnqueueHead((QueueItem *)Element);
  313. #endif
  314. LeaveCriticalSection(&m_CritSect);
  315. return(err);
  316. }
  317. int FreeList::AllocateAndEnqueue(int NumElements)
  318. {
  319. int enqueued = 0;
  320. char * pMemory = NULL;
  321. ASSERT( NumElements > 0 );
  322. // Replacement for the ASSERTs
  323. if( NumElements <= 0 )
  324. {
  325. return 0;
  326. }
  327. EnterCriticalSection(&m_CritSect);
  328. //pMemory = new char [(m_Size*NumElements)]; //new may not be the best memory allocator here.
  329. if (m_hMemAlloc) {
  330. for (int i=0; i < NumElements; i++)
  331. {
  332. // Get some more bytes to put a signature
  333. // at the beggining and end of buffer
  334. #if DEBUG_FREELIST > 0
  335. pMemory = (char *)HeapAlloc(m_hMemAlloc,
  336. 0,
  337. m_Size + FREE_LIST_SIG_SIZE*2);
  338. #else
  339. pMemory = (char *)HeapAlloc(m_hMemAlloc,
  340. 0,
  341. m_Size);
  342. #endif
  343. if(pMemory )
  344. {
  345. #ifdef PDEBUG
  346. DBG_MSG(DBG_TRACE,
  347. ("FreeList::AllocateAndEnqueue: Allocated"));
  348. #endif
  349. #if DEBUG_FREELIST > 0
  350. // Shift to make room for beggining signature
  351. pMemory += FREE_LIST_SIG_SIZE;
  352. #endif
  353. m_List.EnqueueTail((QueueItem*)(pMemory));
  354. enqueued++;
  355. InterlockedIncrement(&lFreeListHeapAlloc);
  356. pMemory = NULL;
  357. }
  358. }
  359. m_AllocatedCount+= enqueued;
  360. }
  361. LeaveCriticalSection(&m_CritSect);
  362. return enqueued;
  363. }
  364. FreeList::~FreeList()
  365. {
  366. void * v_ptr;
  367. unsigned free_count = 0;
  368. EnterCriticalSection(&m_CritSect);
  369. if (m_hMemAlloc) {
  370. while( (v_ptr = (void *) m_List.DequeueTail()) != NULL ) {
  371. // Shift pointer before freeing
  372. v_ptr = (char *)v_ptr - FREE_LIST_SIG_SIZE;
  373. if (HeapFree(m_hMemAlloc, 0, v_ptr)) {
  374. InterlockedIncrement(&lFreeListHeapFree);
  375. ++free_count;
  376. } else {
  377. #if DEBUG_FREELIST > 1
  378. char msg[128];
  379. DWORD error = GetLastError();
  380. wsprintf(msg,
  381. "0x%X FreeList::~FreeList: "
  382. "HeapFree failed: %d (0x%x)\n",
  383. this, error, error);
  384. DBG_MSG(DBG_ERROR, (msg));
  385. OutputDebugString(msg);
  386. DEBUGBREAK();
  387. #endif
  388. }
  389. }
  390. }
  391. LeaveCriticalSection(&m_CritSect);
  392. #if defined(_DEBUG) || DEBUG_FREELIST > 0
  393. if( free_count != m_AllocatedCount )
  394. {
  395. #if defined(_DEBUG) || DEBUG_FREELIST > 1
  396. char msg[128];
  397. wsprintf(msg,"0x%X FreeList::~FreeList: "
  398. "Memory leak in Freelist(size=%d) "
  399. "(free_count:%d != %d:m_AllocatedCount)\n",
  400. this, m_Size, free_count, m_AllocatedCount);
  401. OutputDebugString(msg);
  402. #endif
  403. #if DEBUG_FREELIST > 0
  404. InterlockedIncrement(&lFreeListLeak);
  405. DEBUGBREAK();
  406. #endif
  407. }
  408. #endif
  409. if (m_hMemAlloc) {
  410. SetHandleInformation(m_hMemAlloc, HANDLE_FLAG_PROTECT_FROM_CLOSE, 0);
  411. HeapDestroy(m_hMemAlloc);
  412. InterlockedIncrement(&lFreeListHeapDestroy);
  413. }
  414. m_hMemAlloc = NULL;
  415. DeleteCriticalSection(&m_CritSect);
  416. }