#ifndef _SMPOOL_HPP_ #define _SMPOOL_HPP_ // Ruler // 1 2 3 4 5 6 7 8 //345678901234567890123456789012345678901234567890123456789012345678901234567890 /********************************************************************/ /* */ /* The standard layout. */ /* */ /* The standard layout for 'hpp' files for this code is as */ /* follows: */ /* */ /* 1. Include files. */ /* 2. Constants exported from the class. */ /* 3. Data structures exported from the class. */ /* 4. Forward references to other data structures. */ /* 5. Class specifications (including inline functions). */ /* 6. Additional large inline functions. */ /* */ /* Any portion that is not required is simply omitted. */ /* */ /********************************************************************/ #include "Global.hpp" #include "Block.hpp" #include "Exclusive.hpp" #include "Queue.hpp" #include "Spinlock.hpp" #include "Stack.hpp" #include "Vector.hpp" /********************************************************************/ /* */ /* Constants exported from the class. */ /* */ /* The server constants specify the size of the server queue */ /* per processor stacks. */ /* */ /********************************************************************/ CONST SBIT16 MinSMPoolSize = 128; CONST SBIT16 SMPoolStackSize = 32; /********************************************************************/ /* */ /* Pools and pool management. */ /* */ /* This class provides general purpose memory pool along with */ /* basic management. The pools are optimized for very high */ /* performance on SMP systems (although this calls does not */ /* perform the actual locking. Whenever possible multiple */ /* items should allocated and deallocated at the same time. */ /* */ /********************************************************************/ template class SMPOOL { // // Private structures. // typedef EXCLUSIVE< QUEUE > LOCKED_QUEUE; typedef struct { CHAR TypeSize[sizeof(TYPE)]; } TYPE_SIZE; // // Private data. // SBIT32 MaxSize; SBIT32 MinSize; BLOCK< VECTOR > Block; LOCKED_QUEUE FreeQueue; VECTOR< STACK > Stacks; public: // // Public functions. // SMPOOL( SBIT32 MinSize = MinSMPoolSize ); TYPE *PopPool( SBIT16 Cpu ); TYPE **MultiplePopPool ( SBIT16 Cpu, SBIT32 Requested, SBIT32 *Size ); VOID PushPool( SBIT16 Cpu, TYPE *Pool ); VOID MultiplePushPool ( SBIT16 Cpu, TYPE *Pool[], SBIT32 Size ); ~SMPOOL( VOID ); private: // // Private functions. // VOID ExpandSize( SBIT32 NewSize ); // // Disabled operations. // SMPOOL( CONST SMPOOL & Copy ); VOID operator=( CONST SMPOOL & Copy ); }; /********************************************************************/ /* */ /* Class constructor. */ /* */ /* Create a new pool and prepare it for use. This call is */ /* not thread safe and should only be made in a single thread */ /* environment. */ /* */ /********************************************************************/ template SMPOOL::SMPOOL( SBIT32 MinSize ) : // // Call the constructors for the contained classes. // FreeQueue( MinSize ), Stacks( NumberOfCpus(), CacheLineSize ) { #ifdef DEBUGGING if ( MinSize > 0 ) { #endif // // We need to keep a note of the amount of elements // we have allocated so far. // this -> MaxSize = 0; this -> MinSize = MinSize; #ifdef DEBUGGING } else { Failure( "MinSize in constructor for SMPOOL" ); } #endif } /********************************************************************/ /* */ /* Expand size. */ /* */ /* Expand the current memory allocation if the free queue is */ /* empty. */ /* */ /********************************************************************/ template VOID SMPOOL::ExpandSize( SBIT32 NewSize ) { REGISTER SBIT32 Count1; REGISTER SBIT32 Count2; STATIC SPINLOCK Spinlock; Spinlock.ClaimLock(); if ( FreeQueue.SizeOfQueue() <= 0 ) { REGISTER SBIT32 ActualSize = (NewSize <= MinSize) ? MinSize : NewSize; REGISTER VECTOR *NewBlock = ( (VECTOR*) new VECTOR ( ActualSize, CacheLineSize ) ); // // We need to keep a note of the number of elements // we have allocated thus far. // MaxSize += ActualSize; // // We put the address of each element we allocate on // a stack to enable high speed allocation and // deallocation. // for ( Count1 = 0; Count1 < ActualSize; Count1 += SMPoolStackSize ) { AUTO POINTER NewCalls[ SMPoolStackSize ]; // // We add elements to the stack in blocks // to reduce the number of call to the // stack code. // for ( Count2 = 0; ((Count1 + Count2) < ActualSize) && (Count2 < SMPoolStackSize); Count2 ++ ) { REGISTER TYPE *NewCall = ( & (*NewBlock)[ (Count1 + Count2) ] ); NewCalls[ Count2 ] = (POINTER) NewCall; } // // Add the next block for free work packets to // the global free queue. // Stack.MultiplePushStack ( NewCalls, Count2 ); } // // Add the newly allocated block to the list of // things to be deleted when this class is deleted. // Block.DeferedDelete( (VECTOR*) NewBlock ); } Spinlock.ReleaseLock(); } /********************************************************************/ /* */ /* Remove a single item from the pool. */ /* */ /* We remove a single item from the pool. This call assumes */ /* all calls with the same 'Cpu' value are executed serially */ /* and that only one such call can be executing at any given */ /* time. */ /* */ /********************************************************************/ template TYPE *SMPOOL::PopPool( SBIT16 Cpu ) { REGISTER STACK *Stack = & Stacks[ Cpu ]; STATIC TYPE *NewPool; while ( ! Stack -> PopStack( (POINTER*) & NewPool ) ) { AUTO POINTER Store[ SMPoolStackSize ]; AUTO SBIT32 Size; FreeQueue.RemoveMultipleFromQueue ( SMPoolStackSize, Store, & Size ); if ( Size > 0 ) { Stack -> MultiplePushStack( Store, Size ); } else { ExpandSize( MaxSize ); } } (VOID) PLACEMENT_NEW( NewPool, TYPE ); return NewPool; } /********************************************************************/ /* */ /* Remove multiple items from the pool. */ /* */ /* We remove multiple items from the pool. This call assumes */ /* all calls with the same 'Cpu' value are executed serially */ /* and that only one such call can be executing at any given */ /* time. */ /* */ /********************************************************************/ template TYPE **SMPOOL::MultiplePopPool ( SBIT16 Cpu, SBIT32 Requested, SBIT32 *Size ) { REGISTER SBIT32 Count; REGISTER STACK *Stack = & Stacks[ Cpu ]; STATIC TYPE *NewPool[ SMPoolStackSize ]; Requested = (Requested <= SMPoolStackSize) ? Requested : SMPoolStackSize; while ( ! Stack -> MultiplePopStack( Requested,(POINTER*) NewPool,Size ) ) { AUTO POINTER Store[ SMPoolStackSize ]; AUTO SBIT32 Size; FreeQueue.RemoveMultipleFromQueue ( SMPoolStackSize, Store, & Size ); if ( Size > 0 ) { Stack -> MultiplePushStack( Store, Size ); } else { ExpandSize( MaxSize ); } } for ( Count=0;Count < (*Size); Count ++ ) { (VOID) PLACEMENT_NEW( NewPool[ Count ], TYPE ); } return NewPool; } /********************************************************************/ /* */ /* Add a single item to the pool. */ /* */ /* We add a single item to the pool. This call assumes */ /* all calls with the same 'Cpu' value are executed serially */ /* and that only one such call can be executing at any given */ /* time. */ /* */ /********************************************************************/ template VOID SMPOOL::PushPool ( SBIT16 Cpu, TYPE *Pool ) { REGISTER STACK *Stack = & Stacks[ Cpu ]; PLACEMENT_DELETE( Pool, TYPE ); Stack -> PushStack( (POINTER) Pool ); while ( Stack -> SizeOfStack() > (SMPoolStackSize * 2) ) { AUTO POINTER Store[ SMPoolStackSize ]; AUTO SBIT32 Size; Stack -> MultiplePopStack ( SMPoolStackSize, Store, & Size ); FreeQueue.AddMultipleToQueue( Store, Size ); } } /********************************************************************/ /* */ /* Add multiple items to the pool. */ /* */ /* We add a multiple items to the pool. This call assumes */ /* all calls with the same 'Cpu' value are executed serially */ /* and that only one such call can be executing at any given */ /* time. */ /* */ /********************************************************************/ template VOID SMPOOL::MultiplePushPool ( SBIT16 Cpu, TYPE *Pool[], SBIT32 Size ) { REGISTER SBIT32 Count; REGISTER STACK *Stack = & Stacks[ Cpu ]; for ( Count=(Size - 1);Count >= 0; Count -- ) { PLACEMENT_DELETE( Pool[ Count ], TYPE ); } Stack -> MultiplePushStack( (POINTER*) Pool,Size ); while ( Stack -> SizeOfStack() > (SMPoolStackSize * 2) ) { AUTO POINTER Store[ SMPoolStackSize ]; AUTO SBIT32 Size; Stack -> MultiplePopStack ( SMPoolStackSize, Store, & Size ); FreeQueue.AddMultipleToQueue( Store, Size ); } } /********************************************************************/ /* */ /* Class destructor. */ /* */ /* Destory the stack. This call is not thread safe and should */ /* only be made in a single thread environment. */ /* */ /********************************************************************/ template SMPOOL::~SMPOOL( VOID ) { /* void */ } #endif