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.

488 lines
10 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. MyHeap.h
  5. Abstract:
  6. Implementation of a (dumb and) fast heap allocator
  7. Author:
  8. Hakki T. Bostanci (hakkib) 06-Apr-2000
  9. Revision History:
  10. --*/
  11. #ifndef MYHEAP_H
  12. #define MYHEAP_H
  13. //////////////////////////////////////////////////////////////////////////
  14. //
  15. //
  16. //
  17. #ifdef _WIN32
  18. #undef ALIGNMENT
  19. #define ALIGNMENT 8
  20. #endif //WIN32
  21. #ifdef _WIN64
  22. #undef ALIGNMENT
  23. #define ALIGNMENT 16
  24. #endif //WIN64
  25. //////////////////////////////////////////////////////////////////////////
  26. //
  27. //
  28. //
  29. typedef enum { nAllocBlockSize = 64*1024 };
  30. //////////////////////////////////////////////////////////////////////////
  31. //
  32. //
  33. //
  34. template <size_t nBucketSize = nAllocBlockSize>
  35. class CMyHeap
  36. {
  37. public:
  38. CMyHeap()
  39. {
  40. InitializeCriticalSection(&m_cs);
  41. m_pBucket = 0;
  42. m_pNextFree = 0;
  43. }
  44. ~CMyHeap()
  45. {
  46. DumpAllocations();
  47. FreeAllBuckets();
  48. DeleteCriticalSection(&m_cs);
  49. }
  50. void *allocate(size_t nSize, ULONG uFlags = 0)
  51. {
  52. int nAllocSize = AllocSize(nSize);
  53. if (nAllocSize < 0)
  54. {
  55. if (uFlags & HEAP_GENERATE_EXCEPTIONS)
  56. {
  57. RaiseException(STATUS_NO_MEMORY, 0, 0, 0);
  58. }
  59. return 0;
  60. }
  61. if (!(uFlags & HEAP_NO_SERIALIZE))
  62. {
  63. EnterCriticalSection(&m_cs);
  64. }
  65. // do we have enough buffer space?
  66. if (m_pBucket == 0 ||
  67. m_pNextFree + nAllocSize > (PBYTE) m_pBucket + nBucketSize)
  68. {
  69. // if we can manage the requested allocation size,
  70. // try to allocate a new bucket
  71. if (nAllocSize > nBucketSize || AllocNewBucket() == false)
  72. {
  73. // if we fail the allocation, return 0 or raise an exception
  74. if (!(uFlags & HEAP_NO_SERIALIZE))
  75. {
  76. LeaveCriticalSection(&m_cs);
  77. }
  78. if (uFlags & HEAP_GENERATE_EXCEPTIONS)
  79. {
  80. RaiseException(STATUS_NO_MEMORY, 0, 0, 0);
  81. }
  82. return 0;
  83. }
  84. }
  85. // ok, we have enough space, allocate and initialize a block
  86. ASSERT(m_pBucket->Contains(m_pNextFree));
  87. CAllocation *pAllocation = (CAllocation *) m_pNextFree;
  88. pAllocation->m_nRefCount = 1;
  89. pAllocation->m_nDataSize = nSize;
  90. m_pNextFree += nAllocSize;
  91. m_pBucket->m_nAllocated += nAllocSize;
  92. ASSERT(m_pBucket->m_nAllocated < nBucketSize);
  93. // we are done
  94. if (!(uFlags & HEAP_NO_SERIALIZE))
  95. {
  96. LeaveCriticalSection(&m_cs);
  97. }
  98. if (uFlags & HEAP_ZERO_MEMORY)
  99. {
  100. // virtual alloc has already given us zero-init memory
  101. }
  102. return pAllocation->m_Data;
  103. }
  104. template <class T>
  105. T *allocate_array(size_t nItems, ULONG uFlags = 0)
  106. {
  107. return (T *) g_MyHeap.allocate(nItems * sizeof(T), uFlags);
  108. }
  109. void AddRef(void *pMem)
  110. {
  111. if (pMem)
  112. {
  113. CAllocation *pAllocation = CONTAINING_RECORD(pMem, CAllocation, m_Data);
  114. ASSERT(pAllocation->m_nRefCount != 0);
  115. InterlockedIncrement(&pAllocation->m_nRefCount);
  116. }
  117. }
  118. void deallocate(void *pMem, ULONG uFlags = 0)
  119. {
  120. if (!(uFlags & HEAP_NO_SERIALIZE))
  121. {
  122. EnterCriticalSection(&m_cs);
  123. }
  124. // find which bucket this allocation belongs to
  125. CBucket *pBucket;
  126. if (nBucketSize == nAllocBlockSize)
  127. {
  128. // if the bucket size is aligned with the VirtualAlloc block size,
  129. // then simply zero the lower WORD to reach to the base address
  130. pBucket = (CBucket *) ((UINT_PTR)pMem & ~(nAllocBlockSize-1));
  131. }
  132. else
  133. {
  134. // the general case: find the bucket by walking though each one
  135. for (
  136. pBucket = m_pBucket;
  137. pBucket != 0 && !pBucket->Contains(pMem);
  138. pBucket = pBucket->m_pNextBucket
  139. );
  140. }
  141. // if we have found the container bucket, release the allocation
  142. if (pBucket)
  143. {
  144. CAllocation *pAllocation = CONTAINING_RECORD(pMem, CAllocation, m_Data);
  145. pAllocation->m_nRefCount -= 1;
  146. ASSERT(pAllocation->m_nRefCount >= 0);
  147. // delete the allocation if the reference count is zero
  148. if (pAllocation->m_nRefCount == 0)
  149. {
  150. pBucket->m_nAllocated -= AllocSize(pAllocation->m_nDataSize);
  151. ASSERT(pBucket->m_nAllocated >= 0);
  152. // if all the allocation units in this bucket are freed,
  153. // free the bucket
  154. if (pBucket->m_nAllocated == 0)
  155. {
  156. FreeBucket(pBucket);
  157. }
  158. }
  159. }
  160. if (!(uFlags & HEAP_NO_SERIALIZE))
  161. {
  162. LeaveCriticalSection(&m_cs);
  163. }
  164. }
  165. size_t max_size() const
  166. {
  167. return nBucketSize;
  168. }
  169. bool DumpAllocations() const
  170. {
  171. bool bResult = true;
  172. CBucket *pBucket = m_pBucket;
  173. while (pBucket)
  174. {
  175. CAllocation *pAllocation = (CAllocation *) pBucket->m_Data;
  176. while (pAllocation->m_nDataSize != 0)
  177. {
  178. if (pAllocation->m_nRefCount != 0)
  179. {
  180. OutputDebugStringF(
  181. _T("0x%p, DataSize=%d, RefCount=%d; %s\n"),
  182. pAllocation->m_Data,
  183. pAllocation->m_nDataSize,
  184. pAllocation->m_nRefCount,
  185. pAllocation->m_Data
  186. );
  187. }
  188. pAllocation = (CAllocation *)
  189. ((PBYTE)pAllocation + AllocSize(pAllocation->m_nDataSize));
  190. }
  191. pBucket = pBucket->m_pNextBucket;
  192. }
  193. return bResult;
  194. }
  195. private:
  196. struct CBucket
  197. {
  198. CBucket *m_pNextBucket;
  199. LONG m_nAllocated;
  200. BYTE m_Data[ANYSIZE_ARRAY];
  201. bool Contains(const void *pMem) const
  202. {
  203. return
  204. (PBYTE)pMem >= (PBYTE)m_Data &&
  205. (PBYTE)pMem < (PBYTE)this + nBucketSize;
  206. }
  207. };
  208. struct CAllocation
  209. {
  210. size_t m_nDataSize;
  211. LONG m_nRefCount;
  212. BYTE m_Data[ANYSIZE_ARRAY];
  213. };
  214. private:
  215. static size_t AllocSize(int nDataSize)
  216. {
  217. return (nDataSize + FIELD_OFFSET(CAllocation, m_Data) + (ALIGNMENT-1)) & ~(ALIGNMENT-1);
  218. }
  219. bool AllocNewBucket()
  220. {
  221. CBucket *pBucket = (CBucket *) VirtualAlloc(
  222. 0,
  223. nBucketSize,
  224. MEM_COMMIT,
  225. PAGE_READWRITE
  226. );
  227. if (pBucket)
  228. {
  229. pBucket->m_pNextBucket = m_pBucket;
  230. m_pBucket = pBucket;
  231. m_pNextFree = pBucket->m_Data;
  232. return true;
  233. }
  234. return false;
  235. }
  236. void FreeBucket(CBucket *pThisBucket)
  237. {
  238. CBucket **ppBucket = &m_pBucket;
  239. ASSERT(*ppBucket != 0);
  240. while (*ppBucket != pThisBucket)
  241. {
  242. ppBucket = &((*ppBucket)->m_pNextBucket);
  243. ASSERT(*ppBucket != 0);
  244. }
  245. *ppBucket = pThisBucket->m_pNextBucket;
  246. VirtualFree(pThisBucket, 0, MEM_RELEASE);
  247. }
  248. void FreeAllBuckets()
  249. {
  250. CBucket *pBucket = m_pBucket;
  251. while (pBucket)
  252. {
  253. CBucket *pThisBucket = pBucket;
  254. pBucket = pBucket->m_pNextBucket;
  255. VirtualFree(pThisBucket, 0, MEM_RELEASE);
  256. }
  257. m_pBucket = 0;
  258. m_pNextFree = 0;
  259. }
  260. private:
  261. CRITICAL_SECTION m_cs;
  262. CBucket *m_pBucket;
  263. PBYTE m_pNextFree;
  264. };
  265. //////////////////////////////////////////////////////////////////////////
  266. //
  267. //
  268. //
  269. extern CMyHeap<> g_MyHeap;
  270. //////////////////////////////////////////////////////////////////////////
  271. //
  272. //
  273. //
  274. template <class T>
  275. class CMyAlloc //: public allocator<T>
  276. {
  277. public:
  278. typedef size_t size_type;
  279. typedef ptrdiff_t difference_type;
  280. typedef T *pointer;
  281. typedef const T *const_pointer;
  282. typedef T &reference;
  283. typedef const T &const_reference;
  284. typedef T value_type;
  285. pointer allocate(size_type N, const void *)
  286. {
  287. return (pointer) g_MyHeap.allocate(N);
  288. }
  289. char *_Charalloc(size_type N)
  290. {
  291. return (char *) g_MyHeap.allocate(N);
  292. }
  293. void deallocate(void *P, size_type)
  294. {
  295. g_MyHeap.deallocate(P);
  296. }
  297. size_type max_size() const
  298. {
  299. return g_MyHeap.max_size();
  300. }
  301. };
  302. template<class T, class U>
  303. inline bool operator ==(const CMyAlloc<T>&, const CMyAlloc<U>&)
  304. {
  305. return true;
  306. }
  307. template<class T, class U>
  308. inline bool operator !=(const CMyAlloc<T>&, const CMyAlloc<U>&)
  309. {
  310. return false;
  311. }
  312. //////////////////////////////////////////////////////////////////////////
  313. //
  314. //
  315. //
  316. class CMyStr
  317. {
  318. public:
  319. CMyStr()
  320. {
  321. m_pStr = 0;
  322. }
  323. ~CMyStr()
  324. {
  325. g_MyHeap.deallocate(m_pStr);
  326. }
  327. explicit CMyStr(int nLength)
  328. {
  329. m_pStr = (PTSTR) g_MyHeap.allocate(nLength * sizeof(TCHAR));
  330. m_pStr[0] = _T('\0');
  331. }
  332. CMyStr(PCTSTR pStr)
  333. {
  334. DupStr(pStr);
  335. }
  336. CMyStr(const CMyStr &rhs)
  337. {
  338. g_MyHeap.AddRef(rhs.m_pStr);
  339. m_pStr = rhs.m_pStr;
  340. }
  341. CMyStr &operator =(PCTSTR pStr)
  342. {
  343. g_MyHeap.deallocate(m_pStr);
  344. DupStr(pStr);
  345. return *this;
  346. }
  347. CMyStr &operator =(const CMyStr &rhs)
  348. {
  349. g_MyHeap.AddRef(rhs.m_pStr);
  350. g_MyHeap.deallocate(m_pStr);
  351. m_pStr = rhs.m_pStr;
  352. return *this;
  353. }
  354. operator PTSTR()
  355. {
  356. return m_pStr;
  357. }
  358. operator PCTSTR() const
  359. {
  360. return m_pStr;
  361. }
  362. private:
  363. void DupStr(PCTSTR pStr)
  364. {
  365. if (!pStr)
  366. {
  367. pStr = _T("");
  368. }
  369. m_pStr = (PTSTR) g_MyHeap.allocate((_tcslen(pStr) + 1) * sizeof(TCHAR));
  370. if (m_pStr)
  371. {
  372. _tcscpy(m_pStr, pStr);
  373. }
  374. }
  375. private:
  376. PTSTR m_pStr;
  377. };
  378. #endif //MYHEAP_H