userlibandfileserver/fileserver/sfile/sf_memory_man.cpp
author Tom Cosgrove <tom.cosgrove@nokia.com>
Fri, 28 May 2010 16:26:05 +0100
branchRCL_3
changeset 29 743008598095
parent 19 4a8fed1c0ef6
child 43 c1f20ce4abcf
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) 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);
	
	// search for existing clients by name
	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];
			}
		}

	// if it is a new drive/file system who wants to connect, create a new client for it
	// parameter validation
	if (iSizeInBytes < iCurrentOffsetMark + (aMaxSizeInSegs << SegmentSizeInBytesLog2()))
		{
		__PRINT1(_L("CCacheMemoryManager::ConnectClientL([%S]) failed, please check \"GlobalCacheMemorySize\" setting!!!"), &aClientName);
		User::Leave(KErrArgument);
		}
	
	// note: client creation may leave under OOM conditions
	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 conditions
	TInt err = iRegisteredClients.Append(client);
	if (err != KErrNone)
		{
		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()
	{
	if (TGlobalCacheMemorySettings::CacheSize() > 0)
	    iCacheMemoryManager = CCacheMemoryManager::NewL(TGlobalCacheMemorySettings::CacheSize());
	else
	    __PRINT(_L("\"GlobalCacheMemorySize\" set <= 0, CCacheMemoryManager is not created!!!"));
	}

/**
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;
	}