kernel/eka/memmodel/epoc/flexible/mmu/mslaballoc.h
author Tom Cosgrove <tom.cosgrove@nokia.com>
Fri, 28 May 2010 16:26:05 +0100
branchRCL_3
changeset 29 743008598095
parent 0 a41df078684a
permissions -rw-r--r--
Fix for bug 2283 (RVCT 4.0 support is missing from PDK 3.0.h) Have multiple extension sections in the bld.inf, one for each version of the compiler. The RVCT version building the tools will build the runtime libraries for its version, but make sure we extract all the other versions from zip archives. Also add the archive for RVCT4.

// Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies).
// All rights reserved.
// This component and the accompanying materials are made available
// under the terms of the License "Eclipse Public License v1.0"
// which accompanies this distribution, and is available
// at the URL "http://www.eclipse.org/legal/epl-v10.html".
//
// Initial Contributors:
// Nokia Corporation - initial contribution.
//
// Contributors:
//
// Description:
//

/**
 @file
 @internalComponent
*/

#ifndef MSLABALLOC_H
#define MSLABALLOC_H

#include "mcleanup.h"

/**
Slab allocator.
*/
class RSlabAllocatorBase
	{
public:
	RSlabAllocatorBase(TBool aDelayedCleanup);
	~RSlabAllocatorBase();

	/**
	Construct a slab allocator.

	@param aMaxSlabs	Maximum number of slabs to use. (Number of bits in \a slabBits.)
	@param aObjectSize	Size of objects to allocate.
	*/
	TInt Construct(TUint aMaxSlabs, TUint aObjectSize);

	/**
	Construct a slab allocator using fixed virtual memory.

	@param aMaxSlabs	Maximum number of slabs to use. (Number of bits in \a slabBits.)
	@param aObjectSize	Size of objects to allocate.
	@param aBase		Virtual address for start of memory where slabs will be allocated.
						Zero indicates 'anywhere'.
	*/
	TInt Construct(TUint aMaxSlabs, TUint aObjectSize, TLinAddr aBase);

	/**
	Set the memory object to be used for the slab allocator.
	*/
	FORCE_INLINE void SetMemory(DMemoryObject* aMemory, TUint aReserveCount)
		{
		__NK_ASSERT_DEBUG(!iMemory);
		iMemory = aMemory;
		iReserveCount = aReserveCount;
		}

	/**
	Allocate an object.

	@return Allocated object, or the null pointer if there is insufficient memory to perform the allocation.

	@pre MmuLock held
	@post MmuLock held, but has always beet flashed
	*/
	TAny* Alloc();

	/**
	Free an object previously allocated with #Alloc.

	@param aObject The object.

	@pre MmuLock held
	@post MmuLock held, but has always beet flashed
	*/
	void Free(TAny* aObject);

protected:
	class TSlabHeader : public SDblQueLink
		{
	public:
		SDblQue iFreeList;		///< List of unallocated objects in list.
		TUint iAllocCount;		///< Number of objects allocated in this slab.
		TAny* iHighWaterMark;	///< End of initialise region in slab.
		};

private:
	TBool NewSlab();
	void InitSlab(TLinAddr aPage);
	void FreeSlab(TSlabHeader* aSlab);
	static void CleanupTrampoline(TAny* aSelf);
	void Cleanup();
#ifdef _DEBUG
	void CheckSlab(TSlabHeader* aSlab);
#endif

private:
	SDblQue iFreeList;			///< List of slabs which have unallocated objects in them.
	TUint iFreeCount;			///< Number of unallocated objects.
	TUint iReserveCount;		///< Number of unallocated objects to keep in reserve (to allow for recursion during allocation).
	TUint iObjectsPerSlab;		///< Number of objects in each slab.
	TUint iObjectSize;			///< Size, in bytes, of objects to be allocated.
	TSpinLock iSpinLock;		///< Spinlock which protects iFreeList, iFreeCount  and TSlabHeader contents.

	TMemoryCleanup iCleanup;	///< Used to queue Cleanup() if iDelayedCleanup is true.
	TBool iDelayedCleanup;		///< True, if Free() should not free empty slabs.

	TBool iAllocatingSlab;		///< True if a new slab page is being allocated.
	TBitMapAllocator* iSlabMap;	///< Bitmap of allocated slabs.
	DMemoryObject* iMemory;		///< The memory object used to store slabs.
	DMemoryMapping* iMapping;	///< The memory mapping used for slabs.
	TLinAddr iBase;				///< Address of first slab.
	};


/**
Template for a slab allocator which can allocate up to N objects of type T.
*/
template <class T, TUint N>
class RSlabAllocator : public RSlabAllocatorBase
	{
public:
	enum
		{
		EObjectSize = sizeof(T)>sizeof(SDblQueLink) ? sizeof(T) : sizeof(SDblQueLink),
		EObjectsPerSlab = (KPageSize-sizeof(TSlabHeader))/EObjectSize,
		EMaxSlabs = (N+EObjectsPerSlab-1)/EObjectsPerSlab
		};

	FORCE_INLINE RSlabAllocator()
		: RSlabAllocatorBase(EFalse)
		{
		__ASSERT_COMPILE(EObjectsPerSlab>0);
		}

	FORCE_INLINE TInt Construct()
		{
		return RSlabAllocatorBase::Construct(EMaxSlabs,EObjectSize);
		}

	/**
	Allocate an object.

	@return Allocated object, or the null pointer if there is insufficient memory to perform the allocation.
	*/
	FORCE_INLINE T* Alloc()
		{
		return (T*)RSlabAllocatorBase::Alloc();
		}

	/**
	Free an object previously allocated with #Alloc.

	@param aObject Object.
	*/
	FORCE_INLINE void Free(T* aObject)
		{
		RSlabAllocatorBase::Free(aObject);
		}
	};


/**
Template for a slab allocator for allocating objects of type T, using the
virtual address region [B..E)
*/
template <class T, TLinAddr B, TLinAddr E>
class RStaticSlabAllocator : public RSlabAllocatorBase
	{
public:
	enum
		{
		EObjectSize = sizeof(T)>sizeof(SDblQueLink) ? sizeof(T) : sizeof(SDblQueLink),
		EObjectsPerSlab = (KPageSize-sizeof(TSlabHeader))/EObjectSize,
		EMaxSlabs = (E-B)/KPageSize
		};

	FORCE_INLINE RStaticSlabAllocator()
		: RSlabAllocatorBase(ETrue)
		{
		__ASSERT_COMPILE(EObjectsPerSlab>0);
		}

	FORCE_INLINE TInt Construct()
		{
		return RSlabAllocatorBase::Construct(EMaxSlabs,EObjectSize,B);
		}

	/**
	Allocate an object.

	@return Allocated object, or the null pointer if there is insufficient memory to perform the allocation.
	*/
	FORCE_INLINE T* Alloc()
		{
		return (T*)RSlabAllocatorBase::Alloc();
		}

	/**
	Free an object previously allocated with #Alloc.

	@param aObject Object.
	*/
	FORCE_INLINE void Free(T* aObject)
		{
		RSlabAllocatorBase::Free(aObject);
		}
	};

#endif