//                                        Ruler
//       1         2         3         4         5         6         7         8
//345678901234567890123456789012345678901234567890123456789012345678901234567890

    /********************************************************************/
    /*                                                                  */
    /*   The standard layout.                                           */
    /*                                                                  */
    /*   The standard layout for 'cpp' files in this code is as         */
    /*   follows:                                                       */
    /*                                                                  */
    /*      1. Include files.                                           */
    /*      2. Constants local to the class.                            */
    /*      3. Data structures local to the class.                      */
    /*      4. Data initializations.                                    */
    /*      5. Static functions.                                        */
    /*      6. Class functions.                                         */
    /*                                                                  */
    /*   The constructor is typically the first function, class         */
    /*   member functions appear in alphabetical order with the         */
    /*   destructor appearing at the end of the file.  Any section      */
    /*   or function this is not required is simply omitted.            */
    /*                                                                  */
    /********************************************************************/

#include "InterfacePCH.hpp"

#include "Common.hpp"
#include "RockallBackEnd.hpp"
#include "RockallFrontEnd.hpp"

    /********************************************************************/
    /*                                                                  */
    /*   Static member initialization.                                  */
    /*                                                                  */
    /*   Static member initialization sets the initial value for all    */
    /*   static members.                                                */
    /*                                                                  */
    /********************************************************************/

#pragma init_seg(compiler)
ROCKALL_BACK_END ROCKALL_BACK_END::DefaultBaseClass;

    /********************************************************************/
    /*                                                                  */
    /*   Class constructor.                                             */
    /*                                                                  */
    /*   The may be a situation where the Rockall Back End needs a      */
    /*   constructor but this is certainly not expected to be           */
    /*   very common.                                                   */
    /*                                                                  */
    /********************************************************************/

ROCKALL_BACK_END::ROCKALL_BACK_END( void )
	{ /* void */ }

    /********************************************************************/
    /*                                                                  */
    /*   Delete allocation area.                                        */
    /*                                                                  */
    /*   All memory requests are eventually sent back to the external   */
    /*   deallocator.  This function can be overloaded so that memory   */
    /*   can be provided from any source.  The default is to send       */
    /*   it back to the operating system.                               */
    /*                                                                  */
    /********************************************************************/

void ROCKALL_BACK_END::DeleteArea( void *Memory,int Size,bool User )
	{
	REGISTER DWORD NewSize = ((Size == 0) ? Size : 0);

#ifdef DEBUGGING
#ifdef ENABLE_ALLOCATION_STATISTICS
	//
	//  When we are debugging print out trace information.
	//  
	DebugPrint( "Delete\t 0x%08x %d bytes\n",Memory,Size );

#endif
#endif
	//
	//   The NT 'VirtualFree' call requires the 'Size'
	//   to be zero.  This may not be true of all 
	//   deallocators so we pass the value and then
	//   replace it with zero above.
	//
	if ( VirtualFree( Memory,NewSize,MEM_RELEASE ) == NULL )
		{ Failure( "Delete fails in DeleteArea" ); }
	}

    /********************************************************************/
    /*                                                                  */
    /*   The natural allocation size.                                   */
    /*                                                                  */
    /*   We would like to know a good default size for allocations.     */
    /*   We really don't have a clue so we ask the operating system     */
    /*   for the size of an allocation granual.                         */
    /*                                                                  */
    /********************************************************************/

int ROCKALL_BACK_END::NaturalSize( void )
    {
		return ENVIRONMENT::AllocationSize();
	}

    /********************************************************************/
    /*                                                                  */
    /*   New allocation area.                                           */
    /*                                                                  */
    /*   All memory requests are eventually sent to the new external    */
    /*   allocator.  This function can be overloaded so that memory     */
    /*   can be provided from any source.  The default is to get        */
    /*   new memory from the operating system.                          */
    /*                                                                  */
    /********************************************************************/

void *ROCKALL_BACK_END::NewArea( int AlignMask,int Size,bool User )
    {
	//
	//   When there is an alignment requirement greater
	//   than the natural alignment provided by the
	//   operating system we have to play various tricks
	//   to allocate a suitable block.  If not then we
	//   just do a normal allocation call.
	//
	if ( AlignMask > NaturalSize() )
		{
		assert((AlignMask + Size)>0 && (AlignMask + Size)>=Size); //PREfast wants to ensure things are right
		REGISTER SBIT32 NewSize = (AlignMask + Size);

		//
		//   We need to allocate a block with an 
		//   alignment requirement greater than 
		//   the operating system default.  So we
		//   allocate a much larger block and
		//   release the parts we don't need.
		//
		while ( True )
			{
			REGISTER VOID *Reserved =
				(
				VirtualAlloc
					( 
					NULL,
					((DWORD) NewSize),
					MEM_RESERVE
#ifdef USE_LARGE_PAGES
					|MEM_LARGE_PAGES
#endif
					,PAGE_READWRITE 
					)
				);

			//
			//   Lets ensure we were able to find a suitable
			//   memory block.  If not then we exit.
			//
			if ( Reserved != NULL )
				{
				//
				//   We just want to return the parts of
				//   the block we don't need but 'NT' is  
				//   not smart enough.  So we free the  
				//   entire block.
				//
				if ( VirtualFree( Reserved,0,MEM_RELEASE ) )
					{
					REGISTER SNATIVE Address = ((SNATIVE) Reserved);
					REGISTER VOID *NewMemory;

					//
					//   Compute the base address of the part 
					//   of the block we really want to allocate.
					//
					Address = ((Address + AlignMask) & ~AlignMask);

					//
					//   Finally, lets reallocate the part of  
					//   the block we wanted but just released   
					//   and hope that nobody else got it before
					//   us.
					//
					NewMemory =
						(
						VirtualAlloc
							( 
							((LPVOID) Address),
							((DWORD) Size),
							MEM_RESERVE | MEM_COMMIT
#ifdef USE_LARGE_PAGES
							|MEM_LARGE_PAGES
#endif
							,PAGE_READWRITE 
							)
						);

					//
					//   If it all worked we can exit.
					//
					if ( NewMemory != NULL )
						{ 
#ifdef DEBUGGING
#ifdef ENABLE_ALLOCATION_STATISTICS
						//
						//  When we are debugging output 
						//  out trace information.
						//  
						DebugPrint
							( 
							"New\t\t at 0x%08x of %d bytes (by %s request)\n",
							NewMemory,
							Size,
							User?"user":"system"
							);

#endif
#endif
						return ((void*) NewMemory); 
						}
					}
				else
					{ return ((void*) AllocationFailure); }

				}
			else
				{ return ((void*) AllocationFailure); }
			}
		}
	else
		{
		REGISTER VOID *NewMemory;

		//
		//   We can allocate directly from the operating 
		//   system as the default alignment requirement 
		//   is enough for this case.
		//
		NewMemory =
			(
			VirtualAlloc
				( 
				NULL,
				((DWORD) Size),
				MEM_COMMIT
#ifdef USE_LARGE_PAGES
					|MEM_LARGE_PAGES
#endif
				,PAGE_READWRITE
				)
			);
#ifdef DEBUGGING
#ifdef ENABLE_ALLOCATION_STATISTICS

		if ( NewMemory != NULL )
			{
			//
			//  When we are debugging output out trace
			//  information.
			//  
			DebugPrint( "New memory allocated at\t 0x%08x of %d bytes (by %s request)\n",
						NewMemory, Size, User?"user":"system");
			}
#endif
#endif

		return ((void*) NewMemory);
		}
	}

    /********************************************************************/
    /*                                                                  */
    /*   Class destructor.                                              */
    /*                                                                  */
    /*   The may be a situation where the Rockall Back End needs a      */
    /*   destructor but this is certainly not expected to be            */
    /*   very common.                                                   */
    /*                                                                  */
    /********************************************************************/

ROCKALL_BACK_END::~ROCKALL_BACK_END( void )
	{ /* void */ }
