os/ossrv/lowlevellibsandfws/pluginfw/Framework/frame/resolvercache.cpp
author sl@SLION-WIN7.fritz.box
Fri, 15 Jun 2012 03:10:57 +0200
changeset 0 bde4ae8d615e
permissions -rw-r--r--
First public contribution.
sl@0
     1
// Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
sl@0
     2
// All rights reserved.
sl@0
     3
// This component and the accompanying materials are made available
sl@0
     4
// under the terms of "Eclipse Public License v1.0"
sl@0
     5
// which accompanies this distribution, and is available
sl@0
     6
// at the URL "http://www.eclipse.org/legal/epl-v10.html".
sl@0
     7
//
sl@0
     8
// Initial Contributors:
sl@0
     9
// Nokia Corporation - initial contribution.
sl@0
    10
//
sl@0
    11
// Contributors:
sl@0
    12
//
sl@0
    13
// Description:
sl@0
    14
//
sl@0
    15
sl@0
    16
/**
sl@0
    17
 @file
sl@0
    18
 @internalComponent
sl@0
    19
*/
sl@0
    20
sl@0
    21
#include <e32def.h>
sl@0
    22
#include <e32cmn.h>
sl@0
    23
#include <hal.h>
sl@0
    24
#include "EComDebug.h"
sl@0
    25
#include "ImplementationInformation.h"  // CompareTUidValues
sl@0
    26
#include "callback.h"
sl@0
    27
#include "resolvercache.h"
sl@0
    28
#include "EComPatchDataConstantv2.h"
sl@0
    29
sl@0
    30
const TInt KCacheQueueGranularity = 4;
sl@0
    31
sl@0
    32
//
sl@0
    33
// TCounterTicks class
sl@0
    34
//
sl@0
    35
inline TCounterTicks::TCounterTicks(TUint aTicks)
sl@0
    36
	: iTicks(aTicks)
sl@0
    37
	{
sl@0
    38
	}
sl@0
    39
sl@0
    40
/** This substraction calculate elapsed ticks: aEndTick - this */
sl@0
    41
inline
sl@0
    42
TUint TCounterTicks::ElapsedSinceThis(TUint aEndTick) const
sl@0
    43
	{
sl@0
    44
	TUint diff;
sl@0
    45
	if (aEndTick < iTicks) // wrap around occurred
sl@0
    46
		{
sl@0
    47
		diff = KMaxTUint - iTicks + aEndTick + 1;
sl@0
    48
		}
sl@0
    49
	else
sl@0
    50
		{
sl@0
    51
		diff = aEndTick - iTicks;
sl@0
    52
		}
sl@0
    53
	return diff;
sl@0
    54
	}
sl@0
    55
sl@0
    56
/** default constructor which initializes all member data to 0. */
sl@0
    57
RResolverCacheEntry::RResolverCacheEntry()
sl@0
    58
	: iLastUse( TCounterTicks(0) ), iLruRank(0), iResolverUid(KNullUid),
sl@0
    59
	iNewLFuncPtr(NULL), iFlags(EEntryFlagsNone)
sl@0
    60
	{
sl@0
    61
	iLibrary.SetHandle(KNullHandle);
sl@0
    62
	}
sl@0
    63
sl@0
    64
/** construct RResolverCacheEntry with specific data
sl@0
    65
@param aResolverUid TUid of the resolver.
sl@0
    66
@param aLib RLibrary with handle open on the resolver DLL.
sl@0
    67
@param aNewL Function ptr to instantiate the resolver.
sl@0
    68
@param aFlags Special conditions about the cache entry.
sl@0
    69
*/
sl@0
    70
RResolverCacheEntry::RResolverCacheEntry(const TUid aResolverUid,
sl@0
    71
										RLibrary aLib,
sl@0
    72
										TProxyNewLPtr aNewL,
sl@0
    73
										TUint32 aFlags)
sl@0
    74
	: iLastUse( TCounterTicks(0) ), iLruRank(0), iResolverUid(aResolverUid),
sl@0
    75
	iNewLFuncPtr(aNewL), iFlags(aFlags)
sl@0
    76
	{
sl@0
    77
	iLibrary.SetHandle(aLib.Handle());
sl@0
    78
	}
sl@0
    79
sl@0
    80
/** unallocate resources owned by the RResolverCacheEntry object */
sl@0
    81
void RResolverCacheEntry::Close()
sl@0
    82
	{
sl@0
    83
	iLibrary.Close();
sl@0
    84
	}
sl@0
    85
sl@0
    86
/** This method compares two RResolverCacheEntry objects.
sl@0
    87
@param aEntry1 first RResolverCacheEntry object.
sl@0
    88
@param aEntry2 second RResolverCacheEntry object.
sl@0
    89
@return 0 means the two objects are equal.
sl@0
    90
        positive value means first object is greater than the second.
sl@0
    91
		negative vlaue means second object is greater than the first.
sl@0
    92
*/
sl@0
    93
TInt RResolverCacheEntry::CompareUid(const RResolverCacheEntry& aEntry1,
sl@0
    94
								     const RResolverCacheEntry& aEntry2)
sl@0
    95
	{
sl@0
    96
	return CompareTUidValues(aEntry1.iResolverUid.iUid,
sl@0
    97
							 aEntry2.iResolverUid.iUid);
sl@0
    98
	}
sl@0
    99
sl@0
   100
/** Compare the age of two cache entries.
sl@0
   101
@param aOther The RResolverCacheEntry to compare with.
sl@0
   102
@param aCurrTick The current system tick. It simplifies handling
sl@0
   103
	of system tick wrap around to zero.
sl@0
   104
@return ETrue means "this" object is older than aOther.
sl@0
   105
	EFalse means aOther is older than "this".
sl@0
   106
*/
sl@0
   107
TBool RResolverCacheEntry::ThisIsOlder(const RResolverCacheEntry& aOther,
sl@0
   108
										TUint aCurrTick) const
sl@0
   109
	{
sl@0
   110
	if (iLastUse.iTicks == aOther.iLastUse.iTicks)
sl@0
   111
		{
sl@0
   112
		return iLruRank < aOther.iLruRank;
sl@0
   113
		}
sl@0
   114
sl@0
   115
	// Because of counter wrap around, it is not safe to directly
sl@0
   116
	// compare the two ticks. Drag in the current system tick.
sl@0
   117
	return iLastUse.ElapsedSinceThis(aCurrTick) >
sl@0
   118
			aOther.iLastUse.ElapsedSinceThis(aCurrTick);
sl@0
   119
	}
sl@0
   120
sl@0
   121
//=================================
sl@0
   122
// CCustomResolverCache class
sl@0
   123
//=================================
sl@0
   124
sl@0
   125
/** CCustomResolverCache constructor
sl@0
   126
@param aCacheSize Maximum number of entries allowed to cache.
sl@0
   127
*/
sl@0
   128
CCustomResolverCache::CCustomResolverCache(TUint32 aCacheSize)
sl@0
   129
	: CTimer(CActive::EPriorityStandard),
sl@0
   130
	iResolvers(KCacheQueueGranularity), 
sl@0
   131
	iMaxCacheSize(aCacheSize)
sl@0
   132
	{
sl@0
   133
	}
sl@0
   134
sl@0
   135
/** static factory method to instantiate CCustomResolverCache
sl@0
   136
@param aCacheSize Maximum number of entries allowed to cache.
sl@0
   137
@param aCacheTimeout Cache timeout in microseconds.
sl@0
   138
@leave Any of the system wide error codes.
sl@0
   139
*/
sl@0
   140
CCustomResolverCache* CCustomResolverCache::NewL(TUint32 aCacheSize, TUint32 aCacheTimeout)
sl@0
   141
	{
sl@0
   142
	CCustomResolverCache* self = new (ELeave) CCustomResolverCache(aCacheSize);
sl@0
   143
	CleanupStack::PushL(self);
sl@0
   144
	self->ConstructL(aCacheTimeout);
sl@0
   145
	CleanupStack::Pop(self);
sl@0
   146
	return self;
sl@0
   147
	}
sl@0
   148
sl@0
   149
/** Standard two phase construction to complete construction of
sl@0
   150
the CCustomResolverCache object.
sl@0
   151
@param aCacheTimeout Cache timeout in microseconds.
sl@0
   152
@leave Any of the system wide error codes.
sl@0
   153
*/
sl@0
   154
void CCustomResolverCache::ConstructL(TUint32 aCacheTimeout)
sl@0
   155
	{
sl@0
   156
	User::LeaveIfError(HAL::Get(HALData::ESystemTickPeriod,
sl@0
   157
								iSystemTickPeriod));
sl@0
   158
	iEntryTimeToLive = (aCacheTimeout + iSystemTickPeriod - 1) / iSystemTickPeriod;
sl@0
   159
sl@0
   160
	CTimer::ConstructL();
sl@0
   161
	CActiveScheduler::Add(this);
sl@0
   162
	}
sl@0
   163
sl@0
   164
/** CCustomResolverCache destructor */
sl@0
   165
CCustomResolverCache::~CCustomResolverCache()
sl@0
   166
	{
sl@0
   167
	Cancel();
sl@0
   168
	for (TInt i = iResolvers.Count() - 1; i >= 0; i--)
sl@0
   169
		{
sl@0
   170
		iResolvers[i].Close();
sl@0
   171
		}
sl@0
   172
	iResolvers.Reset();
sl@0
   173
	}
sl@0
   174
sl@0
   175
/** Implement the CActive RunL pure virtual */
sl@0
   176
void CCustomResolverCache::RunL()
sl@0
   177
	{
sl@0
   178
	TUint currTickCount = User::TickCount();
sl@0
   179
	TUint lruAge = 0;
sl@0
   180
sl@0
   181
	for (TInt i = iResolvers.Count() - 1; i >= 0; i--)
sl@0
   182
		{
sl@0
   183
		RResolverCacheEntry& resolverEntry = iResolvers[i];
sl@0
   184
		TUint age = resolverEntry.iLastUse.ElapsedSinceThis(currTickCount);
sl@0
   185
		if (age >= iEntryTimeToLive)
sl@0
   186
			{
sl@0
   187
			resolverEntry.Close();
sl@0
   188
			iResolvers.Remove(i);
sl@0
   189
			}
sl@0
   190
		else if (age > lruAge)
sl@0
   191
			{
sl@0
   192
			lruAge = age;
sl@0
   193
			}
sl@0
   194
		}
sl@0
   195
sl@0
   196
	if (iResolvers.Count() > 0)
sl@0
   197
		{
sl@0
   198
		After( iSystemTickPeriod * (iEntryTimeToLive - lruAge + 1) );
sl@0
   199
		}
sl@0
   200
sl@0
   201
#ifdef __ECOMSERVER_TESTING__
sl@0
   202
	// In unit testing notify test bed that cache timer has fired.
sl@0
   203
	iTimerExpireCB.CallBack(0, NULL);
sl@0
   204
#endif
sl@0
   205
	}
sl@0
   206
sl@0
   207
/** Search of a resolver UID in cache
sl@0
   208
@param aResolverUid the resolver to search for.
sl@0
   209
@return If find is successful, index of the resolver in RArray of cached resolvers.
sl@0
   210
		Return KErrNotFound if resolver is not in cache.
sl@0
   211
*/
sl@0
   212
TInt CCustomResolverCache::FindResolver(const TUid aResolverUid) const
sl@0
   213
	{
sl@0
   214
	RResolverCacheEntry trgt;
sl@0
   215
	trgt.iResolverUid = aResolverUid;
sl@0
   216
	TLinearOrder<RResolverCacheEntry> comparator(RResolverCacheEntry::CompareUid);
sl@0
   217
	return iResolvers.FindInOrder(trgt, comparator);
sl@0
   218
	}
sl@0
   219
sl@0
   220
/** Add a resolver library to cache 
sl@0
   221
@param aResolverUid Implementation UID of the resolver.
sl@0
   222
@param aLib	The RLibrary object which has the resolver loaded. The handle
sl@0
   223
	of the RLibrary is owned by the cache if call is successful.
sl@0
   224
@param aNewL value for the iNewLFuncPtr member data of RResolverCacheEntry.
sl@0
   225
@param aFlags value for the iFlags member data of RResolverCacheEntry.
sl@0
   226
@return KErrNone if the data is added to cache.
sl@0
   227
	KErrNoMemory if fail to insert the data in RArray.
sl@0
   228
*/
sl@0
   229
TInt CCustomResolverCache::CacheResolver(const TUid aResolverUid,
sl@0
   230
										  RLibrary aLib,
sl@0
   231
										  TProxyNewLPtr aNewL,
sl@0
   232
										  TUint32 aFlags)
sl@0
   233
	{
sl@0
   234
	if (iResolvers.Count() == iMaxCacheSize)
sl@0
   235
		{
sl@0
   236
		EvictLeastRecentlyUsed();
sl@0
   237
		}
sl@0
   238
sl@0
   239
	RResolverCacheEntry entry(aResolverUid, aLib, aNewL, aFlags);
sl@0
   240
	SetLastUseTime(entry);
sl@0
   241
sl@0
   242
#ifdef ECOM_TRACE
sl@0
   243
	__ECOM_TRACE2("ECOM: adding custom resolver 0x%X to cache. New queue size will be %d.\n", aResolverUid.iUid, 1 + iResolvers.Count());
sl@0
   244
#endif
sl@0
   245
sl@0
   246
	TLinearOrder<RResolverCacheEntry> comparator(RResolverCacheEntry::CompareUid);
sl@0
   247
	TInt err = iResolvers.InsertInOrder(entry, comparator);
sl@0
   248
sl@0
   249
	// if cache was empty before need to start timer
sl@0
   250
	if (err == KErrNone && ! IsActive())
sl@0
   251
		{
sl@0
   252
		After( iSystemTickPeriod * (iEntryTimeToLive + 1) );
sl@0
   253
		}
sl@0
   254
	return err;
sl@0
   255
	}
sl@0
   256
sl@0
   257
/** Check if both queue size and cache timeout are non zero  */
sl@0
   258
TBool CCustomResolverCache::CachingEnabled() const
sl@0
   259
	{
sl@0
   260
	return (iMaxCacheSize && iEntryTimeToLive);
sl@0
   261
	}
sl@0
   262
sl@0
   263
/** Remove a cached entry
sl@0
   264
@param aIndex position of entry in the array.
sl@0
   265
*/
sl@0
   266
void CCustomResolverCache::Remove(TInt aIndex)
sl@0
   267
	{
sl@0
   268
	iResolvers[aIndex].Close();
sl@0
   269
	iResolvers.Remove(aIndex);
sl@0
   270
	}
sl@0
   271
sl@0
   272
/** Search for a resolverUID. If found, return the NewL pointer and
sl@0
   273
update time to live of the entry.
sl@0
   274
@param aResolverUid the resolver to lookup
sl@0
   275
@param aNewLFuncPtr output parameter. If lookup successful it has
sl@0
   276
	the function pointer to instantiate the resolver.
sl@0
   277
@return True if resolver is in cache. False otherwise.
sl@0
   278
@post If cache hit, the timestamp of the entry is updated.
sl@0
   279
*/
sl@0
   280
TBool CCustomResolverCache::CacheLookup(const TUid aResolverUid,
sl@0
   281
										TProxyNewLPtr& aNewLFuncPtr)
sl@0
   282
	{
sl@0
   283
	TInt i = FindResolver(aResolverUid);
sl@0
   284
	if (i >= 0)
sl@0
   285
		{
sl@0
   286
		aNewLFuncPtr = iResolvers[i].iNewLFuncPtr;
sl@0
   287
		SetLastUseTime(iResolvers[i]);
sl@0
   288
		}
sl@0
   289
	return (i >= 0);
sl@0
   290
	}
sl@0
   291
sl@0
   292
/** Remove a resolver from cache.
sl@0
   293
@param aResolverUid Identify the resolver to remove.
sl@0
   294
@return ETrue if aResolverUid is found in cache. EFalse means the
sl@0
   295
	resolver is not in cache.
sl@0
   296
*/
sl@0
   297
TBool CCustomResolverCache::Remove(const TUid aResolverUid)
sl@0
   298
	{
sl@0
   299
	TInt i = FindResolver(aResolverUid);
sl@0
   300
	if (i >= 0)
sl@0
   301
		{
sl@0
   302
		Remove(i);
sl@0
   303
		}
sl@0
   304
	return (i >= 0);
sl@0
   305
	}
sl@0
   306
sl@0
   307
/** Remove cached entries with flags set.
sl@0
   308
@param aMask If an entry has any of the bits in aMask set, it is removed.
sl@0
   309
*/
sl@0
   310
void CCustomResolverCache::RemoveItemsWithFlags(TUint32 aMask)
sl@0
   311
	{
sl@0
   312
	for (TInt i = iResolvers.Count() - 1; i >= 0; i--)
sl@0
   313
		{
sl@0
   314
		if (iResolvers[i].iFlags & aMask)
sl@0
   315
			{
sl@0
   316
			Remove(i);
sl@0
   317
			}
sl@0
   318
		}
sl@0
   319
	}
sl@0
   320
sl@0
   321
/** evict the least recently used entry in cache
sl@0
   322
*/
sl@0
   323
void CCustomResolverCache::EvictLeastRecentlyUsed()
sl@0
   324
	{
sl@0
   325
	TUint curr = User::TickCount();
sl@0
   326
	TInt index = 0; // set to first entry in cache.
sl@0
   327
sl@0
   328
	for (TInt i = 1; i < iResolvers.Count(); i++)
sl@0
   329
		{
sl@0
   330
		RResolverCacheEntry& resolverEntry = iResolvers[i];
sl@0
   331
		if (resolverEntry.ThisIsOlder(iResolvers[index], curr))
sl@0
   332
			{
sl@0
   333
			index = i;
sl@0
   334
			}
sl@0
   335
		}
sl@0
   336
sl@0
   337
	Remove(index);
sl@0
   338
	}
sl@0
   339
sl@0
   340
/** Set the iLastUse field and iLruRank field of the entry.
sl@0
   341
The iLruRank field serves as tie breaker when two entries are
sl@0
   342
added within the same tick period.
sl@0
   343
@param aEntry The entry to update.
sl@0
   344
*/
sl@0
   345
void CCustomResolverCache::SetLastUseTime(RResolverCacheEntry& aEntry)
sl@0
   346
	{
sl@0
   347
	TUint curr = User::TickCount();
sl@0
   348
	aEntry.iLastUse.iTicks = curr;
sl@0
   349
	aEntry.iLruRank = 0;
sl@0
   350
sl@0
   351
	if (curr == iMostRecentTimestamp)
sl@0
   352
		{
sl@0
   353
		// There are entries with same timestamp. So have to step
sl@0
   354
		// through each cache entry to resolve senority.
sl@0
   355
		for (TInt i = 0; i < iResolvers.Count(); i++)
sl@0
   356
			{
sl@0
   357
			RResolverCacheEntry& another = iResolvers[i];
sl@0
   358
			if (another.iLastUse.iTicks == curr &&
sl@0
   359
				another.iResolverUid != aEntry.iResolverUid &&
sl@0
   360
				another.iLruRank >= aEntry.iLruRank)
sl@0
   361
				{
sl@0
   362
				aEntry.iLruRank = another.iLruRank + 1;
sl@0
   363
				}
sl@0
   364
			}
sl@0
   365
		}
sl@0
   366
	else
sl@0
   367
		{
sl@0
   368
		iMostRecentTimestamp = curr;
sl@0
   369
		}
sl@0
   370
	}
sl@0
   371