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.

498 lines
10 KiB

  1. /*
  2. * M E M X . H
  3. *
  4. * Default implementation of DAV allocators.
  5. *
  6. * It is possible that sometime in the future we may decide that different
  7. * implementations of DAV may require different allocator implementations,
  8. * so each DAV implementation has its own allocator implementation file
  9. * (mem.cpp) in its own directory. However, until we need to differentiate
  10. * allocator implementations among DAV implementations (if we ever do),
  11. * it is easier to have the common default implementation in one place -- here.
  12. *
  13. * This header defines a full implementation for a fast heap allocator
  14. * and implementations for other allocators that can be used for debugging.
  15. * This file should be included exactly once by mem.cpp in each DAV implementation.
  16. *
  17. * To use the virtual heap allocator set:
  18. *
  19. * [General]
  20. * UseVirtual=1
  21. *
  22. * Copyright 1986-1997 Microsoft Corporation, All Rights Reserved
  23. */
  24. #include <singlton.h>
  25. #include <except.h>
  26. // ===================================================================================
  27. //
  28. // IHeap
  29. //
  30. // Heap interface base class.
  31. //
  32. class IHeap
  33. {
  34. public:
  35. // CREATORS
  36. //
  37. virtual ~IHeap() = 0;
  38. // ACCESSORS
  39. //
  40. virtual LPVOID Alloc( SIZE_T cb ) const = 0;
  41. virtual LPVOID Realloc( LPVOID lpv, SIZE_T cb ) const = 0;
  42. virtual VOID Free( LPVOID pv ) const = 0;
  43. };
  44. // ------------------------------------------------------------------------
  45. //
  46. // IHeap::~IHeap()
  47. //
  48. // Out of line virtual destructor necessary for proper deletion
  49. // of objects of derived classes via this class
  50. //
  51. IHeap::~IHeap() {}
  52. // ===================================================================================
  53. //
  54. // CMultiHeap
  55. //
  56. // Multi-heap implementation (provided by STAXMEM.DLL). It is significantly
  57. // faster than the process heap on multiprocessor machines because it uses
  58. // multiple internal heaps, lookaside lists and deferred freeing to reduce
  59. // contention on system heap critical sections.
  60. //
  61. class CMultiHeap :
  62. public IHeap,
  63. private Singleton<CMultiHeap>
  64. {
  65. //
  66. // Friend declarations required by Singleton template
  67. //
  68. friend class Singleton<CMultiHeap>;
  69. typedef HANDLE (WINAPI *HEAPCREATE) (
  70. ULONG cHeaps,
  71. DWORD dwFlags,
  72. SIZE_T dwInitialSize,
  73. SIZE_T dwMaxSize );
  74. typedef BOOL (WINAPI *HEAPDESTROY) ();
  75. typedef LPVOID (WINAPI *HEAPALLOC) (
  76. SIZE_T dwSize );
  77. typedef LPVOID (WINAPI *HEAPREALLOC) (
  78. LPVOID pvOld,
  79. SIZE_T dwSize );
  80. typedef BOOL (WINAPI *HEAPFREE) (
  81. LPVOID pvFree );
  82. //
  83. // Allocation functions
  84. //
  85. HEAPCREATE m_HeapCreate;
  86. HEAPDESTROY m_HeapDestroy;
  87. HEAPALLOC m_HeapAlloc;
  88. HEAPREALLOC m_HeapRealloc;
  89. HEAPFREE m_HeapFree;
  90. // CREATORS
  91. //
  92. // Declared private to ensure that arbitrary instances
  93. // of this class cannot be created. The Singleton
  94. // template (declared as a friend above) controls
  95. // the sole instance of this class.
  96. //
  97. CMultiHeap() :
  98. m_HeapCreate(NULL),
  99. m_HeapDestroy(NULL),
  100. m_HeapAlloc(NULL),
  101. m_HeapRealloc(NULL),
  102. m_HeapFree(NULL)
  103. {
  104. }
  105. // MANIPULATORS
  106. //
  107. BOOL FInit();
  108. public:
  109. // STATICS
  110. //
  111. static CMultiHeap * New();
  112. // CREATORS
  113. //
  114. ~CMultiHeap();
  115. // ACCESSORS
  116. //
  117. LPVOID Alloc( SIZE_T cb ) const;
  118. LPVOID Realloc( LPVOID lpv, SIZE_T cb ) const;
  119. VOID Free( LPVOID pv ) const;
  120. };
  121. CMultiHeap *
  122. CMultiHeap::New()
  123. {
  124. if ( CreateInstance().FInit() )
  125. return &Instance();
  126. DestroyInstance();
  127. return NULL;
  128. }
  129. BOOL
  130. CMultiHeap::FInit()
  131. {
  132. //
  133. // Load up STAXMEM.DLL - or whatever
  134. //
  135. HINSTANCE hinst = LoadLibraryExW( g_szMemDll, NULL, 0 );
  136. if ( !hinst )
  137. return FALSE;
  138. //
  139. // Get the function pointers for the multi-heap implementation
  140. //
  141. m_HeapCreate = reinterpret_cast<HEAPCREATE>(
  142. GetProcAddress( hinst, "ExchMHeapCreate" ));
  143. m_HeapDestroy = reinterpret_cast<HEAPDESTROY>(
  144. GetProcAddress( hinst, "ExchMHeapDestroy" ));
  145. m_HeapAlloc = reinterpret_cast<HEAPALLOC>(
  146. GetProcAddress( hinst, "ExchMHeapAlloc" ));
  147. m_HeapRealloc = reinterpret_cast<HEAPREALLOC>(
  148. GetProcAddress( hinst, "ExchMHeapReAlloc" ));
  149. m_HeapFree = reinterpret_cast<HEAPFREE>(
  150. GetProcAddress( hinst, "ExchMHeapFree" ));
  151. //
  152. // Make sure we found all of the entrypoints
  153. //
  154. if ( !(m_HeapCreate &&
  155. m_HeapDestroy &&
  156. m_HeapAlloc &&
  157. m_HeapRealloc &&
  158. m_HeapFree) )
  159. {
  160. return FALSE;
  161. }
  162. //
  163. // Create the multi-heap. We don't need the heap HANDLE
  164. // that is returned since none of the allocation functions
  165. // take it. We just need to know whether it succeeded.
  166. //
  167. return !!m_HeapCreate( 0, // number of heaps -- 0 means use a default
  168. // proportional to the number of CPUs.
  169. 0, // no flags
  170. 8192, // initially 8K (growable)
  171. 0 ); // size unlimited
  172. }
  173. CMultiHeap::~CMultiHeap()
  174. {
  175. if ( m_HeapDestroy )
  176. m_HeapDestroy();
  177. }
  178. LPVOID
  179. CMultiHeap::Alloc( SIZE_T cb ) const
  180. {
  181. return m_HeapAlloc( cb );
  182. }
  183. LPVOID
  184. CMultiHeap::Realloc( LPVOID lpv, SIZE_T cb ) const
  185. {
  186. return m_HeapRealloc( lpv, cb );
  187. }
  188. void
  189. CMultiHeap::Free( LPVOID lpv ) const
  190. {
  191. m_HeapFree( lpv );
  192. }
  193. //
  194. // Debug-only allocators...
  195. //
  196. #if defined(DBG)
  197. // ===================================================================================
  198. //
  199. // CVirtualHeap (X86 only)
  200. //
  201. // Places allocations at the end of virtual memory pages.
  202. // While being drastically slower than other allocators,
  203. // this one catches memory overwrites immediately by
  204. // throwing a memory access violation exception.
  205. //
  206. #if defined(_X86_)
  207. class CVirtualHeap :
  208. public IHeap,
  209. private Singleton<CVirtualHeap>
  210. {
  211. //
  212. // Friend declarations required by Singleton template
  213. //
  214. friend class Singleton<CVirtualHeap>;
  215. // CREATORS
  216. //
  217. // Declared private to ensure that arbitrary instances
  218. // of this class cannot be created. The Singleton
  219. // template (declared as a friend above) controls
  220. // the sole instance of this class.
  221. //
  222. CVirtualHeap() {}
  223. public:
  224. // STATICS
  225. //
  226. static CVirtualHeap * New()
  227. {
  228. return &CreateInstance();
  229. }
  230. // ACCESSORS
  231. //
  232. LPVOID Alloc( SIZE_T cb ) const
  233. {
  234. return VMAlloc( cb );
  235. }
  236. LPVOID Realloc( LPVOID lpv, SIZE_T cb ) const
  237. {
  238. return VMRealloc( lpv, cb );
  239. }
  240. VOID Free( LPVOID lpv ) const
  241. {
  242. VMFree( lpv );
  243. }
  244. };
  245. #endif // defined(_X86)
  246. #endif // DBG
  247. // ===================================================================================
  248. //
  249. // CHeapImpl
  250. //
  251. // Top-level heap implementation
  252. //
  253. class CHeapImpl : private RefCountedGlobal<CHeapImpl>
  254. {
  255. //
  256. // Friend declarations required by RefCountedGlobal template
  257. //
  258. friend class Singleton<CHeapImpl>;
  259. friend class RefCountedGlobal<CHeapImpl>;
  260. //
  261. // Pointer to the object that provides our heap implementation
  262. //
  263. auto_ptr<IHeap> m_pHeapImpl;
  264. // CREATORS
  265. //
  266. // Declared private to ensure that arbitrary instances
  267. // of this class cannot be created. The Singleton
  268. // template (declared as a friend above) controls
  269. // the sole instance of this class.
  270. //
  271. CHeapImpl() {}
  272. // NOT IMPLEMENTED
  273. //
  274. CHeapImpl( const CHeapImpl& );
  275. CHeapImpl& operator=( const CHeapImpl& );
  276. //
  277. // Initialization routine called
  278. // by the RefCountedGlobal template
  279. //
  280. BOOL FInit()
  281. {
  282. //
  283. // And bind to a particular heap implementation
  284. //
  285. // In DBG builds only, check whether we are being told
  286. // to use the virtual allocator heap implementation
  287. //
  288. #if defined(DBG)
  289. #if defined(_X86_)
  290. if ( GetPrivateProfileIntA( gc_szDbgGeneral,
  291. gc_szDbgUseVirtual,
  292. FALSE,
  293. gc_szDbgIni ) )
  294. {
  295. m_pHeapImpl = CVirtualHeap::New();
  296. }
  297. else
  298. #endif // defined(_X86_)
  299. #endif // DBG
  300. m_pHeapImpl = CMultiHeap::New();
  301. return !!m_pHeapImpl;
  302. }
  303. public:
  304. using RefCountedGlobal<CHeapImpl>::DwInitRef;
  305. using RefCountedGlobal<CHeapImpl>::DeinitRef;
  306. static IHeap& Heap()
  307. {
  308. Assert( Instance().m_pHeapImpl.get() != NULL );
  309. return *Instance().m_pHeapImpl;
  310. }
  311. };
  312. // ===================================================================================
  313. //
  314. // CHeap
  315. //
  316. // Top-level heap.
  317. //
  318. // This "class" (it's actually a struct) really only acts as a namespace.
  319. // I.e. its only members are static functions. It remains a class for
  320. // historical reasons (mainly to avoid changing a LOT of code from calling
  321. // "g_heap.Fn()" to simply calling "Fn()").
  322. //
  323. BOOL
  324. CHeap::FInit()
  325. {
  326. return !!CHeapImpl::DwInitRef();
  327. }
  328. void
  329. CHeap::Deinit()
  330. {
  331. CHeapImpl::DeinitRef();
  332. }
  333. LPVOID
  334. CHeap::Alloc( SIZE_T cb )
  335. {
  336. LPVOID lpv;
  337. Assert( cb > 0 );
  338. lpv = CHeapImpl::Heap().Alloc(cb);
  339. #ifndef _NOTHROW_
  340. if ( !lpv )
  341. {
  342. DebugTrace ("CHeap::Alloc() - Error allocating (%d)\n", GetLastError());
  343. throw CLastErrorException();
  344. }
  345. #endif // _NOTHROW_
  346. return lpv;
  347. }
  348. LPVOID
  349. CHeap::Realloc( LPVOID lpv, SIZE_T cb )
  350. {
  351. LPVOID lpvNew;
  352. Assert( cb > 0 );
  353. // Just in case some heap implementation doesn't handle
  354. // realloc with NULL lpv, map that case to Alloc here.
  355. //
  356. if (!lpv)
  357. lpvNew = CHeapImpl::Heap().Alloc(cb);
  358. else
  359. lpvNew = CHeapImpl::Heap().Realloc(lpv, cb);
  360. #ifndef _NOTHROW_
  361. if ( !lpvNew )
  362. {
  363. DebugTrace ("CHeap::Alloc() - Error reallocating (%d)\n", GetLastError());
  364. throw CLastErrorException();
  365. }
  366. #endif // _NOTHROW_
  367. return lpvNew;
  368. }
  369. VOID
  370. CHeap::Free( LPVOID lpv )
  371. {
  372. if ( lpv )
  373. {
  374. CHeapImpl::Heap().Free( lpv );
  375. }
  376. }
  377. //
  378. // The one global heap "object". CHeap is really just a struct
  379. // containing only static member functions, so there should be
  380. // no space required for this declaration. The actual heap
  381. // implementation (CHeapImpl) provides everything. CHeap is
  382. // now just an interface.
  383. //
  384. CHeap g_heap;
  385. // ------------------------------------------------------------------------
  386. //
  387. // Global new operator
  388. // Global delete operator
  389. //
  390. // Remap all calls to new to use our memory manager.
  391. // (Don't forget to throw explicitly on error!)
  392. //
  393. void * __cdecl operator new(size_t cb)
  394. {
  395. #ifdef DBG
  396. AssertSz(cb, "Zero-size allocation detecetd!");
  397. // Force small allocations up to min size of four
  398. // so that I can reliably do the "vtable-nulling trick" in delete!
  399. //
  400. if (cb < 4) cb = 4;
  401. #endif // DBG
  402. PVOID pv = g_heap.Alloc(cb);
  403. #ifndef _NOTHROW_
  404. if (!pv)
  405. throw CDAVException();
  406. #endif // _NOTHROW_
  407. return pv;
  408. }
  409. void __cdecl operator delete(void * pv)
  410. {
  411. #ifdef DBG
  412. // Zero-out the first four bytes of this allocation.
  413. // (If there was a vtable there previously, we'll now trap
  414. // if we try to use it!)
  415. //
  416. if (pv)
  417. *((DWORD *)pv) = 0;
  418. #endif // DBG
  419. g_heap.Free(pv);
  420. }