fixed_mem_pool.h 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330
  1. // -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
  2. // vim:tabstop=4:shiftwidth=4:expandtab:
  3. /*
  4. * Copyright (C) 2004-2008 Wu Yongwei <adah at users dot sourceforge dot net>
  5. *
  6. * This software is provided 'as-is', without any express or implied
  7. * warranty. In no event will the authors be held liable for any
  8. * damages arising from the use of this software.
  9. *
  10. * Permission is granted to anyone to use this software for any purpose,
  11. * including commercial applications, and to alter it and redistribute
  12. * it freely, subject to the following restrictions:
  13. *
  14. * 1. The origin of this software must not be misrepresented; you must
  15. * not claim that you wrote the original software. If you use this
  16. * software in a product, an acknowledgement in the product
  17. * documentation would be appreciated but is not required.
  18. * 2. Altered source versions must be plainly marked as such, and must
  19. * not be misrepresented as being the original software.
  20. * 3. This notice may not be removed or altered from any source
  21. * distribution.
  22. *
  23. * This file is part of Stones of Nvwa:
  24. * http://sourceforge.net/projects/nvwa
  25. *
  26. */
  27. /*!
  28. * \file fixed_mem_pool.h
  29. * \ingroup QxMemLeak
  30. *
  31. * Definition of a fixed-size memory pool template for structs/classes.
  32. * This is a easy-to-use class template for pre-allocated memory pools.
  33. * The client side needs to do the following things:
  34. * - Use one of the macros #DECLARE_FIXED_MEM_POOL,
  35. * #DECLARE_FIXED_MEM_POOL__NOTHROW, and
  36. * #DECLARE_FIXED_MEM_POOL__THROW_NOCHECK at the end of the class
  37. * (say, \c class \e _Cls) definitions
  38. * - Call fixed_mem_pool<_Cls>::initialize at the beginning of the
  39. * program
  40. * - Optionally, specialize fixed_mem_pool<_Cls>::bad_alloc_handler to
  41. * change the behaviour when all memory blocks are allocated
  42. * - Optionally, call fixed_mem_pool<_Cls>::deinitialize at exit of the
  43. * program to check for memory leaks
  44. * - Optionally, call fixed_mem_pool<_Cls>::get_alloc_count to check
  45. * memory usage when the program is running
  46. *
  47. * \version 1.14, 2005/09/19
  48. * \author Wu Yongwei
  49. *
  50. */
  51. #ifndef QT_NO_DEBUG
  52. #ifndef _QX_MODE_RELEASE
  53. #if _QX_USE_MEM_LEAK_DETECTION
  54. #ifndef _FIXED_MEM_POOL_H
  55. #define _FIXED_MEM_POOL_H
  56. #ifdef _MSC_VER
  57. #pragma once
  58. #endif
  59. #include <new>
  60. #include <assert.h>
  61. #include <stdlib.h>
  62. #include "class_level_lock.h"
  63. #include "mem_pool_base.h"
  64. /**
  65. * Defines the alignment of memory blocks.
  66. */
  67. #ifndef MEM_POOL_ALIGNMENT
  68. #define MEM_POOL_ALIGNMENT 4
  69. #endif
  70. namespace qx {
  71. namespace memory {
  72. /**
  73. * Class template to manipulate a fixed-size memory pool. Please notice
  74. * that only allocate and deallocate are protected by a lock.
  75. *
  76. * @param _Tp class to use the fixed_mem_pool
  77. */
  78. template <class _Tp>
  79. class fixed_mem_pool
  80. {
  81. public:
  82. typedef typename class_level_lock<fixed_mem_pool<_Tp> >::lock lock;
  83. static void* allocate();
  84. static void deallocate(void*);
  85. static bool initialize(size_t __size);
  86. static int deinitialize();
  87. static int get_alloc_count();
  88. static bool is_initialized();
  89. protected:
  90. static bool bad_alloc_handler();
  91. private:
  92. static size_t _S_align(size_t __size);
  93. static void* _S_mem_pool_ptr;
  94. static void* _S_first_avail_ptr;
  95. static int _S_alloc_cnt;
  96. };
  97. /** Pointer to the allocated chunk of memory. */
  98. template <class _Tp>
  99. void* fixed_mem_pool<_Tp>::_S_mem_pool_ptr = NULL;
  100. /** Pointer to the first available memory block. */
  101. template <class _Tp>
  102. void* fixed_mem_pool<_Tp>::_S_first_avail_ptr = NULL;
  103. /** Count of allocations. */
  104. template <class _Tp>
  105. int fixed_mem_pool<_Tp>::_S_alloc_cnt = 0;
  106. /**
  107. * Allocates a memory block from the memory pool.
  108. *
  109. * @return pointer to the allocated memory block
  110. */
  111. template <class _Tp>
  112. inline void* fixed_mem_pool<_Tp>::allocate()
  113. {
  114. lock __guard;
  115. for (;;)
  116. {
  117. if (void* __result = _S_first_avail_ptr)
  118. {
  119. _S_first_avail_ptr = *(void**)_S_first_avail_ptr;
  120. ++_S_alloc_cnt;
  121. return __result;
  122. }
  123. else
  124. if (!bad_alloc_handler())
  125. return NULL;
  126. }
  127. }
  128. /**
  129. * Deallocates a memory block and returns it to the memory pool.
  130. *
  131. * @param __block_ptr pointer to the memory block to return
  132. */
  133. template <class _Tp>
  134. inline void fixed_mem_pool<_Tp>::deallocate(void* __block_ptr)
  135. {
  136. if (__block_ptr == NULL)
  137. return;
  138. lock __guard;
  139. assert(_S_alloc_cnt != 0);
  140. --_S_alloc_cnt;
  141. *(void**)__block_ptr = _S_first_avail_ptr;
  142. _S_first_avail_ptr = __block_ptr;
  143. }
  144. /**
  145. * Initializes the memory pool.
  146. *
  147. * @param __size number of memory blocks to put in the memory pool
  148. * @return \c true if successful; \c false if memory insufficient
  149. */
  150. template <class _Tp>
  151. bool fixed_mem_pool<_Tp>::initialize(size_t __size)
  152. {
  153. size_t __block_size = _S_align(sizeof(_Tp));
  154. assert(!is_initialized());
  155. assert(__size > 0 && __block_size >= sizeof(void*));
  156. _S_mem_pool_ptr = mem_pool_base::alloc_sys(__size * __block_size);
  157. _S_first_avail_ptr = _S_mem_pool_ptr;
  158. if (_S_mem_pool_ptr == NULL)
  159. return false;
  160. char* __block_ = (char*)_S_mem_pool_ptr;
  161. while (--__size != 0)
  162. {
  163. char* __next_ = __block_ + __block_size;
  164. *(void**)__block_ = __next_;
  165. __block_ = __next_;
  166. }
  167. *(void**)__block_ = NULL;
  168. return true;
  169. }
  170. /**
  171. * Deinitializes the memory pool.
  172. *
  173. * @return \c 0 if all memory blocks are returned and the memory pool
  174. * successfully freed; or a non-zero value indicating number of
  175. * memory blocks still in allocation
  176. */
  177. template <class _Tp>
  178. int fixed_mem_pool<_Tp>::deinitialize()
  179. {
  180. if (_S_alloc_cnt != 0)
  181. return _S_alloc_cnt;
  182. assert(is_initialized());
  183. mem_pool_base::dealloc_sys(_S_mem_pool_ptr);
  184. _S_mem_pool_ptr = NULL;
  185. _S_first_avail_ptr = NULL;
  186. return 0;
  187. }
  188. /**
  189. * Gets the allocation count.
  190. *
  191. * @return the number of memory blocks still in allocation
  192. */
  193. template <class _Tp>
  194. inline int fixed_mem_pool<_Tp>::get_alloc_count()
  195. {
  196. return _S_alloc_cnt;
  197. }
  198. /**
  199. * Is the memory pool initialized?
  200. *
  201. * @return \c true if it is successfully initialized; \c false otherwise
  202. */
  203. template <class _Tp>
  204. inline bool fixed_mem_pool<_Tp>::is_initialized()
  205. {
  206. return _S_mem_pool_ptr != NULL;;
  207. }
  208. /**
  209. * Bad allocation handler. Called when there are no memory blocks
  210. * available in the memory pool. If this function returns \c false
  211. * (default behaviour if not explicitly specialized), it indicates that
  212. * it can do nothing and allocate() should return \c NULL; if this
  213. * function returns \c true, it indicates that it has freed some memory
  214. * blocks and allocate() should try allocating again.
  215. */
  216. template <class _Tp>
  217. bool fixed_mem_pool<_Tp>::bad_alloc_handler()
  218. {
  219. return false;
  220. }
  221. /**
  222. * Aligns the memory block size.
  223. *
  224. * @param __size size to be aligned
  225. * @return aligned value of \a __size
  226. */
  227. template <class _Tp>
  228. inline size_t fixed_mem_pool<_Tp>::_S_align(size_t __size)
  229. {
  230. return (__size + MEM_POOL_ALIGNMENT - 1)
  231. / MEM_POOL_ALIGNMENT * MEM_POOL_ALIGNMENT;
  232. }
  233. } // namespace memory
  234. } // namespace qx
  235. /**
  236. * Declares the normal (exceptionable) overload of <b>operator new</b>
  237. * and <b>operator delete</b>.
  238. *
  239. * @param _Cls class to use the fixed_mem_pool
  240. * @see DECLARE_FIXED_MEM_POOL__THROW_NOCHECK, which, too,
  241. * defines an <b>operator new</b> that will never return
  242. * \c NULL, but requires more discipline on the
  243. * programmer's side.
  244. */
  245. #define DECLARE_FIXED_MEM_POOL(_Cls) \
  246. public: \
  247. static void* operator new(size_t __size) \
  248. { \
  249. assert(__size == sizeof(_Cls)); \
  250. if (void* __ptr = fixed_mem_pool<_Cls>::allocate()) \
  251. return __ptr; \
  252. else \
  253. throw std::bad_alloc(); \
  254. } \
  255. static void operator delete(void* __ptr) \
  256. { \
  257. if (__ptr != NULL) \
  258. fixed_mem_pool<_Cls>::deallocate(__ptr); \
  259. }
  260. /**
  261. * Declares the non-exceptionable overload of <b>operator new</b> and
  262. * <b>operator delete</b>.
  263. *
  264. * @param _Cls class to use the fixed_mem_pool
  265. */
  266. #define DECLARE_FIXED_MEM_POOL__NOTHROW(_Cls) \
  267. public: \
  268. static void* operator new(size_t __size) throw() \
  269. { \
  270. assert(__size == sizeof(_Cls)); \
  271. return fixed_mem_pool<_Cls>::allocate(); \
  272. } \
  273. static void operator delete(void* __ptr) \
  274. { \
  275. if (__ptr != NULL) \
  276. fixed_mem_pool<_Cls>::deallocate(__ptr); \
  277. }
  278. /**
  279. * Declares the exceptionable, non-checking overload of <b>operator
  280. * new</b> and <b>operator delete</b>.
  281. *
  282. * N.B. Using this macro \e requires users to explicitly specialize
  283. * fixed_mem_pool::bad_alloc_handler so that it shall never return
  284. * \c false (it may throw exceptions, say, \c std::bad_alloc, or simply
  285. * abort). Otherwise a segmentation fault might occur (instead of
  286. * returning a \c NULL pointer).
  287. *
  288. * @param _Cls class to use the fixed_mem_pool
  289. */
  290. #define DECLARE_FIXED_MEM_POOL__THROW_NOCHECK(_Cls) \
  291. public: \
  292. static void* operator new(size_t __size) \
  293. { \
  294. assert(__size == sizeof(_Cls)); \
  295. return fixed_mem_pool<_Cls>::allocate(); \
  296. } \
  297. static void operator delete(void* __ptr) \
  298. { \
  299. if (__ptr != NULL) \
  300. fixed_mem_pool<_Cls>::deallocate(__ptr); \
  301. }
  302. #endif // _FIXED_MEM_POOL_H
  303. #endif // _QX_USE_MEM_LEAK_DETECTION
  304. #endif // _QX_MODE_RELEASE
  305. #endif // QT_NO_DEBUG