Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

906 lines
22 KiB

//+---------------------------------------------------------------------------
//
// Microsoft Windows NT Security
// Copyright (C) Microsoft Corporation, 1997 - 1999
//
// File: lru.cpp
//
// Contents: LRU cache implementation
//
// History: 24-Dec-97 kirtd Created
//
//----------------------------------------------------------------------------
#include <global.hxx>
//+---------------------------------------------------------------------------
//
// Member: CLruEntry::CLruEntry, public
//
// Synopsis: Constructor
//
//----------------------------------------------------------------------------
CLruEntry::CLruEntry (
IN PCLRUCACHE pCache,
IN PCRYPT_DATA_BLOB pIdentifier,
IN LPVOID pvData,
OUT BOOL& rfResult
)
{
rfResult = TRUE;
m_cRefs = 1;
m_pPrevEntry = NULL;
m_pNextEntry = NULL;
m_Usage = 0;
m_pCache = pCache;
m_pvData = pvData;
m_pBucket = pCache->BucketFromIdentifier( pIdentifier );
if ( pCache->Flags() & LRU_CACHE_NO_COPY_IDENTIFIER )
{
m_Identifier = *pIdentifier;
}
else
{
m_Identifier.cbData = pIdentifier->cbData;
m_Identifier.pbData = new BYTE [ pIdentifier->cbData ];
if ( m_Identifier.pbData != NULL )
{
memcpy(
m_Identifier.pbData,
pIdentifier->pbData,
pIdentifier->cbData
);
}
else
{
rfResult = FALSE;
SetLastError( (DWORD) E_OUTOFMEMORY );
return;
}
}
assert( m_pBucket != NULL );
assert( m_Identifier.pbData != NULL );
}
//+---------------------------------------------------------------------------
//
// Member: CLruEntry::~CLruEntry, public
//
// Synopsis: Destructor
//
//----------------------------------------------------------------------------
CLruEntry::~CLruEntry ()
{
m_pCache->FreeEntryData( m_pvData );
if ( !( m_pCache->Flags() & LRU_CACHE_NO_COPY_IDENTIFIER ) )
{
delete m_Identifier.pbData;
}
}
//+---------------------------------------------------------------------------
//
// Member: CLruCache::CLruCache, public
//
// Synopsis: Constructor
//
//----------------------------------------------------------------------------
CLruCache::CLruCache (
IN PLRU_CACHE_CONFIG pConfig,
OUT BOOL& rfResult
)
{
rfResult = TRUE;
m_Config.dwFlags = LRU_CACHE_NO_SERIALIZE;
m_cEntries = 0;
m_aBucket = new LRU_CACHE_BUCKET [ pConfig->cBuckets ];
if ( m_aBucket == NULL )
{
rfResult = FALSE;
SetLastError( (DWORD) E_OUTOFMEMORY );
return;
}
memset( m_aBucket, 0, sizeof( LRU_CACHE_BUCKET ) * pConfig->cBuckets );
if ( !( pConfig->dwFlags & LRU_CACHE_NO_SERIALIZE ) )
{
if (! Pki_InitializeCriticalSection( &m_Lock ))
{
rfResult = FALSE;
return;
}
}
m_Config = *pConfig;
m_UsageClock = 0;
m_cLruDisabled = 0;
}
//+---------------------------------------------------------------------------
//
// Member: CLruCache::~CLruCache, public
//
// Synopsis: Destructor
//
//----------------------------------------------------------------------------
CLruCache::~CLruCache ()
{
if ( m_cEntries > 0 )
{
PurgeAllEntries( 0, NULL );
}
if ( !( m_Config.dwFlags & LRU_CACHE_NO_SERIALIZE ) )
{
DeleteCriticalSection( &m_Lock );
}
delete m_aBucket;
}
//+---------------------------------------------------------------------------
//
// Member: CLruCache::EnableLruOfEntries, public
//
// Synopsis: enable LRU of entries and purge anything over the watermark
//
//----------------------------------------------------------------------------
VOID
CLruCache::EnableLruOfEntries (IN OPTIONAL LPVOID pvLruRemovalContext)
{
LockCache();
assert( m_cLruDisabled > 0 );
if ( m_cLruDisabled == 0 )
{
return;
}
m_cLruDisabled -= 1;
if ( m_cLruDisabled == 0 )
{
while ( m_cEntries > m_Config.MaxEntries )
{
PurgeLeastRecentlyUsed( pvLruRemovalContext );
}
}
UnlockCache();
}
//+---------------------------------------------------------------------------
//
// Member: CLruCache::DisableLruOfEntries, public
//
// Synopsis: disable LRU of entries
//
//----------------------------------------------------------------------------
VOID
CLruCache::DisableLruOfEntries ()
{
LockCache();
m_cLruDisabled += 1;
UnlockCache();
}
//+---------------------------------------------------------------------------
//
// Member: CLruCache::InsertEntry, public
//
// Synopsis: insert an entry into the cache
//
//----------------------------------------------------------------------------
VOID
CLruCache::InsertEntry (
IN PCLRUENTRY pEntry,
IN OPTIONAL LPVOID pvLruRemovalContext
)
{
assert( pEntry->PrevPointer() == NULL );
assert( pEntry->NextPointer() == NULL );
pEntry->AddRef();
LockCache();
if ( ( m_cEntries == m_Config.MaxEntries ) &&
( m_Config.MaxEntries != 0 ) &&
( m_cLruDisabled == 0 ) )
{
PurgeLeastRecentlyUsed( pvLruRemovalContext );
}
assert( ( m_cEntries < m_Config.MaxEntries ) ||
( m_Config.MaxEntries == 0 ) ||
( m_cLruDisabled > 0 ) );
pEntry->SetNextPointer( pEntry->Bucket()->pList );
if ( pEntry->Bucket()->pList != NULL )
{
pEntry->Bucket()->pList->SetPrevPointer( pEntry );
}
pEntry->Bucket()->pList = pEntry;
m_cEntries += 1;
TouchEntryNoLock( pEntry, 0 );
UnlockCache();
}
//+---------------------------------------------------------------------------
//
// Member: CLruCache::RemoveEntry, public
//
// Synopsis: remove an entry from the cache
//
//----------------------------------------------------------------------------
VOID
CLruCache::RemoveEntry (
IN PCLRUENTRY pEntry,
IN DWORD dwFlags,
IN OPTIONAL LPVOID pvRemovalContext
)
{
LockCache();
RemoveEntryFromBucket(
pEntry->Bucket(),
pEntry,
dwFlags,
pvRemovalContext
);
UnlockCache();
}
//+---------------------------------------------------------------------------
//
// Member: CLruCache::TouchEntry, public
//
// Synopsis: touch the entry
//
//----------------------------------------------------------------------------
VOID
CLruCache::TouchEntry (IN PCLRUENTRY pEntry, IN DWORD dwFlags)
{
LockCache();
TouchEntryNoLock( pEntry, dwFlags );
UnlockCache();
}
//+---------------------------------------------------------------------------
//
// Member: CLruCache::FindEntry, public
//
// Synopsis: find the entry matching the given identifier
//
//----------------------------------------------------------------------------
PCLRUENTRY
CLruCache::FindEntry (IN PCRYPT_DATA_BLOB pIdentifier, IN BOOL fTouchEntry)
{
PLRU_CACHE_BUCKET pBucket;
pBucket = BucketFromIdentifier( pIdentifier );
assert( pBucket != NULL );
return( FindNextMatchingEntryInBucket(
pBucket,
NULL,
pIdentifier,
fTouchEntry
) );
}
//+---------------------------------------------------------------------------
//
// Member: CLruCache::NextMatchingEntry, public
//
// Synopsis: find the next matching entry to pPrevEntry
//
//----------------------------------------------------------------------------
PCLRUENTRY
CLruCache::NextMatchingEntry (IN PCLRUENTRY pPrevEntry, IN BOOL fTouchEntry)
{
PCLRUENTRY pNextEntry;
pNextEntry = FindNextMatchingEntryInBucket(
NULL,
pPrevEntry,
NULL,
fTouchEntry
);
pPrevEntry->Release();
return( pNextEntry );
}
//+---------------------------------------------------------------------------
//
// Member: CLruCache::WalkEntries, public
//
// Synopsis: walk the entries
//
//----------------------------------------------------------------------------
VOID
CLruCache::WalkEntries (IN PFN_WALK_ENTRIES pfnWalk, IN LPVOID pvParameter)
{
DWORD cCount;
PCLRUENTRY pEntry;
PCLRUENTRY pNextEntry;
for ( cCount = 0; cCount < m_Config.cBuckets; cCount++ )
{
pEntry = m_aBucket[ cCount ].pList;
while ( pEntry != NULL )
{
pNextEntry = pEntry->NextPointer();
if ( ( *pfnWalk )( pvParameter, pEntry ) == FALSE )
{
return;
}
pEntry = pNextEntry;
}
}
}
//+---------------------------------------------------------------------------
//
// Member: CLruCache::RemoveEntryFromBucket, public
//
// Synopsis: remove entry from bucket
//
//----------------------------------------------------------------------------
VOID
CLruCache::RemoveEntryFromBucket (
IN PLRU_CACHE_BUCKET pBucket,
IN PCLRUENTRY pEntry,
IN DWORD dwFlags,
IN OPTIONAL LPVOID pvRemovalContext
)
{
if ( pEntry->PrevPointer() != NULL )
{
pEntry->PrevPointer()->SetNextPointer( pEntry->NextPointer() );
}
else
{
assert( pBucket->pList == pEntry );
pBucket->pList = pEntry->NextPointer();
}
if ( pEntry->NextPointer() != NULL )
{
pEntry->NextPointer()->SetPrevPointer( pEntry->PrevPointer() );
}
pEntry->SetPrevPointer( NULL );
pEntry->SetNextPointer( NULL );
m_cEntries -= 1;
if ( ( m_Config.pfnOnRemoval != NULL ) &&
!( dwFlags & LRU_SUPPRESS_REMOVAL_NOTIFICATION ) )
{
( *m_Config.pfnOnRemoval )( pEntry->Data(), pvRemovalContext );
}
pEntry->Release();
}
//+---------------------------------------------------------------------------
//
// Member: CLruCache::FindNextMatchingEntryInBucket, public
//
// Synopsis: find the next matching entry in the given bucket. If pCurrent
// is non NULL then start from there, the bucket is not needed and
// pIdentifier is ignored. If pCurrent is NULL then pIdentifier
// and the bucket must both be non NULL
//
//----------------------------------------------------------------------------
PCLRUENTRY
CLruCache::FindNextMatchingEntryInBucket (
IN PLRU_CACHE_BUCKET pBucket,
IN PCLRUENTRY pCurrent,
IN PCRYPT_DATA_BLOB pIdentifier,
IN BOOL fTouchEntry
)
{
LockCache();
if ( pCurrent == NULL )
{
pCurrent = pBucket->pList;
}
else
{
pIdentifier = pCurrent->Identifier();
pCurrent = pCurrent->NextPointer();
}
while ( pCurrent != NULL )
{
if ( ( pIdentifier->cbData == pCurrent->Identifier()->cbData ) &&
( memcmp(
pIdentifier->pbData,
pCurrent->Identifier()->pbData,
pIdentifier->cbData
) == 0 ) )
{
break;
}
pCurrent = pCurrent->NextPointer();
}
if ( pCurrent != NULL )
{
pCurrent->AddRef();
if ( fTouchEntry == TRUE )
{
TouchEntryNoLock( pCurrent, 0 );
}
}
UnlockCache();
return( pCurrent );
}
//+---------------------------------------------------------------------------
//
// Member: CLruCache::PurgeLeastRecentlyUsed, public
//
// Synopsis: find and remove the least recently used entry
//
//----------------------------------------------------------------------------
VOID
CLruCache::PurgeLeastRecentlyUsed (IN OPTIONAL LPVOID pvLruRemovalContext)
{
DWORD cCount;
PLRU_CACHE_BUCKET pBucket;
PCLRUENTRY pEntry;
PCLRUENTRY pLRU;
assert( m_cEntries > 0 );
for ( cCount = 0; cCount < m_Config.cBuckets; cCount++ )
{
if ( m_aBucket[cCount].pList != NULL )
{
break;
}
}
pBucket = &m_aBucket[cCount];
cCount += 1;
for ( ; cCount < m_Config.cBuckets; cCount++ )
{
if ( ( m_aBucket[cCount].pList != NULL ) &&
( m_aBucket[cCount].Usage < pBucket->Usage ) )
{
pBucket = &m_aBucket[cCount];
}
}
assert( pBucket != NULL );
assert( pBucket->pList != NULL );
pLRU = pBucket->pList;
pEntry = pLRU->NextPointer();
while ( pEntry != NULL )
{
if ( pEntry->Usage() < pLRU->Usage() )
{
pLRU = pEntry;
}
pEntry = pEntry->NextPointer();
}
RemoveEntryFromBucket( pBucket, pLRU, 0, pvLruRemovalContext );
}
//+---------------------------------------------------------------------------
//
// Member: CLruCache::PurgeAllEntries, public
//
// Synopsis: remove all entries from the cache
//
//----------------------------------------------------------------------------
VOID
CLruCache::PurgeAllEntries (
IN DWORD dwFlags,
IN OPTIONAL LPVOID pvRemovalContext
)
{
DWORD cCount;
for ( cCount = 0; cCount < m_Config.cBuckets; cCount++ )
{
while ( m_aBucket[cCount].pList != NULL )
{
RemoveEntryFromBucket(
&m_aBucket[cCount],
m_aBucket[cCount].pList,
dwFlags,
pvRemovalContext
);
}
}
assert( m_cEntries == 0 );
}
//+---------------------------------------------------------------------------
//
// Function: I_CryptCreateLruCache
//
// Synopsis: create an LRU cache area
//
//----------------------------------------------------------------------------
BOOL WINAPI
I_CryptCreateLruCache (
IN PLRU_CACHE_CONFIG pConfig,
OUT HLRUCACHE* phCache
)
{
BOOL fResult = FALSE;
PCLRUCACHE pCache;
pCache = new CLruCache( pConfig, fResult );
if ( pCache == NULL )
{
SetLastError( (DWORD) E_OUTOFMEMORY );
return( FALSE );
}
if ( fResult == FALSE )
{
delete pCache;
return( FALSE );
}
*phCache = (HLRUCACHE)pCache;
return( TRUE );
}
//+---------------------------------------------------------------------------
//
// Function: I_CryptFlushLruCache
//
// Synopsis: flush the cache
//
//----------------------------------------------------------------------------
VOID WINAPI
I_CryptFlushLruCache (
IN HLRUCACHE hCache,
IN OPTIONAL DWORD dwFlags,
IN OPTIONAL LPVOID pvRemovalContext
)
{
( (PCLRUCACHE)hCache )->LockCache();
( (PCLRUCACHE)hCache )->PurgeAllEntries( dwFlags, pvRemovalContext );
( (PCLRUCACHE)hCache )->UnlockCache();
}
//+---------------------------------------------------------------------------
//
// Function: I_CryptFreeLruCache
//
// Synopsis: free the LRU cache area
//
//----------------------------------------------------------------------------
VOID WINAPI
I_CryptFreeLruCache (
IN HLRUCACHE hCache,
IN DWORD dwFlags,
IN OPTIONAL LPVOID pvRemovalContext
)
{
if ( hCache == NULL )
{
return;
}
if ( dwFlags != 0 )
{
( (PCLRUCACHE)hCache )->PurgeAllEntries( dwFlags, pvRemovalContext );
}
delete (PCLRUCACHE)hCache;
}
//+---------------------------------------------------------------------------
//
// Function: I_CryptCreateLruEntry
//
// Synopsis: create an LRU entry
//
//----------------------------------------------------------------------------
BOOL WINAPI
I_CryptCreateLruEntry (
IN HLRUCACHE hCache,
IN PCRYPT_DATA_BLOB pIdentifier,
IN LPVOID pvData,
OUT HLRUENTRY* phEntry
)
{
BOOL fResult = FALSE;
PCLRUENTRY pEntry;
pEntry = new CLruEntry(
(PCLRUCACHE)hCache,
pIdentifier,
pvData,
fResult
);
if ( pEntry == NULL )
{
SetLastError( (DWORD) E_OUTOFMEMORY );
return( FALSE );
}
if ( fResult == FALSE )
{
delete pEntry;
return( FALSE );
}
*phEntry = (HLRUENTRY)pEntry;
return( TRUE );
}
//+---------------------------------------------------------------------------
//
// Function: I_CryptGetLruEntryIdentifier
//
// Synopsis: return the identifier for the entry
//
//----------------------------------------------------------------------------
PCRYPT_DATA_BLOB WINAPI
I_CryptGetLruEntryIdentifier (
IN HLRUENTRY hEntry
)
{
return( ( (PCLRUENTRY)hEntry )->Identifier() );
}
//+---------------------------------------------------------------------------
//
// Function: I_CryptGetLruEntryData
//
// Synopsis: get the data associated with the entry
//
//----------------------------------------------------------------------------
LPVOID WINAPI
I_CryptGetLruEntryData (
IN HLRUENTRY hEntry
)
{
return( ( (PCLRUENTRY)hEntry )->Data() );
}
//+---------------------------------------------------------------------------
//
// Function: I_CryptAddRefLruEntry
//
// Synopsis: add a reference to the entry
//
//----------------------------------------------------------------------------
VOID WINAPI
I_CryptAddRefLruEntry (
IN HLRUENTRY hEntry
)
{
( (PCLRUENTRY)hEntry )->AddRef();
}
//+---------------------------------------------------------------------------
//
// Function: I_CryptReleaseLruEntry
//
// Synopsis: remove a reference from the entry
//
//----------------------------------------------------------------------------
VOID WINAPI
I_CryptReleaseLruEntry (
IN HLRUENTRY hEntry
)
{
( (PCLRUENTRY)hEntry )->Release();
}
//+---------------------------------------------------------------------------
//
// Function: I_CryptInsertLruEntry
//
// Synopsis: insert the entry into its associated cache
//
//----------------------------------------------------------------------------
VOID WINAPI
I_CryptInsertLruEntry (
IN HLRUENTRY hEntry,
IN OPTIONAL LPVOID pvLruRemovalContext
)
{
PCLRUENTRY pEntry = (PCLRUENTRY)hEntry;
pEntry->Cache()->InsertEntry( pEntry, pvLruRemovalContext );
}
//+---------------------------------------------------------------------------
//
// Function: I_CryptRemoveLruEntry
//
// Synopsis: remove the entry from its associated cache
//
//----------------------------------------------------------------------------
VOID WINAPI
I_CryptRemoveLruEntry (
IN HLRUENTRY hEntry,
IN DWORD dwFlags,
IN LPVOID pvLruRemovalContext
)
{
PCLRUENTRY pEntry = (PCLRUENTRY)hEntry;
pEntry->Cache()->RemoveEntry( pEntry, dwFlags, pvLruRemovalContext );
}
//+---------------------------------------------------------------------------
//
// Function: I_CryptTouchLruEntry
//
// Synopsis: touch the entry
//
//----------------------------------------------------------------------------
VOID WINAPI
I_CryptTouchLruEntry (
IN HLRUENTRY hEntry,
IN DWORD dwFlags
)
{
PCLRUENTRY pEntry = (PCLRUENTRY)hEntry;
pEntry->Cache()->TouchEntry( pEntry, dwFlags );
}
//+---------------------------------------------------------------------------
//
// Function: I_CryptFindLruEntry
//
// Synopsis: find the entry with the given identifier
//
//----------------------------------------------------------------------------
HLRUENTRY WINAPI
I_CryptFindLruEntry (
IN HLRUCACHE hCache,
IN PCRYPT_DATA_BLOB pIdentifier
)
{
PCLRUCACHE pCache = (PCLRUCACHE)hCache;
return( pCache->FindEntry( pIdentifier, FALSE ) );
}
//+---------------------------------------------------------------------------
//
// Function: I_CryptFindLruEntryData
//
// Synopsis: find the entry with the given identifier
//
//----------------------------------------------------------------------------
LPVOID WINAPI
I_CryptFindLruEntryData (
IN HLRUCACHE hCache,
IN PCRYPT_DATA_BLOB pIdentifier,
OUT HLRUENTRY* phEntry
)
{
PCLRUCACHE pCache = (PCLRUCACHE)hCache;
PCLRUENTRY pEntry;
pEntry = pCache->FindEntry( pIdentifier, TRUE );
*phEntry = (HLRUENTRY)pEntry;
if ( pEntry != NULL )
{
return( pEntry->Data() );
}
return( NULL );
}
//+---------------------------------------------------------------------------
//
// Function: I_CryptEnumMatchingLruEntries
//
// Synopsis: get the next matching entry
//
//----------------------------------------------------------------------------
HLRUENTRY WINAPI
I_CryptEnumMatchingLruEntries (
IN HLRUENTRY hPrevEntry
)
{
PCLRUCACHE pCache = ( (PCLRUENTRY)hPrevEntry )->Cache();
PCLRUENTRY pNextEntry;
pNextEntry = pCache->NextMatchingEntry( (PCLRUENTRY)hPrevEntry, FALSE );
return( (HLRUENTRY)pNextEntry );
}
//+---------------------------------------------------------------------------
//
// Function: I_CryptEnableLruOfEntries
//
// Synopsis: enable LRU of entries
//
//----------------------------------------------------------------------------
VOID WINAPI
I_CryptEnableLruOfEntries (
IN HLRUCACHE hCache,
IN OPTIONAL LPVOID pvLruRemovalContext
)
{
( (PCLRUCACHE)hCache )->EnableLruOfEntries( pvLruRemovalContext);
}
//+---------------------------------------------------------------------------
//
// Function: I_CryptDisableLruOfEntries
//
// Synopsis: disable LRU of entries
//
//----------------------------------------------------------------------------
VOID WINAPI
I_CryptDisableLruOfEntries (
IN HLRUCACHE hCache
)
{
( (PCLRUCACHE)hCache )->DisableLruOfEntries();
}
//+---------------------------------------------------------------------------
//
// Function: I_CryptWalkAllLruCacheEntries
//
// Synopsis: walk the LRU cache entries
//
//----------------------------------------------------------------------------
VOID WINAPI
I_CryptWalkAllLruCacheEntries (
IN HLRUCACHE hCache,
IN PFN_WALK_ENTRIES pfnWalk,
IN LPVOID pvParameter
)
{
( (PCLRUCACHE)hCache )->WalkEntries( pfnWalk, pvParameter );
}