userlibandfileserver/fileserver/sfile/sf_memory_man.cpp
author Slion
Tue, 08 Dec 2009 08:11:42 +0100
branchanywhere
changeset 19 f6d3d9676ee4
parent 0 a41df078684a
child 31 56f325a607ea
permissions -rw-r--r--
Trying to figure out how to implement my WINC like compatibility layer. Going the emulation way is probably not so smart. We should not use the kernel but rather hook native functions in the Exec calls.

// Copyright (c) 2008-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:
// f32\sfile\sf_memory_man.cpp
// 
//

/**
 @file
 @internalTechnology
*/


#include <e32std.h>
#include <e32std_private.h>
#include "sf_std.h"
#include <e32uid.h>
#include <e32wins.h>
#include <f32file.h>
#include <hal.h>
#include "sf_memory_man.h"
#include "sf_memory_client.h"

/**
Destructor of the CCacheMemoryManager, need to destroy all registered clients.
*/
CCacheMemoryManager::~CCacheMemoryManager()
	{
	for (TInt i = 0; i < iRegisteredClients.Count(); i++)
		{
		iRegisteredClients[i]->Reset();
		delete iRegisteredClients[i];
		}
	iRegisteredClients.Close();
	}

/**
Static factory function of CCacheMemoryManager
@param	aCacheSize	the total size of the virtual address space
*/
CCacheMemoryManager* CCacheMemoryManager::NewL(TInt aCacheSize)
	{
	CCacheMemoryManager* cacheMemoryManager = new (ELeave) CCacheMemoryManager(aCacheSize);

	CleanupStack::PushL(cacheMemoryManager);
	cacheMemoryManager->ConstructL();
	CleanupStack::Pop(1, cacheMemoryManager);

	return cacheMemoryManager;
	}

/**
Constructor of CCacheMemoryManager
@param	aMaxSize	the total size of the virtual address space
*/
CCacheMemoryManager::CCacheMemoryManager(TUint32 aMaxSize)
:iBase(NULL),
iSizeInBytes(aMaxSize),
iCurrentOffsetMark(0)
	{
	}

/**
Second phase constructor of CCacheMemoryManager.
Creates RChunk object and sets low memory threshold.
*/
void CCacheMemoryManager::ConstructL()
	{
	// calculate the low-memory threshold below which we fail any attempt to allocate memory
	TMemoryInfoV1Buf meminfo;
	TInt r = UserHal::MemoryInfo(meminfo);
	ASSERT(r==KErrNone);
	User::LeaveIfError(r);
	iLowMemoryThreshold = (meminfo().iTotalRamInBytes * TGlobalCacheMemorySettings::LowMemoryThreshold()) / 100;
	TChunkCreateInfo createInfo;
	createInfo.SetCache(iSizeInBytes);
	createInfo.SetOwner(EOwnerProcess);
	r = iChunk.Create(createInfo);
	ASSERT(r==KErrNone);
	User::LeaveIfError(r);
	UserSvr::RegisterTrustedChunk(iChunk.Handle());
	iBase = iChunk.Base();
	iRegisteredClients.ReserveL(10);
	__PRINT3(_L("CCacheMemoryManager::ConstructL(lowMem=%d, iSize=%d, base=0x%lx)"), iLowMemoryThreshold, iSizeInBytes, iBase);
	}

/**
Connect or register a client.
Note: callers of this function should be constructor of various caches, it is their resposibility
	to make sure that parameters are sensible when calling this function

@internalTechnology
@released

@param	aClientName	an identifier of the client to be connected
@param	aMinSizeInSegs	minimum client size in segments
@param	aMaxSizeInSegs	maximum client size in segments
@return	CCacheMemoryClient*	pointer to the client that connected, or NULL if parameters are not valid.
@leave	if no memory
*/
EXPORT_C CCacheMemoryClient* CCacheMemoryManager::ConnectClientL(const TDesC& aClientName, TUint32 aMinSizeInSegs, TUint32 aMaxSizeInSegs)
	{
	__PRINT3(_L("CCacheMemoryManager::ConnectClientL: [%S], minSeg=%d, maxSeg=%d"), &aClientName, aMinSizeInSegs, aMaxSizeInSegs);
	for (TInt i = 0; i < iRegisteredClients.Count(); i++)
		{
		if (aClientName.Compare(iRegisteredClients[i]->Name()) == 0)
			{
			ASSERT(iRegisteredClients[i]->iTouchedRegionFlag == 0);
			__PRINT1(_L("CCacheMemoryManager::ConnectClientL: [%S] found!"), &aClientName);
			return iRegisteredClients[i];
			}
		}

	// parameter validation
	ASSERT(iSizeInBytes > iCurrentOffsetMark + (aMaxSizeInSegs << SegmentSizeInBytesLog2()));
	if (iSizeInBytes < iCurrentOffsetMark + (aMaxSizeInSegs << SegmentSizeInBytesLog2()))
		{
		ASSERT(0);
		return NULL;
		}
	
	// if not found in registered clients, creates new
	// this may leave under OOM condition
	CCacheMemoryClient* client = CCacheMemoryClient::NewL(*this, aClientName, iCurrentOffsetMark, aMinSizeInSegs, aMaxSizeInSegs);

	// if error happens during client registration, the client will be deleted
	// this may leave under OOM condition
	TInt err = iRegisteredClients.Append(client);
	if (err != KErrNone)
		{
		ASSERT(0);
		delete client;
		client = NULL;
		User::Leave(err);
		}

	// record current offset mark for next client
	iCurrentOffsetMark += (aMaxSizeInSegs << SegmentSizeInBytesLog2());
	return client;
	}

/**
Commit a contiguous set of segments.
@param	aStartRamAddr	the start ram address of the region to be committed.
@param	aSegmentCount	the segment number of the contiguous region to be committed.
@return	TInt	KErrNone if succeeded, KErrNoMemory if passed low memory threshold, otherwise a system-wide error code.
*/
TInt CCacheMemoryManager::AllocateAndLockSegments(TUint8* aStartRamAddr, TInt aSegmentCount)
	{
	__PRINT2(_L("CCacheMemoryManager::AllocateAndLockSegments: base=0x%x, seg=%d"), aStartRamAddr, aSegmentCount);
	TMemoryInfoV1Buf meminfo;
	TInt r = UserHal::MemoryInfo(meminfo);
	__ASSERT_DEBUG(r==KErrNone,Fault(EMemoryInfoFailed));
	if (r != KErrNone)
		{
		return r;
		}

	if (isMemoryLow || (meminfo().iFreeRamInBytes < iLowMemoryThreshold))
		{
		__PRINT(_L("CCacheMemoryManager: free RAM below threshold !!!"));
		return KErrNoMemory;
		}
	return Commit(aStartRamAddr, aSegmentCount);
	}

/**
Notify the change of memory status
@param	aIsMemoryLow	the flag that sets current memory status
*/
void CCacheMemoryManager::FreeMemoryChanged(TBool aIsMemoryLow)
	{
	isMemoryLow = aIsMemoryLow;
	}

/**
Decommit a contiguous set of segments.
@param	aStartRamAddr	the start ram address of the region to be decommitted.
@param	aSegmentCount	the segment number of the contiguous region to be decommitted.
@return	TInt	KErrNone if succeeded, otherwise a system-wide error code.
*/
TInt CCacheMemoryManager::DecommitSegments(TUint8* aStartRamAddr, TUint32 aSegmentCount)
	{
	return Decommit(aStartRamAddr, aSegmentCount);
	}

/**
Lock a contiguous set of segments.
@param	aStartRamAddr	the start ram address of the region to be locked.
@param	aSegmentCount	the segment number of the contiguous region to be locked.
@return	TInt	KErrNone if succeeded, otherwise a system-wide error code.
*/
TInt CCacheMemoryManager::LockSegments(TUint8* aStartRamAddr, TUint32 aSegmentCount)
	{
	return Lock(aStartRamAddr, aSegmentCount);
	}

/**
Unlock a contiguous set of segments.
@param	aStartRamAddr	the start ram address of the region to be unlocked.
@param	aSegmentCount	the segment number of the contiguous region to be unlocked.
@return	TInt	KErrNone if succeeded, otherwise a system-wide error code.
*/
TInt CCacheMemoryManager::UnlockSegments(TUint8* aStartRamAddr, TUint32 aSegmentCount)
	{
	return Unlock(aStartRamAddr, aSegmentCount);
	}

/**
Commit a contiguous set of segments.
@param	aStartRamAddr	the start ram address of the region to be committed.
@param	aSegmentCount	the segment number of the contiguous region to be committed.
@return	TInt	KErrNone if succeeded, otherwise a system-wide error code.
*/
TInt CCacheMemoryManager::Commit(TUint8* aStartRamAddr, TInt aSegmentCount)
	{
	TInt offset = aStartRamAddr - iBase;
	TInt r = iChunk.Commit(offset, aSegmentCount << KSegmentSizeLog2);
	return r;
	}

/**
Actual implementation of DecommitSegments().
@see CCacheMemoryManager::DecommitSegments().
*/
TInt CCacheMemoryManager::Decommit(TUint8* aStartRamAddr, TInt aSegmentCount)
	{
	return iChunk.Decommit(aStartRamAddr - iBase, aSegmentCount << KSegmentSizeLog2);
	}

/**
Actual implementation of UnlockSegments().
@see CCacheMemoryManager::UnlockSegments().
*/
TInt CCacheMemoryManager::Unlock(TUint8* aStartRamAddr, TInt aSegmentCount)
	{
	TInt r = iChunk.Unlock(aStartRamAddr - iBase, aSegmentCount << KSegmentSizeLog2);
	return r;
	}

/**
Actual implementation of LockSegments().
@see CCacheMemoryManager::LockSegments().
*/
TInt CCacheMemoryManager::Lock(TUint8* aStartRamAddr, TInt aSegmentCount)
	{
	return iChunk.Lock(aStartRamAddr - iBase, aSegmentCount << KSegmentSizeLog2);
	}


//=====================================================================
TUint8* CCacheMemoryManager::Base()
	{
	return iChunk.Base();
	}

/**
Get function, returns log2 value of a segment size in bytes.

@internalTechnology
@released
*/
EXPORT_C TUint CCacheMemoryManager::SegmentSizeInBytesLog2() const
	{
	return KSegmentSizeLog2;
	}


//=============================================================================
/**
The singleton of global cache memory manager
*/
CCacheMemoryManager* CCacheMemoryManagerFactory::iCacheMemoryManager = NULL;

/**
Global factory function of CCacheMemoryManager. 
*/
void CCacheMemoryManagerFactory::CreateL()
	{
	iCacheMemoryManager = CCacheMemoryManager::NewL(TGlobalCacheMemorySettings::CacheSize());
	}

/**
Global get function of CCacheMemoryManager. 

@internalTechnology
@released
*/
EXPORT_C CCacheMemoryManager* CCacheMemoryManagerFactory::CacheMemoryManager()
	{
	return iCacheMemoryManager;
	}

/**
Global destroy function of CCacheMemoryManager. 
*/
void CCacheMemoryManagerFactory::Destroy()
	{
	delete iCacheMemoryManager;
	iCacheMemoryManager = NULL;
	}

//=============================================================================
const TInt KByteToByteShift = 10;
TInt32 TGlobalCacheMemorySettings::iCacheSizeInBytes	= KDefaultGlobalCacheMemorySize << KByteToByteShift;
TInt32 TGlobalCacheMemorySettings::iLowMemoryThreshold  = KDefaultLowMemoryThreshold;
_LIT8(KLitSectionNameCacheMemory,"CacheMemory");

/**
Read ESTART.TXT file for global cache memory settings 
*/
void TGlobalCacheMemorySettings::ReadPropertiesFile()
	{
	// Get size of cache in kilobytes
	TInt32 cacheSizeInKBytes;
	if (F32Properties::GetInt(KLitSectionNameCacheMemory, _L8("GlobalCacheMemorySize"), cacheSizeInKBytes))
		{
		iCacheSizeInBytes = cacheSizeInKBytes << KByteToByteShift;
		}

	// Get low memory threshold
	TInt32 lowMemoryThreshold;
	if (F32Properties::GetInt(KLitSectionNameCacheMemory, _L8("LowMemoryThreshold"), lowMemoryThreshold))
		iLowMemoryThreshold = lowMemoryThreshold;
	}

TInt TGlobalCacheMemorySettings::CacheSize()
	{
	return iCacheSizeInBytes;
	}

TInt TGlobalCacheMemorySettings::LowMemoryThreshold()
	{
	return iLowMemoryThreshold;
	}