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.

422 lines
15 KiB

  1. #ifndef _SMPOOL_HPP_
  2. #define _SMPOOL_HPP_
  3. // Ruler
  4. // 1 2 3 4 5 6 7 8
  5. //345678901234567890123456789012345678901234567890123456789012345678901234567890
  6. /********************************************************************/
  7. /* */
  8. /* The standard layout. */
  9. /* */
  10. /* The standard layout for 'hpp' files for this code is as */
  11. /* follows: */
  12. /* */
  13. /* 1. Include files. */
  14. /* 2. Constants exported from the class. */
  15. /* 3. Data structures exported from the class. */
  16. /* 4. Forward references to other data structures. */
  17. /* 5. Class specifications (including inline functions). */
  18. /* 6. Additional large inline functions. */
  19. /* */
  20. /* Any portion that is not required is simply omitted. */
  21. /* */
  22. /********************************************************************/
  23. #include "Global.hpp"
  24. #include "Block.hpp"
  25. #include "Exclusive.hpp"
  26. #include "Queue.hpp"
  27. #include "Spinlock.hpp"
  28. #include "Stack.hpp"
  29. #include "Vector.hpp"
  30. /********************************************************************/
  31. /* */
  32. /* Constants exported from the class. */
  33. /* */
  34. /* The server constants specify the size of the server queue */
  35. /* per processor stacks. */
  36. /* */
  37. /********************************************************************/
  38. CONST SBIT16 MinSMPoolSize = 128;
  39. CONST SBIT16 SMPoolStackSize = 32;
  40. /********************************************************************/
  41. /* */
  42. /* Pools and pool management. */
  43. /* */
  44. /* This class provides general purpose memory pool along with */
  45. /* basic management. The pools are optimized for very high */
  46. /* performance on SMP systems (although this calls does not */
  47. /* perform the actual locking. Whenever possible multiple */
  48. /* items should allocated and deallocated at the same time. */
  49. /* */
  50. /********************************************************************/
  51. template <class TYPE> class SMPOOL
  52. {
  53. //
  54. // Private structures.
  55. //
  56. typedef EXCLUSIVE< QUEUE<POINTER> > LOCKED_QUEUE;
  57. typedef struct { CHAR TypeSize[sizeof(TYPE)]; } TYPE_SIZE;
  58. //
  59. // Private data.
  60. //
  61. SBIT32 MaxSize;
  62. SBIT32 MinSize;
  63. BLOCK< VECTOR<TYPE_SIZE> > Block;
  64. LOCKED_QUEUE FreeQueue;
  65. VECTOR< STACK<POINTER> > Stacks;
  66. public:
  67. //
  68. // Public functions.
  69. //
  70. SMPOOL( SBIT32 MinSize = MinSMPoolSize );
  71. TYPE *PopPool( SBIT16 Cpu );
  72. TYPE **MultiplePopPool
  73. (
  74. SBIT16 Cpu,
  75. SBIT32 Requested,
  76. SBIT32 *Size
  77. );
  78. VOID PushPool( SBIT16 Cpu, TYPE *Pool );
  79. VOID MultiplePushPool
  80. (
  81. SBIT16 Cpu,
  82. TYPE *Pool[],
  83. SBIT32 Size
  84. );
  85. ~SMPOOL( VOID );
  86. private:
  87. //
  88. // Private functions.
  89. //
  90. VOID ExpandSize( SBIT32 NewSize );
  91. //
  92. // Disabled operations.
  93. //
  94. SMPOOL( CONST SMPOOL & Copy );
  95. VOID operator=( CONST SMPOOL & Copy );
  96. };
  97. /********************************************************************/
  98. /* */
  99. /* Class constructor. */
  100. /* */
  101. /* Create a new pool and prepare it for use. This call is */
  102. /* not thread safe and should only be made in a single thread */
  103. /* environment. */
  104. /* */
  105. /********************************************************************/
  106. template <class TYPE> SMPOOL<TYPE>::SMPOOL( SBIT32 MinSize ) :
  107. //
  108. // Call the constructors for the contained classes.
  109. //
  110. FreeQueue( MinSize ),
  111. Stacks( NumberOfCpus(), CacheLineSize )
  112. {
  113. #ifdef DEBUGGING
  114. if ( MinSize > 0 )
  115. {
  116. #endif
  117. //
  118. // We need to keep a note of the amount of elements
  119. // we have allocated so far.
  120. //
  121. this -> MaxSize = 0;
  122. this -> MinSize = MinSize;
  123. #ifdef DEBUGGING
  124. }
  125. else
  126. { Failure( "MinSize in constructor for SMPOOL" ); }
  127. #endif
  128. }
  129. /********************************************************************/
  130. /* */
  131. /* Expand size. */
  132. /* */
  133. /* Expand the current memory allocation if the free queue is */
  134. /* empty. */
  135. /* */
  136. /********************************************************************/
  137. template <class TYPE> VOID SMPOOL<TYPE>::ExpandSize( SBIT32 NewSize )
  138. {
  139. REGISTER SBIT32 Count1;
  140. REGISTER SBIT32 Count2;
  141. STATIC SPINLOCK Spinlock;
  142. Spinlock.ClaimLock();
  143. if ( FreeQueue.SizeOfQueue() <= 0 )
  144. {
  145. REGISTER SBIT32 ActualSize =
  146. (NewSize <= MinSize) ? MinSize : NewSize;
  147. REGISTER VECTOR<TYPE> *NewBlock =
  148. (
  149. (VECTOR<TYPE>*) new VECTOR<TYPE_SIZE>
  150. (
  151. ActualSize,
  152. CacheLineSize
  153. )
  154. );
  155. //
  156. // We need to keep a note of the number of elements
  157. // we have allocated thus far.
  158. //
  159. MaxSize += ActualSize;
  160. //
  161. // We put the address of each element we allocate on
  162. // a stack to enable high speed allocation and
  163. // deallocation.
  164. //
  165. for
  166. (
  167. Count1 = 0;
  168. Count1 < ActualSize;
  169. Count1 += SMPoolStackSize
  170. )
  171. {
  172. AUTO POINTER NewCalls[ SMPoolStackSize ];
  173. //
  174. // We add elements to the stack in blocks
  175. // to reduce the number of call to the
  176. // stack code.
  177. //
  178. for
  179. (
  180. Count2 = 0;
  181. ((Count1 + Count2) < ActualSize)
  182. &&
  183. (Count2 < SMPoolStackSize);
  184. Count2 ++
  185. )
  186. {
  187. REGISTER TYPE *NewCall =
  188. (
  189. & (*NewBlock)[ (Count1 + Count2) ]
  190. );
  191. NewCalls[ Count2 ] = (POINTER) NewCall;
  192. }
  193. //
  194. // Add the next block for free work packets to
  195. // the global free queue.
  196. //
  197. Stack.MultiplePushStack
  198. (
  199. NewCalls,
  200. Count2
  201. );
  202. }
  203. //
  204. // Add the newly allocated block to the list of
  205. // things to be deleted when this class is deleted.
  206. //
  207. Block.DeferedDelete( (VECTOR<TYPE_SIZE>*) NewBlock );
  208. }
  209. Spinlock.ReleaseLock();
  210. }
  211. /********************************************************************/
  212. /* */
  213. /* Remove a single item from the pool. */
  214. /* */
  215. /* We remove a single item from the pool. This call assumes */
  216. /* all calls with the same 'Cpu' value are executed serially */
  217. /* and that only one such call can be executing at any given */
  218. /* time. */
  219. /* */
  220. /********************************************************************/
  221. template <class TYPE> TYPE *SMPOOL<TYPE>::PopPool( SBIT16 Cpu )
  222. {
  223. REGISTER STACK<POINTER> *Stack = & Stacks[ Cpu ];
  224. STATIC TYPE *NewPool;
  225. while ( ! Stack -> PopStack( (POINTER*) & NewPool ) )
  226. {
  227. AUTO POINTER Store[ SMPoolStackSize ];
  228. AUTO SBIT32 Size;
  229. FreeQueue.RemoveMultipleFromQueue
  230. (
  231. SMPoolStackSize,
  232. Store,
  233. & Size
  234. );
  235. if ( Size > 0 )
  236. { Stack -> MultiplePushStack( Store, Size ); }
  237. else
  238. { ExpandSize( MaxSize ); }
  239. }
  240. (VOID) PLACEMENT_NEW( NewPool, TYPE );
  241. return NewPool;
  242. }
  243. /********************************************************************/
  244. /* */
  245. /* Remove multiple items from the pool. */
  246. /* */
  247. /* We remove multiple items from the pool. This call assumes */
  248. /* all calls with the same 'Cpu' value are executed serially */
  249. /* and that only one such call can be executing at any given */
  250. /* time. */
  251. /* */
  252. /********************************************************************/
  253. template <class TYPE> TYPE **SMPOOL<TYPE>::MultiplePopPool
  254. (
  255. SBIT16 Cpu,
  256. SBIT32 Requested,
  257. SBIT32 *Size
  258. )
  259. {
  260. REGISTER SBIT32 Count;
  261. REGISTER STACK<POINTER> *Stack = & Stacks[ Cpu ];
  262. STATIC TYPE *NewPool[ SMPoolStackSize ];
  263. Requested = (Requested <= SMPoolStackSize) ? Requested : SMPoolStackSize;
  264. while ( ! Stack -> MultiplePopStack( Requested,(POINTER*) NewPool,Size ) )
  265. {
  266. AUTO POINTER Store[ SMPoolStackSize ];
  267. AUTO SBIT32 Size;
  268. FreeQueue.RemoveMultipleFromQueue
  269. (
  270. SMPoolStackSize,
  271. Store,
  272. & Size
  273. );
  274. if ( Size > 0 )
  275. { Stack -> MultiplePushStack( Store, Size ); }
  276. else
  277. { ExpandSize( MaxSize ); }
  278. }
  279. for ( Count=0;Count < (*Size); Count ++ )
  280. { (VOID) PLACEMENT_NEW( NewPool[ Count ], TYPE ); }
  281. return NewPool;
  282. }
  283. /********************************************************************/
  284. /* */
  285. /* Add a single item to the pool. */
  286. /* */
  287. /* We add a single item to the pool. This call assumes */
  288. /* all calls with the same 'Cpu' value are executed serially */
  289. /* and that only one such call can be executing at any given */
  290. /* time. */
  291. /* */
  292. /********************************************************************/
  293. template <class TYPE> VOID SMPOOL<TYPE>::PushPool
  294. (
  295. SBIT16 Cpu,
  296. TYPE *Pool
  297. )
  298. {
  299. REGISTER STACK<POINTER> *Stack = & Stacks[ Cpu ];
  300. PLACEMENT_DELETE( Pool, TYPE );
  301. Stack -> PushStack( (POINTER) Pool );
  302. while ( Stack -> SizeOfStack() > (SMPoolStackSize * 2) )
  303. {
  304. AUTO POINTER Store[ SMPoolStackSize ];
  305. AUTO SBIT32 Size;
  306. Stack -> MultiplePopStack
  307. (
  308. SMPoolStackSize,
  309. Store,
  310. & Size
  311. );
  312. FreeQueue.AddMultipleToQueue( Store, Size );
  313. }
  314. }
  315. /********************************************************************/
  316. /* */
  317. /* Add multiple items to the pool. */
  318. /* */
  319. /* We add a multiple items to the pool. This call assumes */
  320. /* all calls with the same 'Cpu' value are executed serially */
  321. /* and that only one such call can be executing at any given */
  322. /* time. */
  323. /* */
  324. /********************************************************************/
  325. template <class TYPE> VOID SMPOOL<TYPE>::MultiplePushPool
  326. (
  327. SBIT16 Cpu,
  328. TYPE *Pool[],
  329. SBIT32 Size
  330. )
  331. {
  332. REGISTER SBIT32 Count;
  333. REGISTER STACK<POINTER> *Stack = & Stacks[ Cpu ];
  334. for ( Count=(Size - 1);Count >= 0; Count -- )
  335. { PLACEMENT_DELETE( Pool[ Count ], TYPE ); }
  336. Stack -> MultiplePushStack( (POINTER*) Pool,Size );
  337. while ( Stack -> SizeOfStack() > (SMPoolStackSize * 2) )
  338. {
  339. AUTO POINTER Store[ SMPoolStackSize ];
  340. AUTO SBIT32 Size;
  341. Stack -> MultiplePopStack
  342. (
  343. SMPoolStackSize,
  344. Store,
  345. & Size
  346. );
  347. FreeQueue.AddMultipleToQueue( Store, Size );
  348. }
  349. }
  350. /********************************************************************/
  351. /* */
  352. /* Class destructor. */
  353. /* */
  354. /* Destory the stack. This call is not thread safe and should */
  355. /* only be made in a single thread environment. */
  356. /* */
  357. /********************************************************************/
  358. template <class TYPE> SMPOOL<TYPE>::~SMPOOL( VOID )
  359. { /* void */ }
  360. #endif