diff -r 000000000000 -r e4d67989cc36 lowlevellibsandfws/pluginfw/Framework/frame/resolvercache.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lowlevellibsandfws/pluginfw/Framework/frame/resolvercache.cpp Tue Feb 02 02:01:42 2010 +0200 @@ -0,0 +1,371 @@ +// 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 "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 +*/ + +#include +#include +#include +#include "EComDebug.h" +#include "ImplementationInformation.h" // CompareTUidValues +#include "callback.h" +#include "resolvercache.h" +#include "EComPatchDataConstantv2.h" + +const TInt KCacheQueueGranularity = 4; + +// +// TCounterTicks class +// +inline TCounterTicks::TCounterTicks(TUint aTicks) + : iTicks(aTicks) + { + } + +/** This substraction calculate elapsed ticks: aEndTick - this */ +inline +TUint TCounterTicks::ElapsedSinceThis(TUint aEndTick) const + { + TUint diff; + if (aEndTick < iTicks) // wrap around occurred + { + diff = KMaxTUint - iTicks + aEndTick + 1; + } + else + { + diff = aEndTick - iTicks; + } + return diff; + } + +/** default constructor which initializes all member data to 0. */ +RResolverCacheEntry::RResolverCacheEntry() + : iLastUse( TCounterTicks(0) ), iLruRank(0), iResolverUid(KNullUid), + iNewLFuncPtr(NULL), iFlags(EEntryFlagsNone) + { + iLibrary.SetHandle(KNullHandle); + } + +/** construct RResolverCacheEntry with specific data +@param aResolverUid TUid of the resolver. +@param aLib RLibrary with handle open on the resolver DLL. +@param aNewL Function ptr to instantiate the resolver. +@param aFlags Special conditions about the cache entry. +*/ +RResolverCacheEntry::RResolverCacheEntry(const TUid aResolverUid, + RLibrary aLib, + TProxyNewLPtr aNewL, + TUint32 aFlags) + : iLastUse( TCounterTicks(0) ), iLruRank(0), iResolverUid(aResolverUid), + iNewLFuncPtr(aNewL), iFlags(aFlags) + { + iLibrary.SetHandle(aLib.Handle()); + } + +/** unallocate resources owned by the RResolverCacheEntry object */ +void RResolverCacheEntry::Close() + { + iLibrary.Close(); + } + +/** This method compares two RResolverCacheEntry objects. +@param aEntry1 first RResolverCacheEntry object. +@param aEntry2 second RResolverCacheEntry object. +@return 0 means the two objects are equal. + positive value means first object is greater than the second. + negative vlaue means second object is greater than the first. +*/ +TInt RResolverCacheEntry::CompareUid(const RResolverCacheEntry& aEntry1, + const RResolverCacheEntry& aEntry2) + { + return CompareTUidValues(aEntry1.iResolverUid.iUid, + aEntry2.iResolverUid.iUid); + } + +/** Compare the age of two cache entries. +@param aOther The RResolverCacheEntry to compare with. +@param aCurrTick The current system tick. It simplifies handling + of system tick wrap around to zero. +@return ETrue means "this" object is older than aOther. + EFalse means aOther is older than "this". +*/ +TBool RResolverCacheEntry::ThisIsOlder(const RResolverCacheEntry& aOther, + TUint aCurrTick) const + { + if (iLastUse.iTicks == aOther.iLastUse.iTicks) + { + return iLruRank < aOther.iLruRank; + } + + // Because of counter wrap around, it is not safe to directly + // compare the two ticks. Drag in the current system tick. + return iLastUse.ElapsedSinceThis(aCurrTick) > + aOther.iLastUse.ElapsedSinceThis(aCurrTick); + } + +//================================= +// CCustomResolverCache class +//================================= + +/** CCustomResolverCache constructor +@param aCacheSize Maximum number of entries allowed to cache. +*/ +CCustomResolverCache::CCustomResolverCache(TUint32 aCacheSize) + : CTimer(CActive::EPriorityStandard), + iResolvers(KCacheQueueGranularity), + iMaxCacheSize(aCacheSize) + { + } + +/** static factory method to instantiate CCustomResolverCache +@param aCacheSize Maximum number of entries allowed to cache. +@param aCacheTimeout Cache timeout in microseconds. +@leave Any of the system wide error codes. +*/ +CCustomResolverCache* CCustomResolverCache::NewL(TUint32 aCacheSize, TUint32 aCacheTimeout) + { + CCustomResolverCache* self = new (ELeave) CCustomResolverCache(aCacheSize); + CleanupStack::PushL(self); + self->ConstructL(aCacheTimeout); + CleanupStack::Pop(self); + return self; + } + +/** Standard two phase construction to complete construction of +the CCustomResolverCache object. +@param aCacheTimeout Cache timeout in microseconds. +@leave Any of the system wide error codes. +*/ +void CCustomResolverCache::ConstructL(TUint32 aCacheTimeout) + { + User::LeaveIfError(HAL::Get(HALData::ESystemTickPeriod, + iSystemTickPeriod)); + iEntryTimeToLive = (aCacheTimeout + iSystemTickPeriod - 1) / iSystemTickPeriod; + + CTimer::ConstructL(); + CActiveScheduler::Add(this); + } + +/** CCustomResolverCache destructor */ +CCustomResolverCache::~CCustomResolverCache() + { + Cancel(); + for (TInt i = iResolvers.Count() - 1; i >= 0; i--) + { + iResolvers[i].Close(); + } + iResolvers.Reset(); + } + +/** Implement the CActive RunL pure virtual */ +void CCustomResolverCache::RunL() + { + TUint currTickCount = User::TickCount(); + TUint lruAge = 0; + + for (TInt i = iResolvers.Count() - 1; i >= 0; i--) + { + RResolverCacheEntry& resolverEntry = iResolvers[i]; + TUint age = resolverEntry.iLastUse.ElapsedSinceThis(currTickCount); + if (age >= iEntryTimeToLive) + { + resolverEntry.Close(); + iResolvers.Remove(i); + } + else if (age > lruAge) + { + lruAge = age; + } + } + + if (iResolvers.Count() > 0) + { + After( iSystemTickPeriod * (iEntryTimeToLive - lruAge + 1) ); + } + +#ifdef __ECOMSERVER_TESTING__ + // In unit testing notify test bed that cache timer has fired. + iTimerExpireCB.CallBack(0, NULL); +#endif + } + +/** Search of a resolver UID in cache +@param aResolverUid the resolver to search for. +@return If find is successful, index of the resolver in RArray of cached resolvers. + Return KErrNotFound if resolver is not in cache. +*/ +TInt CCustomResolverCache::FindResolver(const TUid aResolverUid) const + { + RResolverCacheEntry trgt; + trgt.iResolverUid = aResolverUid; + TLinearOrder comparator(RResolverCacheEntry::CompareUid); + return iResolvers.FindInOrder(trgt, comparator); + } + +/** Add a resolver library to cache +@param aResolverUid Implementation UID of the resolver. +@param aLib The RLibrary object which has the resolver loaded. The handle + of the RLibrary is owned by the cache if call is successful. +@param aNewL value for the iNewLFuncPtr member data of RResolverCacheEntry. +@param aFlags value for the iFlags member data of RResolverCacheEntry. +@return KErrNone if the data is added to cache. + KErrNoMemory if fail to insert the data in RArray. +*/ +TInt CCustomResolverCache::CacheResolver(const TUid aResolverUid, + RLibrary aLib, + TProxyNewLPtr aNewL, + TUint32 aFlags) + { + if (iResolvers.Count() == iMaxCacheSize) + { + EvictLeastRecentlyUsed(); + } + + RResolverCacheEntry entry(aResolverUid, aLib, aNewL, aFlags); + SetLastUseTime(entry); + +#ifdef ECOM_TRACE + __ECOM_TRACE2("ECOM: adding custom resolver 0x%X to cache. New queue size will be %d.\n", aResolverUid.iUid, 1 + iResolvers.Count()); +#endif + + TLinearOrder comparator(RResolverCacheEntry::CompareUid); + TInt err = iResolvers.InsertInOrder(entry, comparator); + + // if cache was empty before need to start timer + if (err == KErrNone && ! IsActive()) + { + After( iSystemTickPeriod * (iEntryTimeToLive + 1) ); + } + return err; + } + +/** Check if both queue size and cache timeout are non zero */ +TBool CCustomResolverCache::CachingEnabled() const + { + return (iMaxCacheSize && iEntryTimeToLive); + } + +/** Remove a cached entry +@param aIndex position of entry in the array. +*/ +void CCustomResolverCache::Remove(TInt aIndex) + { + iResolvers[aIndex].Close(); + iResolvers.Remove(aIndex); + } + +/** Search for a resolverUID. If found, return the NewL pointer and +update time to live of the entry. +@param aResolverUid the resolver to lookup +@param aNewLFuncPtr output parameter. If lookup successful it has + the function pointer to instantiate the resolver. +@return True if resolver is in cache. False otherwise. +@post If cache hit, the timestamp of the entry is updated. +*/ +TBool CCustomResolverCache::CacheLookup(const TUid aResolverUid, + TProxyNewLPtr& aNewLFuncPtr) + { + TInt i = FindResolver(aResolverUid); + if (i >= 0) + { + aNewLFuncPtr = iResolvers[i].iNewLFuncPtr; + SetLastUseTime(iResolvers[i]); + } + return (i >= 0); + } + +/** Remove a resolver from cache. +@param aResolverUid Identify the resolver to remove. +@return ETrue if aResolverUid is found in cache. EFalse means the + resolver is not in cache. +*/ +TBool CCustomResolverCache::Remove(const TUid aResolverUid) + { + TInt i = FindResolver(aResolverUid); + if (i >= 0) + { + Remove(i); + } + return (i >= 0); + } + +/** Remove cached entries with flags set. +@param aMask If an entry has any of the bits in aMask set, it is removed. +*/ +void CCustomResolverCache::RemoveItemsWithFlags(TUint32 aMask) + { + for (TInt i = iResolvers.Count() - 1; i >= 0; i--) + { + if (iResolvers[i].iFlags & aMask) + { + Remove(i); + } + } + } + +/** evict the least recently used entry in cache +*/ +void CCustomResolverCache::EvictLeastRecentlyUsed() + { + TUint curr = User::TickCount(); + TInt index = 0; // set to first entry in cache. + + for (TInt i = 1; i < iResolvers.Count(); i++) + { + RResolverCacheEntry& resolverEntry = iResolvers[i]; + if (resolverEntry.ThisIsOlder(iResolvers[index], curr)) + { + index = i; + } + } + + Remove(index); + } + +/** Set the iLastUse field and iLruRank field of the entry. +The iLruRank field serves as tie breaker when two entries are +added within the same tick period. +@param aEntry The entry to update. +*/ +void CCustomResolverCache::SetLastUseTime(RResolverCacheEntry& aEntry) + { + TUint curr = User::TickCount(); + aEntry.iLastUse.iTicks = curr; + aEntry.iLruRank = 0; + + if (curr == iMostRecentTimestamp) + { + // There are entries with same timestamp. So have to step + // through each cache entry to resolve senority. + for (TInt i = 0; i < iResolvers.Count(); i++) + { + RResolverCacheEntry& another = iResolvers[i]; + if (another.iLastUse.iTicks == curr && + another.iResolverUid != aEntry.iResolverUid && + another.iLruRank >= aEntry.iLruRank) + { + aEntry.iLruRank = another.iLruRank + 1; + } + } + } + else + { + iMostRecentTimestamp = curr; + } + } +